<commit_before>var request = require('supertest'),
	app = require('../app'),
	supertest = request(app),
	Expect = require('expect.js');

describe('test getInfo:', function () {
	it('Valid URL One', function (done) {
		var data = {'options': {'url': 'https://www.python.org/', 'keyword': 'Python'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(true);
			Expect(result.body.result.description.content).to.be('The official home of the Python Programming Language');
			Expect(result.body.result.description.status).to.be(1);
			Expect(result.body.result.description.message).to.be('It\'s good that you have a meta description, but it should be between 140 and 170 characters. Your\'s is at 52 characters');
			Expect(result.body.result.description.info.stringLength).to.be(52);
			Expect(result.body.result.description.info.keywordInDescription).to.be(true);
			Expect(result.body.result.description.info.keywordStartsDescription).to.be(false);
			Expect(result.body.result.keywords.content).to.be('Python programming language object oriented web free open source software license documentation download community');
			Expect(result.body.result.keywords.status).to.be(1);
			Expect(result.body.result.keywords.message).to.be('Keywords looks good!');
			Expect(result.body.result.keywords.info.keywordCount).to.be(14);
			Expect(result.body.result.title.content).to.be('Welcome to Python.org');
			Expect(result.body.result.title.status).to.be(1);
			Expect(result.body.result.title.message).to.be('Title tag looks good!');
			Expect(result.body.result.title.info.stringLength).to.be(21);
			Expect(result.body.result.title.info.keywordInTitle).to.be(true);
			Expect(result.body.result.title.info.keywordStartsTitle).to.be(false);
			Expect(result.body.result.headerTags.h1.status).to.be(0);
			Expect(result.body.result.headerTags.h1.message).to.be('There is no text in the first H1 on your page');
			Expect(result.body.result.headerTags.h2.status).to.be(1);
			Expect(result.body.result.headerTags.h2.content).to.be('Get Started');
			Expect(result.body.result.headerTags.h2.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h2.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.h3.status).to.be(0);
			Expect(result.body.result.headerTags.h3.message).to.be('There is no text in the first H3 on your page');
			Expect(result.body.result.headerTags.info.doHeaderingsExist).to.be(true);
			Expect(result.body.result.headerTags.info.headerDuplicate).to.be(false);
			Expect(result.body.result.images.message).to.be(undefined);
			Expect(result.body.result.images.status).to.be(1);
			Expect(result.body.result.images.info.imageCount).to.be(1);
			Expect(result.body.result.images.info.URLArray[0]).to.be('/static/img/python-logo.png');
			Expect(result.body.result.images.info.missingAlt).to.be.empty();
			Expect(result.body.result.images.info.imageNames[0]).to.be('python-logo.png');
			Expect(result.body.result.images.info.underscoreInImageName).to.be.empty();
			Expect(result.body.result.images.info.keywordInImageName).to.be(true);
			Expect(result.body.result.url.content).to.be('https://www.python.org/');
			Expect(result.body.result.url.message).to.be(undefined);
			Expect(result.body.result.url.status).to.be(1);
			Expect(result.body.result.url.info.questionMarkOrEqualsInURL).to.be(false);
			Expect(result.body.result.url.info.keywordInURL).to.be(true);
			Expect(result.body.result.url.info.underscoreInURL).to.be(false);
			done();
		});
	});
	it('Valid URL Two', function (done) {
		var data = {'options': {'url': 'https://www.mozilla.org/en-US/firefox/new/', 'keyword': 'browser'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(true);
			Expect(result.body.result.description.content).to.be('Download Mozilla Firefox, a free Web browser. Firefox is created by a global non-profit dedicated to putting individuals in control online. Get Firefox today!');
			Expect(result.body.result.description.status).to.be(1);
			Expect(result.body.result.description.message).to.be('It\'s good that you have a meta description, but it should be between 140 and 170 characters. Your\'s is at 158 characters');
			Expect(result.body.result.description.info.stringLength).to.be(158);
			Expect(result.body.result.description.info.keywordInDescription).to.be(true);
			Expect(result.body.result.description.info.keywordStartsDescription).to.be(false);
			Expect(result.body.result.keywords.status).to.be(0);
			Expect(result.body.result.keywords.message).to.be('Your site needs a meta keywords.');
			Expect(result.body.result.title.content).to.be('Download Firefox — Free Web Browser — Mozilla');
			Expect(result.body.result.title.status).to.be(1);
			Expect(result.body.result.title.message).to.be('Title tag looks good!');
			Expect(result.body.result.title.info.stringLength).to.be(45);
			Expect(result.body.result.title.info.keywordInTitle).to.be(true);
			Expect(result.body.result.title.info.keywordStartsTitle).to.be(false);
			Expect(result.body.result.headerTags.h1.status).to.be(1);
			Expect(result.body.result.headerTags.h1.content).to.be('When it’s personal,choose Firefox.');
			Expect(result.body.result.headerTags.h1.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h1.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.h2.status).to.be(0);
			Expect(result.body.result.headerTags.h2.message).to.be('There is no text in the first H2 on your page');
			Expect(result.body.result.headerTags.h3.status).to.be(1);
			Expect(result.body.result.headerTags.h3.content).to.be('Get Firefox news');
			Expect(result.body.result.headerTags.h3.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h3.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.info.doHeaderingsExist).to.be(true);
			Expect(result.body.result.headerTags.info.headerDuplicate).to.be(false);
			Expect(result.body.result.images.message).to.be(undefined);
			Expect(result.body.result.images.status).to.be(1);
			Expect(result.body.result.images.info.imageCount).to.be(3);
			Expect(result.body.result.images.info.URLArray[0]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/header-firefox.98d0a02c957f.png');
			Expect(result.body.result.images.info.URLArray[1]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/firefox-logo.d3cb43a0a16f.png');
			Expect(result.body.result.images.info.URLArray[2]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/browser-windows.b9cf0baa80e1.png');
			Expect(result.body.result.images.info.missingAlt).to.be.empty();
			Expect(result.body.result.images.info.imageNames[0]).to.be('header-firefox.98d0a02c957f.png');
			Expect(result.body.result.images.info.imageNames[1]).to.be('firefox-logo.d3cb43a0a16f.png');
			Expect(result.body.result.images.info.imageNames[2]).to.be('browser-windows.b9cf0baa80e1.png');
			Expect(result.body.result.images.info.underscoreInImageName).to.be.empty();
			Expect(result.body.result.images.info.keywordInImageName).to.be(true);
			Expect(result.body.result.url.content).to.be('https://www.mozilla.org/en-US/firefox/new/');
			Expect(result.body.result.url.message).to.be(undefined);
			Expect(result.body.result.url.status).to.be(1);
			Expect(result.body.result.url.info.questionMarkOrEqualsInURL).to.be(false);
			Expect(result.body.result.url.info.keywordInURL).to.be(false);
			Expect(result.body.result.url.info.underscoreInURL).to.be(false);
			done();
		});
	});
	it('Invalid - No URL', function (done) {
		var data = {'options': {'url': '', 'keyword': 'Python'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(false);
			Expect(result.body.result).to.be('No URL');
			done();
		});
	});
	it('Invalid - No Keyword', function (done) {
		var data = {'options': {'url': 'https://www.python.org/', 'keyword': ''}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(false);
			Expect(result.body.result).to.be('No Keyword');
			done();
		});
	});
});
<commit_msg>adding another test case<commit_after>var request = require('supertest'),
	app = require('../app'),
	supertest = request(app),
	Expect = require('expect.js');

describe('test getInfo:', function () {
	it('Valid URL One', function (done) {
		var data = {'options': {'url': 'https://www.python.org/', 'keyword': 'Python'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(true);
			Expect(result.body.result.description.content).to.be('The official home of the Python Programming Language');
			Expect(result.body.result.description.status).to.be(1);
			Expect(result.body.result.description.message).to.be('It\'s good that you have a meta description, but it should be between 140 and 170 characters. Your\'s is at 52 characters');
			Expect(result.body.result.description.info.stringLength).to.be(52);
			Expect(result.body.result.description.info.keywordInDescription).to.be(true);
			Expect(result.body.result.description.info.keywordStartsDescription).to.be(false);
			Expect(result.body.result.keywords.content).to.be('Python programming language object oriented web free open source software license documentation download community');
			Expect(result.body.result.keywords.status).to.be(1);
			Expect(result.body.result.keywords.message).to.be('Keywords looks good!');
			Expect(result.body.result.keywords.info.keywordCount).to.be(14);
			Expect(result.body.result.title.content).to.be('Welcome to Python.org');
			Expect(result.body.result.title.status).to.be(1);
			Expect(result.body.result.title.message).to.be('Title tag looks good!');
			Expect(result.body.result.title.info.stringLength).to.be(21);
			Expect(result.body.result.title.info.keywordInTitle).to.be(true);
			Expect(result.body.result.title.info.keywordStartsTitle).to.be(false);
			Expect(result.body.result.headerTags.h1.status).to.be(0);
			Expect(result.body.result.headerTags.h1.message).to.be('There is no text in the first H1 on your page');
			Expect(result.body.result.headerTags.h2.status).to.be(1);
			Expect(result.body.result.headerTags.h2.content).to.be('Get Started');
			Expect(result.body.result.headerTags.h2.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h2.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.h3.status).to.be(0);
			Expect(result.body.result.headerTags.h3.message).to.be('There is no text in the first H3 on your page');
			Expect(result.body.result.headerTags.info.doHeaderingsExist).to.be(true);
			Expect(result.body.result.headerTags.info.headerDuplicate).to.be(false);
			Expect(result.body.result.images.message).to.be(undefined);
			Expect(result.body.result.images.status).to.be(1);
			Expect(result.body.result.images.info.imageCount).to.be(1);
			Expect(result.body.result.images.info.URLArray[0]).to.be('/static/img/python-logo.png');
			Expect(result.body.result.images.info.missingAlt).to.be.empty();
			Expect(result.body.result.images.info.imageNames[0]).to.be('python-logo.png');
			Expect(result.body.result.images.info.underscoreInImageName).to.be.empty();
			Expect(result.body.result.images.info.keywordInImageName).to.be(true);
			Expect(result.body.result.url.content).to.be('https://www.python.org/');
			Expect(result.body.result.url.message).to.be(undefined);
			Expect(result.body.result.url.status).to.be(1);
			Expect(result.body.result.url.info.questionMarkOrEqualsInURL).to.be(false);
			Expect(result.body.result.url.info.keywordInURL).to.be(true);
			Expect(result.body.result.url.info.underscoreInURL).to.be(false);
			done();
		});
	});
	it('Valid URL Two', function (done) {
		var data = {'options': {'url': 'https://www.mozilla.org/en-US/firefox/new/', 'keyword': 'browser'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(true);
			Expect(result.body.result.description.content).to.be('Download Mozilla Firefox, a free Web browser. Firefox is created by a global non-profit dedicated to putting individuals in control online. Get Firefox today!');
			Expect(result.body.result.description.status).to.be(1);
			Expect(result.body.result.description.message).to.be('It\'s good that you have a meta description, but it should be between 140 and 170 characters. Your\'s is at 158 characters');
			Expect(result.body.result.description.info.stringLength).to.be(158);
			Expect(result.body.result.description.info.keywordInDescription).to.be(true);
			Expect(result.body.result.description.info.keywordStartsDescription).to.be(false);
			Expect(result.body.result.keywords.status).to.be(0);
			Expect(result.body.result.keywords.message).to.be('Your site needs a meta keywords.');
			Expect(result.body.result.title.content).to.be('Download Firefox — Free Web Browser — Mozilla');
			Expect(result.body.result.title.status).to.be(1);
			Expect(result.body.result.title.message).to.be('Title tag looks good!');
			Expect(result.body.result.title.info.stringLength).to.be(45);
			Expect(result.body.result.title.info.keywordInTitle).to.be(true);
			Expect(result.body.result.title.info.keywordStartsTitle).to.be(false);
			Expect(result.body.result.headerTags.h1.status).to.be(1);
			Expect(result.body.result.headerTags.h1.content).to.be('When it’s personal,choose Firefox.');
			Expect(result.body.result.headerTags.h1.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h1.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.h2.status).to.be(0);
			Expect(result.body.result.headerTags.h2.message).to.be('There is no text in the first H2 on your page');
			Expect(result.body.result.headerTags.h3.status).to.be(1);
			Expect(result.body.result.headerTags.h3.content).to.be('Get Firefox news');
			Expect(result.body.result.headerTags.h3.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h3.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.info.doHeaderingsExist).to.be(true);
			Expect(result.body.result.headerTags.info.headerDuplicate).to.be(false);
			Expect(result.body.result.images.message).to.be(undefined);
			Expect(result.body.result.images.status).to.be(1);
			Expect(result.body.result.images.info.imageCount).to.be(3);
			Expect(result.body.result.images.info.URLArray[0]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/header-firefox.98d0a02c957f.png');
			Expect(result.body.result.images.info.URLArray[1]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/firefox-logo.d3cb43a0a16f.png');
			Expect(result.body.result.images.info.URLArray[2]).to.be('//mozorg.cdn.mozilla.net/media/img/firefox/new/browser-windows.b9cf0baa80e1.png');
			Expect(result.body.result.images.info.missingAlt).to.be.empty();
			Expect(result.body.result.images.info.imageNames[0]).to.be('header-firefox.98d0a02c957f.png');
			Expect(result.body.result.images.info.imageNames[1]).to.be('firefox-logo.d3cb43a0a16f.png');
			Expect(result.body.result.images.info.imageNames[2]).to.be('browser-windows.b9cf0baa80e1.png');
			Expect(result.body.result.images.info.underscoreInImageName).to.be.empty();
			Expect(result.body.result.images.info.keywordInImageName).to.be(true);
			Expect(result.body.result.url.content).to.be('https://www.mozilla.org/en-US/firefox/new/');
			Expect(result.body.result.url.message).to.be(undefined);
			Expect(result.body.result.url.status).to.be(1);
			Expect(result.body.result.url.info.questionMarkOrEqualsInURL).to.be(false);
			Expect(result.body.result.url.info.keywordInURL).to.be(false);
			Expect(result.body.result.url.info.underscoreInURL).to.be(false);
			done();
		});
	});
	it('Valid URL Three', function (done) {
		var data = {'options': {'url': 'https://en.wikipedia.org/wiki/Search_engine_optimization', 'keyword': 'seo'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(true);
			Expect(result.body.result.description.content).to.be(null);
			Expect(result.body.result.description.status).to.be(0);
			Expect(result.body.result.description.message).to.be('Your site needs a meta description.');
			Expect(result.body.result.keywords.status).to.be(0);
			Expect(result.body.result.keywords.message).to.be('Your site needs a meta keywords.');
			Expect(result.body.result.title.content).to.be('Search engine optimization - Wikipedia, the free encyclopedia');
			Expect(result.body.result.title.status).to.be(1);
			Expect(result.body.result.title.message).to.be('Title tag looks good!');
			Expect(result.body.result.title.info.stringLength).to.be(61);
			Expect(result.body.result.title.info.keywordInTitle).to.be(false);
			Expect(result.body.result.title.info.keywordStartsTitle).to.be(false);
			Expect(result.body.result.headerTags.h1.status).to.be(1);
			Expect(result.body.result.headerTags.h1.content).to.be('Search engine optimization');
			Expect(result.body.result.headerTags.h1.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h1.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.h2.status).to.be(1);
			Expect(result.body.result.headerTags.h2.content).to.be('Contents');
			Expect(result.body.result.headerTags.h3.status).to.be(1);
			Expect(result.body.result.headerTags.h3.content).to.be('Relationship with Google');
			Expect(result.body.result.headerTags.h3.info.keywordInHeader).to.be(false);
			Expect(result.body.result.headerTags.h3.info.keywordStartsHeader).to.be(false);
			Expect(result.body.result.headerTags.info.doHeaderingsExist).to.be(true);
			Expect(result.body.result.headerTags.info.headerDuplicate).to.be(false);
			Expect(result.body.result.images.message).to.be(undefined);
			Expect(result.body.result.images.status).to.be(1);
			Expect(result.body.result.images.info.imageCount).to.be(7);
			Expect(result.body.result.images.info.URLArray[0]).to.be('//upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Padlock-silver.svg/20px-Padlock-silver.svg.png');
			Expect(result.body.result.images.info.URLArray[1]).to.be('//upload.wikimedia.org/wikipedia/commons/thumb/4/47/Sound-icon.svg/20px-Sound-icon.svg.png');
			Expect(result.body.result.images.info.URLArray[2]).to.be('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Websites_interlinking_to_illustrate_PageRank_percents.png/350px-Websites_interlinking_to_illustrate_PageRank_percents.png');
			Expect(result.body.result.images.info.missingAlt[0]).to.be('//upload.wikimedia.org/wikipedia/commons/thumb/1/1e/Websites_interlinking_to_illustrate_PageRank_percents.png/350px-Websites_interlinking_to_illustrate_PageRank_percents.png');
			Expect(result.body.result.images.info.imageNames[0]).to.be('20px-Padlock-silver.svg.png');
			Expect(result.body.result.images.info.imageNames[1]).to.be('20px-Sound-icon.svg.png');
			Expect(result.body.result.images.info.imageNames[2]).to.be('350px-Websites_interlinking_to_illustrate_PageRank_percents.png');
			Expect(result.body.result.images.info.underscoreInImageName[0]).to.be('350px-Websites_interlinking_to_illustrate_PageRank_percents.png');
			Expect(result.body.result.images.info.keywordInImageName).to.be(false);
			Expect(result.body.result.url.content).to.be('https://en.wikipedia.org/wiki/Search_engine_optimization');
			Expect(result.body.result.url.message).to.be(undefined);
			Expect(result.body.result.url.status).to.be(1);
			Expect(result.body.result.url.info.questionMarkOrEqualsInURL).to.be(false);
			Expect(result.body.result.url.info.keywordInURL).to.be(false);
			Expect(result.body.result.url.info.underscoreInURL).to.be(true);
			done();
		});
	});
	it('Invalid - No URL', function (done) {
		var data = {'options': {'url': '', 'keyword': 'Python'}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(false);
			Expect(result.body.result).to.be('No URL');
			done();
		});
	});
	it('Invalid - No Keyword', function (done) {
		var data = {'options': {'url': 'https://www.python.org/', 'keyword': ''}};
		supertest.post('/getInfo').send(data).end(function (err, result) {
			Expect(result.res.statusCode).to.be(200);
			Expect(result.body.success).to.be(false);
			Expect(result.body.result).to.be('No Keyword');
			done();
		});
	});
});
<|endoftext|>


<commit_before>

// var isMSIE8 = ! ('getComputedStyle' in window && typeof window.getComputedStyle === 'function')

function extensions(parentClass) { return {

	_originalLayers: [],
	_visibleLayers: [],
	_staticLayers: [],
	_rbush: [],
	_cachedRelativeBoxes: [],
	_margin: 0,

	initialize: function (options) {
		parentClass.prototype.initialize.call(this, options);
		this._margin = options.margin || 0;
		this._rbush = null;
	},

	addLayer: function(layer) {
		if ( !('options' in layer) || !('icon' in layer.options)) {
			this._staticLayers.push(layer);
			parentClass.prototype.addLayer.call(this, layer);
			return;
		}

		this._originalLayers.push(layer);
		if (this._map) {
			this._maybeAddLayerToRBush( layer );
		}
	},

	removeLayer: function(layer) {
		this._rbush.remove(this._cachedRelativeBoxes[layer._leaflet_id]);
		delete this._cachedRelativeBoxes[layer._leaflet_id];
		parentClass.prototype.removeLayer.call(this,layer);
		var i;

		i = this._originalLayers.indexOf(layer);
		if (i !== -1) { this._originalLayers.splice(i,1); }

		i = this._visibleLayers.indexOf(layer);
		if (i !== -1) { this._visibleLayers.splice(i,1); }

		i = this._staticLayers.indexOf(layer);
		if (i !== -1) { this._staticLayers.splice(i,1); }
	},

	clearLayers: function() {
		this._rbush = rbush();
		this._originalLayers = [];
		this._visibleLayers  = [];
		this._staticLayers   = [];
		this._cachedRelativeBoxes = [];
		parentClass.prototype.clearLayers.call(this);
	},

	onAdd: function (map) {
		this._map = map;

		for (var i in this._staticLayers) {
			map.addLayer(this._staticLayers[i]);
		}

		this._onZoomEnd();
		map.on('zoomend', this._onZoomEnd, this);
	},

	_maybeAddLayerToRBush: function(layer) {
		var z    = this._map.getZoom();
		var bush = this._rbush;

		var boxes = this._cachedRelativeBoxes[layer._leaflet_id];
		var visible = false;
		if (!boxes) {
			// Add the layer to the map so it's instantiated on the DOM,
			//   in order to fetch its position and size.
			parentClass.prototype.addLayer.call(this, layer);
			var visible = true;
// 			var htmlElement = layer._icon;
			var box = this._getIconBox(layer._icon);
			boxes = this._getRelativeBoxes(layer._icon.children, box);
			boxes.push(box);
			this._cachedRelativeBoxes[layer._leaflet_id] = boxes;
		}

		boxes = this._positionBoxes(this._map.latLngToLayerPoint(layer.getLatLng()),boxes);

		var collision = false;
		for (var i=0; i<boxes.length && !collision; i++) {
			collision = bush.search(boxes[i]).length > 0;
		}

		if (!collision) {
			if (!visible) {
				parentClass.prototype.addLayer.call(this, layer);
			}
			this._visibleLayers.push(layer);
			bush.load(boxes);
		} else {
			parentClass.prototype.removeLayer.call(this, layer);
		}
	},

	// Returns a plain array with the relative dimensions of a L.Icon, based
	//   on the computed values from iconSize and iconAnchor.
	_getIconBox: function (el) {

// 		if (isMSIE8) {
// 			// Fallback for MSIE8, will most probably fail on edge cases
// 			return [ 0, 0, el.offsetWidth, el.offsetHeight];
// 		}

		var styles = window.getComputedStyle(el);

		// getComputedStyle() should return values already in pixels, so using arseInt()
		//   is not as much as a hack as it seems to be.

		return [
			parseInt(styles.marginLeft),
			parseInt(styles.marginTop),
			parseInt(styles.marginLeft) + parseInt(styles.width),
			parseInt(styles.marginTop)  + parseInt(styles.height)
		];
	},

	// Much like _getIconBox, but works for positioned HTML elements, based on offsetWidth/offsetHeight.
	_getRelativeBoxes: function(els,baseBox) {
		var boxes = [];
		for (var i=0; i<els.length; i++) {
			var el = els[i];
			var box = [
				el.offsetLeft,
				el.offsetTop,
				el.offsetLeft + el.offsetWidth,
				el.offsetTop  + el.offsetHeight
			];
			box = this._offsetBoxes(box, baseBox);
			boxes.push( box );

			if (el.children.length) {
				var parentBox = baseBox;
// 				if (!isMSIE8) {
					var positionStyle = window.getComputedStyle(el).position;
					if (positionStyle === 'absolute' || positionStyle === 'relative') {
						parentBox = box;
					}
// 				}
				boxes = boxes.concat( this._getRelativeBoxes(el.children, parentBox) );
			}
		}
		return boxes;
	},

	_offsetBoxes: function(a,b){
		return [
			a[0] + b[0],
			a[1] + b[1],
			a[2] + b[0],
			a[3] + b[1]
		];
	},

	// Adds the coordinate of the layer (in pixels / map canvas units) to each box coordinate.
	_positionBoxes: function(offset, boxes) {
		var newBoxes = [];	// Must be careful to not overwrite references to the original ones.
		for (var i=0; i<boxes.length; i++) {
			newBoxes.push( this._positionBox( offset, boxes[i] ) );
		}
		return newBoxes;
	},

	_positionBox: function(offset, box) {

		return [
			box[0] + offset.x - this._margin,
			box[1] + offset.y - this._margin,
			box[2] + offset.x + this._margin,
			box[3] + offset.y + this._margin,
		]
	},

	_onZoomEnd: function() {

		for (var i=0; i<this._visibleLayers.length; i++) {
			parentClass.prototype.removeLayer.call(this, this._visibleLayers[i]);
		}

		this._rbush = rbush();

		var z = this._map.getZoom();

		for (var i=0; i < this._originalLayers.length; i++) {
			this._maybeAddLayerToRBush(this._originalLayers[i]);
		}

	}
}};

L.LayerGroup.Collision   = L.LayerGroup.extend(extensions( L.LayerGroup ));
L.FeatureGroup.Collision = L.FeatureGroup.extend(extensions( L.FeatureGroup ));
L.GeoJSON.Collision      = L.GeoJSON.extend(extensions( L.GeoJSON ));

// MSIE8 fails to use rbush properly (see https://github.com/mourner/rbush/issues/31),
//   so work around that by making L.LayerGroup.Collision into a plain L.LayerGroup
//   and crossing our fingers.
// If MSIE8 support is ever to be done for this, then care has to be taken with
//   calls to window.getComputedStyle().
var isMSIE8 = 'ActiveXObject' in window && document.documentMode < 9;

if (isMSIE8) {
	L.LayerGroup.Collision   = L.LayerGroup;
	L.FeatureGroup.Collision = L.FeatureGroup;
	L.GeoJSON.Collision      = L.GeoJSON;
}

L.LayerGroup.collision = function (options) {
	return new L.LayerGroup.Collision(options);
};

L.FeatureGroup.collision = function (options) {
	return new L.FeatureGroup.Collision(options);
};

L.GeoJSON.collision = function (options) {
	return new L.GeoJSON.Collision(options);
};

<commit_msg>Forgot to implement onRemove().<commit_after>

// var isMSIE8 = ! ('getComputedStyle' in window && typeof window.getComputedStyle === 'function')

function extensions(parentClass) { return {

	_originalLayers: [],
	_visibleLayers: [],
	_staticLayers: [],
	_rbush: [],
	_cachedRelativeBoxes: [],
	_margin: 0,

	initialize: function (options) {
		parentClass.prototype.initialize.call(this, options);
		this._margin = options.margin || 0;
		this._rbush = null;
	},

	addLayer: function(layer) {
		if ( !('options' in layer) || !('icon' in layer.options)) {
			this._staticLayers.push(layer);
			parentClass.prototype.addLayer.call(this, layer);
			return;
		}

		this._originalLayers.push(layer);
		if (this._map) {
			this._maybeAddLayerToRBush( layer );
		}
	},

	removeLayer: function(layer) {
		this._rbush.remove(this._cachedRelativeBoxes[layer._leaflet_id]);
		delete this._cachedRelativeBoxes[layer._leaflet_id];
		parentClass.prototype.removeLayer.call(this,layer);
		var i;

		i = this._originalLayers.indexOf(layer);
		if (i !== -1) { this._originalLayers.splice(i,1); }

		i = this._visibleLayers.indexOf(layer);
		if (i !== -1) { this._visibleLayers.splice(i,1); }

		i = this._staticLayers.indexOf(layer);
		if (i !== -1) { this._staticLayers.splice(i,1); }
	},

	clearLayers: function() {
		this._rbush = rbush();
		this._originalLayers = [];
		this._visibleLayers  = [];
		this._staticLayers   = [];
		this._cachedRelativeBoxes = [];
		parentClass.prototype.clearLayers.call(this);
	},

	onAdd: function (map) {
		this._map = map;

		for (var i in this._staticLayers) {
			map.addLayer(this._staticLayers[i]);
		}

		this._onZoomEnd();
		map.on('zoomend', this._onZoomEnd, this);
	},

	onRemove: function(map) {
		for (var i in this._staticLayers) {
			map.removeLayer(this._staticLayers[i]);
		}
		map.off('zoomend', this._onZoomEnd, this);
		parentClass.prototype.onRemove.call(this, map);
	},

	_maybeAddLayerToRBush: function(layer) {

		var z    = this._map.getZoom();
		var bush = this._rbush;

		var boxes = this._cachedRelativeBoxes[layer._leaflet_id];
		var visible = false;
		if (!boxes) {
			// Add the layer to the map so it's instantiated on the DOM,
			//   in order to fetch its position and size.
			parentClass.prototype.addLayer.call(this, layer);
			var visible = true;
// 			var htmlElement = layer._icon;
			var box = this._getIconBox(layer._icon);
			boxes = this._getRelativeBoxes(layer._icon.children, box);
			boxes.push(box);
			this._cachedRelativeBoxes[layer._leaflet_id] = boxes;
		}

		boxes = this._positionBoxes(this._map.latLngToLayerPoint(layer.getLatLng()),boxes);

		var collision = false;
		for (var i=0; i<boxes.length && !collision; i++) {
			collision = bush.search(boxes[i]).length > 0;
		}

		if (!collision) {
			if (!visible) {
				parentClass.prototype.addLayer.call(this, layer);
			}
			this._visibleLayers.push(layer);
			bush.load(boxes);
		} else {
			parentClass.prototype.removeLayer.call(this, layer);
		}
	},

	// Returns a plain array with the relative dimensions of a L.Icon, based
	//   on the computed values from iconSize and iconAnchor.
	_getIconBox: function (el) {

// 		if (isMSIE8) {
// 			// Fallback for MSIE8, will most probably fail on edge cases
// 			return [ 0, 0, el.offsetWidth, el.offsetHeight];
// 		}

		var styles = window.getComputedStyle(el);

		// getComputedStyle() should return values already in pixels, so using arseInt()
		//   is not as much as a hack as it seems to be.

		return [
			parseInt(styles.marginLeft),
			parseInt(styles.marginTop),
			parseInt(styles.marginLeft) + parseInt(styles.width),
			parseInt(styles.marginTop)  + parseInt(styles.height)
		];
	},

	// Much like _getIconBox, but works for positioned HTML elements, based on offsetWidth/offsetHeight.
	_getRelativeBoxes: function(els,baseBox) {
		var boxes = [];
		for (var i=0; i<els.length; i++) {
			var el = els[i];
			var box = [
				el.offsetLeft,
				el.offsetTop,
				el.offsetLeft + el.offsetWidth,
				el.offsetTop  + el.offsetHeight
			];
			box = this._offsetBoxes(box, baseBox);
			boxes.push( box );

			if (el.children.length) {
				var parentBox = baseBox;
// 				if (!isMSIE8) {
					var positionStyle = window.getComputedStyle(el).position;
					if (positionStyle === 'absolute' || positionStyle === 'relative') {
						parentBox = box;
					}
// 				}
				boxes = boxes.concat( this._getRelativeBoxes(el.children, parentBox) );
			}
		}
		return boxes;
	},

	_offsetBoxes: function(a,b){
		return [
			a[0] + b[0],
			a[1] + b[1],
			a[2] + b[0],
			a[3] + b[1]
		];
	},

	// Adds the coordinate of the layer (in pixels / map canvas units) to each box coordinate.
	_positionBoxes: function(offset, boxes) {
		var newBoxes = [];	// Must be careful to not overwrite references to the original ones.
		for (var i=0; i<boxes.length; i++) {
			newBoxes.push( this._positionBox( offset, boxes[i] ) );
		}
		return newBoxes;
	},

	_positionBox: function(offset, box) {

		return [
			box[0] + offset.x - this._margin,
			box[1] + offset.y - this._margin,
			box[2] + offset.x + this._margin,
			box[3] + offset.y + this._margin,
		]
	},

	_onZoomEnd: function() {

		for (var i=0; i<this._visibleLayers.length; i++) {
			parentClass.prototype.removeLayer.call(this, this._visibleLayers[i]);
		}

		this._rbush = rbush();

		for (var i=0; i < this._originalLayers.length; i++) {
			this._maybeAddLayerToRBush(this._originalLayers[i]);
		}

	}
}};

L.LayerGroup.Collision   = L.LayerGroup.extend(extensions( L.LayerGroup ));
L.FeatureGroup.Collision = L.FeatureGroup.extend(extensions( L.FeatureGroup ));
L.GeoJSON.Collision      = L.GeoJSON.extend(extensions( L.GeoJSON ));

// MSIE8 fails to use rbush properly (see https://github.com/mourner/rbush/issues/31),
//   so work around that by making L.LayerGroup.Collision into a plain L.LayerGroup
//   and crossing our fingers.
// If MSIE8 support is ever to be done for this, then care has to be taken with
//   calls to window.getComputedStyle().
var isMSIE8 = 'ActiveXObject' in window && document.documentMode < 9;

if (isMSIE8) {
	L.LayerGroup.Collision   = L.LayerGroup;
	L.FeatureGroup.Collision = L.FeatureGroup;
	L.GeoJSON.Collision      = L.GeoJSON;
}

L.LayerGroup.collision = function (options) {
	return new L.LayerGroup.Collision(options);
};

L.FeatureGroup.collision = function (options) {
	return new L.FeatureGroup.Collision(options);
};

L.GeoJSON.collision = function (options) {
	return new L.GeoJSON.Collision(options);
};

<|endoftext|>


<commit_before>/*! hyperaudio v0.0.1 ~ (c) 2012-2013 Hyperaudio Inc. <hello@hyperaud.io> (http://hyperaud.io) */
var ha = (function(window, document) {
var DragDrop = (function (window, document) {

	function DragDrop (handle, droppable, options) {
		this.options = {
			init: true,
			touch: true,
			mouse: true,
			timeout: 500,
			html: ''
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		this.droppable = typeof droppable == 'string' ? document.querySelector(droppable) : droppable;

		// Create the list and the placeholder
		this.list = this.droppable.querySelector('ul');
		if ( !this.list ) {
			this.list = document.createElement('ul');
			this.droppable.appendChild(this.list);
		}
		this.placeholder = document.createElement('li');
		this.placeholder.className = 'placeholder';

		if ( this.options.init ) {
			this.handle = typeof handle == 'string' ? document.querySelector(handle) : handle;

			// Are we reordering the list?
			this.reordering = this.handle.parentNode == this.list;

			if ( this.options.touch ) {
				this.handle.addEventListener('touchstart', this, false);
			}

			if ( this.options.mouse ) {
				this.handle.addEventListener('mousedown', this, false);
			}
		}
	}

	DragDrop.prototype.handleEvent = function (e) {
		// jshint -W086
		switch (e.type) {
			case 'mousedown':
				if ( e.which !== 1 ) {
					break;
				}
			case 'touchstart':
				this.start(e);
				break;
			case 'touchmove':
			case 'mousemove':
				this.move(e);
				break;
			case 'touchend':
			case 'mouseup':
				this.end(e);
				break;
		}
		// jshint +W086
	};

	DragDrop.prototype.start = function (e) {
		e.preventDefault();

		clearTimeout(this.dragTimeout);
		this.initiated = false;
		this.lastTarget = null;

		this.dragTimeout = setTimeout(this.init.bind(this, this.options.html, e), this.options.timeout);
	};

	DragDrop.prototype.init = function (html, e) {
		if ( this.options.touch ) {
			document.addEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			document.addEventListener('mouseup', this, false);
		}

		// Create draggable
		this.draggable = document.createElement('div');
		this.draggable.className = 'draggable';
		this.draggableStyle = this.draggable.style;
		this.draggableStyle.cssText = 'position:absolute;z-index:1000;pointer-events:none;left:-99999px';
		this.draggable.innerHTML = html;

		document.body.appendChild(this.draggable);

		this.draggableCenterX = Math.round(this.draggable.offsetWidth / 2);
		this.draggableCenterY = Math.round(this.draggable.offsetHeight / 2);

		this.position(e);

		if ( this.options.touch ) {
			document.addEventListener('touchmove', this, false);
		}

		if ( this.options.mouse ) {
			document.addEventListener('mousemove', this, false);
		}

		this.initiated = true;

		// If we are reordering the list, hide the current element
		if ( this.reordering ) {
			this.handle.style.display = 'none';
		}

		this.move(e);

		if ( this.options.onDragStart ) {
			this.options.onDragStart.call(this);
		}
	};

	DragDrop.prototype.position = function (e) {
		var point = e.changedTouches ? e.changedTouches[0] : e;

		this.draggableStyle.left = point.pageX - this.draggableCenterX + 'px';
		this.draggableStyle.top = point.pageY - this.draggableCenterY + 'px';
	};

	DragDrop.prototype.move = function (e) {
		e.preventDefault();

		var point = e.changedTouches ? e.changedTouches[0] : e;
		var target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target;

		this.position(e);

		if ( target == this.lastTarget || target == this.placeholder || target == this.list ) {
			return;
		}

		this.lastTarget = target;

		if ( this.list.querySelector('.placeholder') ) {
			this.list.removeChild(this.placeholder);
		}

		if ( target == this.droppable ) {
			this.list.appendChild(this.placeholder);
			return;
		}

		if ( target.className == 'item' ) {
			var items = this.list.querySelectorAll('.item'),
				i = 0, l = items.length;
			for ( ; i < l; i++ ) {
				if ( target == items[i] ) {
					this.list.insertBefore(this.placeholder, items[i]);
					break;
				}
			}
		}
	};

	DragDrop.prototype.end = function (e) {
		clearTimeout(this.dragTimeout);

		document.removeEventListener('touchend', this, false);
		document.removeEventListener('mouseup', this, false);

		if ( !this.initiated ) {
			return;
		}

		document.removeEventListener('touchmove', this, false);
		document.removeEventListener('mousemove', this, false);

		var point = e.changedTouches ? e.changedTouches[0] : e;
		var target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target;

		var html = this.draggable.innerHTML;
		this.draggable.parentNode.removeChild(this.draggable);
		this.draggable = null;

		// if we are reordering, remove the original element
		if ( this.reordering ) {
			if ( this.handle._dragInstance ) {
				this.handle._dragInstance.destroy();
				this.handle._dragInstance = null;
			}

			this.handle.parentNode.removeChild(this.handle);
		}

		// we dropped outside of the draggable area, so exit
		if ( !this.list.querySelector('.placeholder') ) {
			return;
		}

		var el = document.createElement('li');
		el.className = 'item';
		el.innerHTML = html;

		this.list.insertBefore(el, this.placeholder);
		this.placeholder.parentNode.removeChild(this.placeholder);

		if ( this.options.onDrop ) {
			this.options.onDrop.call(this, el);
		}
	};

	DragDrop.prototype.destroy = function () {
		document.removeEventListener('touchstart', this, false);
		document.removeEventListener('touchmove', this, false);
		document.removeEventListener('touchend', this, false);

		document.removeEventListener('mousedown', this, false);
		document.removeEventListener('mousemove', this, false);
		document.removeEventListener('mouseup', this, false);
	};

	return DragDrop;
})(window, document);var WordSelect = (function (window, document) {

	function addTagHelpers (el) {
		var text = (el.innerText || el.textContent).split(' ');

		el.innerHTML = '' + text.join(' ') + '';
	}

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

		var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
		return re.test(e.className);
	}

	function addClass (e, c) {
		if ( hasClass(e, c) ) {
			return;
		}

		var newclass = e.className.split(' ');
		newclass.push(c);
		e.className = newclass.join(' ');
	}

	function removeClass (e, c) {
		if ( !hasClass(e, c) ) {
			return;
		}

		var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
		e.className = e.className.replace(re, ' ');
	}

	function WordSelect (el, options) {
		this.element = document.querySelector(el);

		this.options = {
			addHelpers: false,
			touch: true,
			mouse: true,
			threshold: 10
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		if ( this.options.addHelpers ) {
			addTagHelpers(this.element);
		}

		this.words = this.element.querySelectorAll('a');
		this.wordsCount = this.words.length;

		if ( this.options.touch ) {
			this.element.addEventListener('touchstart', this, false);
		}

		if ( this.options.mouse ) {
			this.element.addEventListener('mousedown', this, false);
		}
	}

	WordSelect.prototype.handleEvent = function (e) {
		// jshint -W086
		switch (e.type) {
			case 'mousedown':
				if ( e.which !== 1 ) {
					break;
				}
			case 'touchstart':
				this.start(e);
				break;
			case 'touchmove':
			case 'mousemove':
				this.move(e);
				break;
			case 'touchend':
			case 'mouseup':
				this.end(e);
				break;
		}
		// jshint +W086
	};

	WordSelect.prototype.start = function (e) {
		e.preventDefault();

		var point = e.touches ? e.touches[0] : e;

		this.selectStarted = false;
		this.startX = e.pageX;
		this.startY = e.pageY;

		if ( this.options.mouse ) {
			this.element.addEventListener('mousemove', this, false);
			this.element.addEventListener('mouseup', this, false);
		}

		if ( this.options.touch ) {
			this.element.addEventListener('touchmove', this, false);
			this.element.addEventListener('touchend', this, false);
		}

		if ( hasClass(e.target, 'selected') ) {
			this.dragTimeout = setTimeout(this.dragStart.bind(this, e), 500);
		}
	};

	WordSelect.prototype.selectStart = function (e) {
		var target = e.target,
			tmp;

		if ( target == this.element ) {
			return;
		}

		this.selectStarted = true;

		this.currentWord = target;

		removeClass(this.element.querySelector('.first'), 'first');
		removeClass(this.element.querySelector('.last'), 'last');

		if ( this.words[this.startPosition] === target ) {
			tmp = this.startPosition;
			this.startPosition = this.endPosition;
			this.endPosition = tmp;
			return;
		}

		if ( this.words[this.endPosition] === target ) {
			return;
		}

		for ( var i = 0; i < this.wordsCount; i++ ) {
			if ( this.words[i] == target ) {
				this.startPosition = i;
			}

			removeClass(this.words[i], 'selected');
		}

		this.endPosition = this.startPosition;

		addClass(target, 'selected');
	};

	WordSelect.prototype.move = function (e) {
		var point = e.changedTouches ? e.changedTouches[0] : e,
			target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target,
			endPosition;

		if ( Math.abs(point.pageX - this.startX) < this.options.threshold &&
			Math.abs(point.pageY - this.startY) < this.options.threshold ) {
			return;
		}

		clearTimeout(this.dragTimeout);

		if ( !this.selectStarted ) {
			this.selectStart(e);
			return;
		}

		if ( target == this.element || target == this.currentWord ) {
			return;
		}

		for ( var i = 0; i < this.wordsCount; i++ ) {
			if ( this.words[i] == target ) {
				endPosition = i;
			}

			if ( ( endPosition === undefined && i >= this.startPosition ) ||
				( endPosition !== undefined && i <= this.startPosition ) ||
				endPosition == i ) {
				addClass(this.words[i], 'selected');
			} else {
				removeClass(this.words[i], 'selected');
			}
		}

		this.currentWord = target;
		this.endPosition = endPosition;
	};

	WordSelect.prototype.end = function (e) {
		clearTimeout(this.dragTimeout);

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		if ( !this.selectStarted ) {
			return;
		}

		var start = Math.min(this.startPosition, this.endPosition),
			end = Math.max(this.startPosition, this.endPosition);

		addClass(this.words[start], 'first');
		addClass(this.words[end], 'last');
	};

	WordSelect.prototype.clearSelection = function () {
		removeClass(this.element.querySelector('.first'), 'first');
		removeClass(this.element.querySelector('.last'), 'last');

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		var selected = this.element.querySelectorAll('.selected');
		for ( var i = 0, l = selected.length; i < l; i++ ) {
			removeClass(selected[i], 'selected');
		}
	};

	WordSelect.prototype.getSelection = function () {
		var selected = this.element.querySelectorAll('.selected');
		var html = '';
		for ( var i = 0, l = selected.length; i < l; i++ ) {
			html += selected[i].innerHTML;
		}

		return html;
	};

	WordSelect.prototype.dragStart = function (e) {
		e.stopPropagation();

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		var point = e.changedTouches ? e.changedTouches[0] : e;

		if ( this.options.onDragStart ) {
			this.options.onDragStart.call(this, e);
		}
	};

	WordSelect.prototype.destroy = function () {
		this.element.removeEventListener('touchstart', this, false);
		this.element.removeEventListener('touchmove', this, false);
		this.element.removeEventListener('touchend', this, false);

		this.element.removeEventListener('mousedown', this, false);
		this.element.removeEventListener('mousemove', this, false);
		this.element.removeEventListener('mouseup', this, false);
	};

	return WordSelect;

})(window, document);var hyperaudio = {};
hyperaudio.utils = {
	DragDrop: DragDrop,
	WordSelect: WordSelect
};
	return hyperaudio;
}(window, document));
<commit_msg>Fixed the line endings... Now using core.autocrlf false on my Win OS.<commit_after>/*! hyperaudio v0.0.1 ~ (c) 2012-2013 Hyperaudio Inc. <hello@hyperaud.io> (http://hyperaud.io) */
var ha = (function(window, document) {
var DragDrop = (function (window, document) {

	function DragDrop (handle, droppable, options) {
		this.options = {
			init: true,
			touch: true,
			mouse: true,
			timeout: 500,
			html: ''
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		this.droppable = typeof droppable == 'string' ? document.querySelector(droppable) : droppable;

		// Create the list and the placeholder
		this.list = this.droppable.querySelector('ul');
		if ( !this.list ) {
			this.list = document.createElement('ul');
			this.droppable.appendChild(this.list);
		}
		this.placeholder = document.createElement('li');
		this.placeholder.className = 'placeholder';

		if ( this.options.init ) {
			this.handle = typeof handle == 'string' ? document.querySelector(handle) : handle;

			// Are we reordering the list?
			this.reordering = this.handle.parentNode == this.list;

			if ( this.options.touch ) {
				this.handle.addEventListener('touchstart', this, false);
			}

			if ( this.options.mouse ) {
				this.handle.addEventListener('mousedown', this, false);
			}
		}
	}

	DragDrop.prototype.handleEvent = function (e) {
		// jshint -W086
		switch (e.type) {
			case 'mousedown':
				if ( e.which !== 1 ) {
					break;
				}
			case 'touchstart':
				this.start(e);
				break;
			case 'touchmove':
			case 'mousemove':
				this.move(e);
				break;
			case 'touchend':
			case 'mouseup':
				this.end(e);
				break;
		}
		// jshint +W086
	};

	DragDrop.prototype.start = function (e) {
		e.preventDefault();

		clearTimeout(this.dragTimeout);
		this.initiated = false;
		this.lastTarget = null;

		this.dragTimeout = setTimeout(this.init.bind(this, this.options.html, e), this.options.timeout);
	};

	DragDrop.prototype.init = function (html, e) {
		if ( this.options.touch ) {
			document.addEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			document.addEventListener('mouseup', this, false);
		}

		// Create draggable
		this.draggable = document.createElement('div');
		this.draggable.className = 'draggable';
		this.draggableStyle = this.draggable.style;
		this.draggableStyle.cssText = 'position:absolute;z-index:1000;pointer-events:none;left:-99999px';
		this.draggable.innerHTML = html;

		document.body.appendChild(this.draggable);

		this.draggableCenterX = Math.round(this.draggable.offsetWidth / 2);
		this.draggableCenterY = Math.round(this.draggable.offsetHeight / 2);

		this.position(e);

		if ( this.options.touch ) {
			document.addEventListener('touchmove', this, false);
		}

		if ( this.options.mouse ) {
			document.addEventListener('mousemove', this, false);
		}

		this.initiated = true;

		// If we are reordering the list, hide the current element
		if ( this.reordering ) {
			this.handle.style.display = 'none';
		}

		this.move(e);

		if ( this.options.onDragStart ) {
			this.options.onDragStart.call(this);
		}
	};

	DragDrop.prototype.position = function (e) {
		var point = e.changedTouches ? e.changedTouches[0] : e;

		this.draggableStyle.left = point.pageX - this.draggableCenterX + 'px';
		this.draggableStyle.top = point.pageY - this.draggableCenterY + 'px';
	};

	DragDrop.prototype.move = function (e) {
		e.preventDefault();

		var point = e.changedTouches ? e.changedTouches[0] : e;
		var target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target;

		this.position(e);

		if ( target == this.lastTarget || target == this.placeholder || target == this.list ) {
			return;
		}

		this.lastTarget = target;

		if ( this.list.querySelector('.placeholder') ) {
			this.list.removeChild(this.placeholder);
		}

		if ( target == this.droppable ) {
			this.list.appendChild(this.placeholder);
			return;
		}

		if ( target.className == 'item' ) {
			var items = this.list.querySelectorAll('.item'),
				i = 0, l = items.length;
			for ( ; i < l; i++ ) {
				if ( target == items[i] ) {
					this.list.insertBefore(this.placeholder, items[i]);
					break;
				}
			}
		}
	};

	DragDrop.prototype.end = function (e) {
		clearTimeout(this.dragTimeout);

		document.removeEventListener('touchend', this, false);
		document.removeEventListener('mouseup', this, false);

		if ( !this.initiated ) {
			return;
		}

		document.removeEventListener('touchmove', this, false);
		document.removeEventListener('mousemove', this, false);

		var point = e.changedTouches ? e.changedTouches[0] : e;
		var target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target;

		var html = this.draggable.innerHTML;
		this.draggable.parentNode.removeChild(this.draggable);
		this.draggable = null;

		// if we are reordering, remove the original element
		if ( this.reordering ) {
			if ( this.handle._dragInstance ) {
				this.handle._dragInstance.destroy();
				this.handle._dragInstance = null;
			}

			this.handle.parentNode.removeChild(this.handle);
		}

		// we dropped outside of the draggable area, so exit
		if ( !this.list.querySelector('.placeholder') ) {
			return;
		}

		var el = document.createElement('li');
		el.className = 'item';
		el.innerHTML = html;

		this.list.insertBefore(el, this.placeholder);
		this.placeholder.parentNode.removeChild(this.placeholder);

		if ( this.options.onDrop ) {
			this.options.onDrop.call(this, el);
		}
	};

	DragDrop.prototype.destroy = function () {
		document.removeEventListener('touchstart', this, false);
		document.removeEventListener('touchmove', this, false);
		document.removeEventListener('touchend', this, false);

		document.removeEventListener('mousedown', this, false);
		document.removeEventListener('mousemove', this, false);
		document.removeEventListener('mouseup', this, false);
	};

	return DragDrop;
})(window, document);var WordSelect = (function (window, document) {

	function addTagHelpers (el) {
		var text = (el.innerText || el.textContent).split(' ');

		el.innerHTML = '' + text.join(' ') + '';
	}

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

		var re = new RegExp("(^|\\s)" + c + "(\\s|$)");
		return re.test(e.className);
	}

	function addClass (e, c) {
		if ( hasClass(e, c) ) {
			return;
		}

		var newclass = e.className.split(' ');
		newclass.push(c);
		e.className = newclass.join(' ');
	}

	function removeClass (e, c) {
		if ( !hasClass(e, c) ) {
			return;
		}

		var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g');
		e.className = e.className.replace(re, ' ');
	}

	function WordSelect (el, options) {
		this.element = document.querySelector(el);

		this.options = {
			addHelpers: false,
			touch: true,
			mouse: true,
			threshold: 10
		};

		for ( var i in options ) {
			this.options[i] = options[i];
		}

		if ( this.options.addHelpers ) {
			addTagHelpers(this.element);
		}

		this.words = this.element.querySelectorAll('a');
		this.wordsCount = this.words.length;

		if ( this.options.touch ) {
			this.element.addEventListener('touchstart', this, false);
		}

		if ( this.options.mouse ) {
			this.element.addEventListener('mousedown', this, false);
		}
	}

	WordSelect.prototype.handleEvent = function (e) {
		// jshint -W086
		switch (e.type) {
			case 'mousedown':
				if ( e.which !== 1 ) {
					break;
				}
			case 'touchstart':
				this.start(e);
				break;
			case 'touchmove':
			case 'mousemove':
				this.move(e);
				break;
			case 'touchend':
			case 'mouseup':
				this.end(e);
				break;
		}
		// jshint +W086
	};

	WordSelect.prototype.start = function (e) {
		e.preventDefault();

		var point = e.touches ? e.touches[0] : e;

		this.selectStarted = false;
		this.startX = e.pageX;
		this.startY = e.pageY;

		if ( this.options.mouse ) {
			this.element.addEventListener('mousemove', this, false);
			this.element.addEventListener('mouseup', this, false);
		}

		if ( this.options.touch ) {
			this.element.addEventListener('touchmove', this, false);
			this.element.addEventListener('touchend', this, false);
		}

		if ( hasClass(e.target, 'selected') ) {
			this.dragTimeout = setTimeout(this.dragStart.bind(this, e), 500);
		}
	};

	WordSelect.prototype.selectStart = function (e) {
		var target = e.target,
			tmp;

		if ( target == this.element ) {
			return;
		}

		this.selectStarted = true;

		this.currentWord = target;

		removeClass(this.element.querySelector('.first'), 'first');
		removeClass(this.element.querySelector('.last'), 'last');

		if ( this.words[this.startPosition] === target ) {
			tmp = this.startPosition;
			this.startPosition = this.endPosition;
			this.endPosition = tmp;
			return;
		}

		if ( this.words[this.endPosition] === target ) {
			return;
		}

		for ( var i = 0; i < this.wordsCount; i++ ) {
			if ( this.words[i] == target ) {
				this.startPosition = i;
			}

			removeClass(this.words[i], 'selected');
		}

		this.endPosition = this.startPosition;

		addClass(target, 'selected');
	};

	WordSelect.prototype.move = function (e) {
		var point = e.changedTouches ? e.changedTouches[0] : e,
			target = e.touches ? document.elementFromPoint(point.pageX, point.pageY) : point.target,
			endPosition;

		if ( Math.abs(point.pageX - this.startX) < this.options.threshold &&
			Math.abs(point.pageY - this.startY) < this.options.threshold ) {
			return;
		}

		clearTimeout(this.dragTimeout);

		if ( !this.selectStarted ) {
			this.selectStart(e);
			return;
		}

		if ( target == this.element || target == this.currentWord ) {
			return;
		}

		for ( var i = 0; i < this.wordsCount; i++ ) {
			if ( this.words[i] == target ) {
				endPosition = i;
			}

			if ( ( endPosition === undefined && i >= this.startPosition ) ||
				( endPosition !== undefined && i <= this.startPosition ) ||
				endPosition == i ) {
				addClass(this.words[i], 'selected');
			} else {
				removeClass(this.words[i], 'selected');
			}
		}

		this.currentWord = target;
		this.endPosition = endPosition;
	};

	WordSelect.prototype.end = function (e) {
		clearTimeout(this.dragTimeout);

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		if ( !this.selectStarted ) {
			return;
		}

		var start = Math.min(this.startPosition, this.endPosition),
			end = Math.max(this.startPosition, this.endPosition);

		addClass(this.words[start], 'first');
		addClass(this.words[end], 'last');
	};

	WordSelect.prototype.clearSelection = function () {
		removeClass(this.element.querySelector('.first'), 'first');
		removeClass(this.element.querySelector('.last'), 'last');

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		var selected = this.element.querySelectorAll('.selected');
		for ( var i = 0, l = selected.length; i < l; i++ ) {
			removeClass(selected[i], 'selected');
		}
	};

	WordSelect.prototype.getSelection = function () {
		var selected = this.element.querySelectorAll('.selected');
		var html = '';
		for ( var i = 0, l = selected.length; i < l; i++ ) {
			html += selected[i].innerHTML;
		}

		return html;
	};

	WordSelect.prototype.dragStart = function (e) {
		e.stopPropagation();

		if ( this.options.touch ) {
			this.element.removeEventListener('touchmove', this, false);
			this.element.removeEventListener('touchend', this, false);
		}

		if ( this.options.mouse ) {
			this.element.removeEventListener('mousemove', this, false);
			this.element.removeEventListener('mouseup', this, false);
		}

		var point = e.changedTouches ? e.changedTouches[0] : e;

		if ( this.options.onDragStart ) {
			this.options.onDragStart.call(this, e);
		}
	};

	WordSelect.prototype.destroy = function () {
		this.element.removeEventListener('touchstart', this, false);
		this.element.removeEventListener('touchmove', this, false);
		this.element.removeEventListener('touchend', this, false);

		this.element.removeEventListener('mousedown', this, false);
		this.element.removeEventListener('mousemove', this, false);
		this.element.removeEventListener('mouseup', this, false);
	};

	return WordSelect;

})(window, document);var hyperaudio = {};
hyperaudio.utils = {
	DragDrop: DragDrop,
	WordSelect: WordSelect
};
	return hyperaudio;
}(window, document));
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import Dialog from 'material-ui/lib/dialog'
import FlatButton from 'material-ui/lib/flat-button'
import SelectField from 'material-ui/lib/select-field'
import MenuItem from 'material-ui/lib/menus/menu-item'
import TextField from 'material-ui/lib/text-field'
import ListItem from 'material-ui/lib/lists/list-item'
import FontIcon from 'material-ui/lib/font-icon'

import config from '../../config'
import GMFileInput from './GMFileInput'

const errorText = 'This is a required field'

class GMImportDialog extends Component {
  initialState () {
    return {
      open: false,
      projectValue: '',
      projectName: '',
      speciesValue: '',
      datatype: 'csv',
      markerLabelFileName: '',
      markerName: '',
      markerFileName: '',
      traitLabelFileName: '',
      traitName: '',
      traitFileName: '',
      snpsFeatureFileName: '',
      snpsFeatureName: '',
      populationFileName: '',
      populationName: '',
      optionDisabled: true,
      species: config.species
    }
  }

  constructor (props, context) {
    super(props, context)
    this.state = this.initialState()
  }

  validateForm () {
    return this.state.projectValue === 'new' ?
      (!!this.state.projectName && !!this.state.speciesValue) : // New projects only require a name and a species
      (!!this.state.projectValue && // If we are using an existing project, we can add markers and/or traits
        (!!this.state.markerName && !!this.state.markerFileName && !!this.state.markerLabelFileName) ||
        (!!this.state.traitName && !!this.state.traitFileName && !!this.state.traitLabelFileName) ||
        (!!this.state.snpsFeatureName && !!this.state.snpsFeatureFileName) ||
        (!!this.state.populationName && !!this.state.populationFileName))
  }

  handleSubmit () {
    this.props.submit(document.forms.importData)
    this.setState(this.initialState())
    this.handleClose()
  }

  handleOpen () {
    this.setState({open: true})
  }

  handleClose () {
    this.setState({open: false})
  }

  onChangeProject (event, index, value) {
    if (value === 'new') {
      this.setState({projectValue: value,
                     optionDisabled: false
      })
    } else {
      const existingProject = this.props.projects.find(function (project, index, array) {
        return (project.id === value)
      })
      const species = existingProject.species
      const projectName = existingProject.name
      this.setState({projectValue: value,
                     projectName: projectName,
                     speciesValue: species,
                     optionDisabled: true
      })
    }
  }

  onChangeFileType (event, index, value){
    this.setState({datatype: value})
  }

  onChangeProjectName (event) {
    this.setState({projectName: event.target.value})
  }

  onChangeSpecies (event, index, value) {
    this.setState({speciesValue: value})
  }

  onChangeMarkerLabelFileName (event) {
    this.setState({markerLabelFileName: event.target.value.substr(12)})
  }

  onChangeMarkerName (event) {
    this.setState({markerName: event.target.value})
  }

  onChangeMarkerFileName (event) {
    this.setState({markerFileName: event.target.value.substr(12)})
  }

  onChangeTraitLabelFileName(event) {
    this.setState({traitLabelFileName: event.target.value.substr(12)})
  }

  onChangeTraitName (event) {
    this.setState({traitName: event.target.value})
  }

  onChangeTraitFileName (event) {
    this.setState({traitFileName: event.target.value.substr(12)})
  }

  onChangeSnpsFeatureName (event) {
    this.setState({snpsFeatureName: event.target.value})
  }

  onChangeSnpsFeatureFileName (event) {
    this.setState({snpsFeatureFileName: event.target.value.substr(12)})
  }

  onChangePopulationName(event) {
    this.setState({populationName: event.target.value})
  }

  onChangePopulationFileName (event) {
    this.setState({populationFileName: event.target.value.substr(12)})
  }

  render () {
    var actions = [
      <FlatButton
        label='Cancel'
        secondary={true}
        onClick={this.handleClose.bind(this)}
      />,
      <FlatButton
        label='Import'
        primary={true}
        keyboardFocused={true}
        onClick={this.handleSubmit.bind(this)}
        disabled={!this.validateForm()}
      />
    ]
    var projectList = this.props.projects.map((project, i) =>
      <MenuItem key={i} value={project.id} primaryText={project.name} />
    )
    var projectListReact = this.props.projects.map((project, i) =>
      <option key={i} value={project.id}>{project.name}</option>
    )
    var speciesList = this.state.species.map((species, i) =>
      <MenuItem key={i} value={species.name} primaryText={species.name} />
    )
    var speciesListReact = this.state.species.map((species, i) =>
      <option key={i} value={species.name}>{species.name}</option>
    )
    return (

        <ListItem
          primaryText='Import Local Data'
          onClick={this.handleOpen.bind(this)}
          leftIcon={<FontIcon className='material-icons'>add</FontIcon>}
        />
        <Dialog
          autoScrollBodyContent={true}
          className='gm-dialog__import'
          title='Import Local Data'
          actions={actions}
          modal={false}
          open={this.state.open}
          onRequestClose={this.handleClose.bind(this)}
        >
          <form name='importData'>

              <SelectField
                value={this.state.projectValue}
                hintText='Choose Project'
                errorText={!this.state.projectValue && errorText}
                onChange={this.onChangeProject.bind(this)}
                >
                <MenuItem value={'new'} primaryText='New Project' />
                {projectList}
              </SelectField>
              <select
                id='project'
                className='hidden'
                value={this.state.projectValue}
                readOnly
              >
                <option value='new'>New Project</option>
                {projectListReact}
              </select>

              <TextField
                id='projectName'
                value={this.state.projectName}
                hintText='New Project Name'
                disabled={this.state.optionDisabled}
                errorText={!this.state.projectName && !this.state.optionDisabled && errorText}
                onChange={this.onChangeProjectName.bind(this)}
              />

              <SelectField
                value={this.state.speciesValue}
                disabled={this.state.optionDisabled}
                hintText='Choose Species'
                errorText={!this.state.speciesValue && !this.state.optionDisabled && errorText}
                onChange={this.onChangeSpecies.bind(this)}
              >
                {speciesList}
              </SelectField>
              <select
                id='species'
                className='hidden'
                value={this.state.speciesValue}
                readOnly
              >
                {speciesListReact}
              </select>

              <SelectField
                value={this.state.datatype}
                hintText='Choose file type'
                onChange={this.onChangeFileType.bind(this)}
              >
                <MenuItem value={'csv'} primaryText='CSV data' />
                <MenuItem value={'plink'} primaryText='PLINK data' />
                <MenuItem value={'bed'} primaryText='PLINK binary data' />
              </SelectField>
              {(this.state.datatype == 'csv') ?

                    <TextField
                      id='markerName'
                      value={this.state.markerName}
                      hintText='Marker Name'
                      errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                      onChange={this.onChangeMarkerName.bind(this)}
                    />

                    <GMFileInput
                      id='markerFile'
                      buttonLabel='Marker File'
                      accept='.csv'
                      onChange={this.onChangeMarkerFileName.bind(this)}
                      fileLabel={this.state.markerFileName}
                    />
                    <GMFileInput
                      id='markerLabelFile'
                      buttonLabel='Marker Label File'
                      accept='.csv'
                      onChange={this.onChangeMarkerLabelFileName.bind(this)}
                      fileLabel={this.state.markerLabelFileName}
                    />

                    <TextField
                      id='traitName'
                      value={this.state.traitName}
                      hintText='Trait Name'
                      errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                      onChange={this.onChangeTraitName.bind(this)}
                    />
                    <GMFileInput
                      id='traitFile'
                      buttonLabel='Trait File'
                      accept='.csv'
                      onChange={this.onChangeTraitFileName.bind(this)}
                      fileLabel={this.state.traitFileName}
                    />
                    <GMFileInput
                      id='traitLabelFile'
                      buttonLabel='Trait Label File'
                      accept='.csv'
                      onChange={this.onChangeTraitLabelFileName.bind(this)}
                      fileLabel={this.state.traitLabelFileName}
                    />

                    <TextField
                      id='population'
                      value={this.state.populationName}
                      hintText='Population File Name'
                      errorText={this.state.populationFileName && !this.state.populationName && errorText}
                      onChange={this.onChangePopulationName.bind(this)}
                      importOnSubmit={true}
                    />
                    <GMFileInput
                      id='populationFile'
                      buttonLabel='Population File'
                      accept='.csv'
                      onChange={this.onChangePopulationFileName.bind(this)}
                      fileLabel={this.state.populationFileName}
                      importOnSubmit={true}
                    />

                    <TextField
                      id='snpsFeature'
                      value={this.state.snpsFeatureName}
                      hintText='SNPs Features Name'
                      errorText={this.state.snpsFeatureFileName && !this.state.snpsFeatureName && errorText}
                      onChange={this.onChangeSnpsFeatureName.bind(this)}
                      importOnSubmit={true}
                    />
                    <GMFileInput
                      id='snpsFeatureFile'
                      buttonLabel='SNPs Feature File'
                      accept='.csv'
                      onChange={this.onChangeSnpsFeatureFileName.bind(this)}
                      fileLabel={this.state.snpsFeatureFileName}
                      importOnSubmit={true}
                    />

:
               (this.state.datatype == 'plink') ?

                    <TextField
                      id='markerName'
                      value={this.state.markerName}
                      hintText='Marker Name'
                      errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                      onChange={this.onChangeMarkerName.bind(this)}
                    />

                    <GMFileInput
                      id='markerFile'
                      buttonLabel='Marker File'
                      hintText= 'PED file can be put here'
                      accept='.ped'
                      onChange={this.onChangeMarkerFileName.bind(this)}
                      fileLabel={this.state.markerFileName}
                    />

                    <TextField
                      id='traitName'
                      value={this.state.traitName}
                      hintText='Trait Name'
                      errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                      onChange={this.onChangeTraitName.bind(this)}
                    />
                    <GMFileInput
                      id='traitFile'
                      buttonLabel='Trait File'
                      hintText = 'MAP file can be put here'
                      accept='.map'
                      onChange={this.onChangeTraitFileName.bind(this)}
                      fileLabel={this.state.traitFileName}
                    />

:
               (this.state.datatype == 'bed') ?

                  <TextField
                    id='markerName'
                    value={this.state.markerName}
                    hintText='Marker Name'
                    errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                    onChange={this.onChangeMarkerName.bind(this)}
                  />

                  <TextField
                    id='traitName'
                    value={this.state.traitName}
                    hintText='Trait Name'
                    errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                    onChange={this.onChangeTraitName.bind(this)}
                  />

                  <GMFileInput
                    id='bedFile'
                    buttonLabel='BED File'
                    hintText= 'BED file can be put here'
                    accept='.ped'
                    onChange={this.onChangeMarkerFileName.bind(this)}
                    fileLabel={this.state.markerFileName}
                  />

                  <GMFileInput
                    id='File'
                    buttonLabel='BIM File'
                    hintText = 'BIM file can be put here'
                    accept='.map'
                    onChange={this.onChangeTraitFileName.bind(this)}
                    fileLabel={this.state.traitFileName}
                  />

                  <GMFileInput
                    id='traitFile'
                    buttonLabel='FAM File'
                    hintText = 'FAM file can be put here'
                    accept='.map'
                    onChange={this.onChangeTraitFileName.bind(this)}
                    fileLabel={this.state.traitFileName}
                  />

:
                null}
          </form>
        </Dialog>

    )
  }
}

GMImportDialog.propTypes = {
  projects: PropTypes.array.isRequired
}

export default GMImportDialog
<commit_msg>integrate documentation with upload screen (#185)<commit_after>import React, { Component, PropTypes } from 'react'
import Dialog from 'material-ui/lib/dialog'
import FlatButton from 'material-ui/lib/flat-button'
import SelectField from 'material-ui/lib/select-field'
import MenuItem from 'material-ui/lib/menus/menu-item'
import TextField from 'material-ui/lib/text-field'
import ListItem from 'material-ui/lib/lists/list-item'
import FontIcon from 'material-ui/lib/font-icon'

import config from '../../config'
import GMFileInput from './GMFileInput'

const errorText = 'This is a required field'

class GMImportDialog extends Component {
  initialState () {
    return {
      open: false,
      projectValue: '',
      projectName: '',
      speciesValue: '',
      datatype: 'csv',
      markerLabelFileName: '',
      markerName: '',
      markerFileName: '',
      traitLabelFileName: '',
      traitName: '',
      traitFileName: '',
      snpsFeatureFileName: '',
      snpsFeatureName: '',
      populationFileName: '',
      populationName: '',
      optionDisabled: true,
      species: config.species
    }
  }

  constructor (props, context) {
    super(props, context)
    this.state = this.initialState()
  }

  validateForm () {
    return this.state.projectValue === 'new' ?
      (!!this.state.projectName && !!this.state.speciesValue) : // New projects only require a name and a species
      (!!this.state.projectValue && // If we are using an existing project, we can add markers and/or traits
        (!!this.state.markerName && !!this.state.markerFileName && !!this.state.markerLabelFileName) ||
        (!!this.state.traitName && !!this.state.traitFileName && !!this.state.traitLabelFileName) ||
        (!!this.state.snpsFeatureName && !!this.state.snpsFeatureFileName) ||
        (!!this.state.populationName && !!this.state.populationFileName))
  }

  handleSubmit () {
    this.props.submit(document.forms.importData)
    this.setState(this.initialState())
    this.handleClose()
  }

  handleOpen () {
    this.setState({open: true})
  }

  handleClose () {
    this.setState({open: false})
  }

  onChangeProject (event, index, value) {
    if (value === 'new') {
      this.setState({projectValue: value,
                     optionDisabled: false
      })
    } else {
      const existingProject = this.props.projects.find(function (project, index, array) {
        return (project.id === value)
      })
      const species = existingProject.species
      const projectName = existingProject.name
      this.setState({projectValue: value,
                     projectName: projectName,
                     speciesValue: species,
                     optionDisabled: true
      })
    }
  }

  onChangeFileType (event, index, value){
    this.setState({datatype: value})
  }

  onChangeProjectName (event) {
    this.setState({projectName: event.target.value})
  }

  onChangeSpecies (event, index, value) {
    this.setState({speciesValue: value})
  }

  onChangeMarkerLabelFileName (event) {
    this.setState({markerLabelFileName: event.target.value.substr(12)})
  }

  onChangeMarkerName (event) {
    this.setState({markerName: event.target.value})
  }

  onChangeMarkerFileName (event) {
    this.setState({markerFileName: event.target.value.substr(12)})
  }

  onChangeTraitLabelFileName(event) {
    this.setState({traitLabelFileName: event.target.value.substr(12)})
  }

  onChangeTraitName (event) {
    this.setState({traitName: event.target.value})
  }

  onChangeTraitFileName (event) {
    this.setState({traitFileName: event.target.value.substr(12)})
  }

  onChangeSnpsFeatureName (event) {
    this.setState({snpsFeatureName: event.target.value})
  }

  onChangeSnpsFeatureFileName (event) {
    this.setState({snpsFeatureFileName: event.target.value.substr(12)})
  }

  onChangePopulationName(event) {
    this.setState({populationName: event.target.value})
  }

  onChangePopulationFileName (event) {
    this.setState({populationFileName: event.target.value.substr(12)})
  }

  render () {
    var actions = [
      <FlatButton
        label='Cancel'
        secondary={true}
        onClick={this.handleClose.bind(this)}
      />,
      <FlatButton
        label='Import'
        primary={true}
        keyboardFocused={true}
        onClick={this.handleSubmit.bind(this)}
        disabled={!this.validateForm()}
      />
    ]
    var projectList = this.props.projects.map((project, i) =>
      <MenuItem key={i} value={project.id} primaryText={project.name} />
    )
    var projectListReact = this.props.projects.map((project, i) =>
      <option key={i} value={project.id}>{project.name}</option>
    )
    var speciesList = this.state.species.map((species, i) =>
      <MenuItem key={i} value={species.name} primaryText={species.name} />
    )
    var speciesListReact = this.state.species.map((species, i) =>
      <option key={i} value={species.name}>{species.name}</option>
    )
    return (

        <ListItem
          primaryText='Import Local Data'
          onClick={this.handleOpen.bind(this)}
          leftIcon={<FontIcon className='material-icons'>add</FontIcon>}
        />
        <Dialog
          autoScrollBodyContent={true}
          className='gm-dialog__import'
          title='Import Local Data'
          actions={actions}
          modal={false}
          open={this.state.open}
          onRequestClose={this.handleClose.bind(this)}
        >
          <form name='importData'>

              <SelectField
                value={this.state.projectValue}
                hintText='Choose Project'
                errorText={!this.state.projectValue && errorText}
                onChange={this.onChangeProject.bind(this)}
                >
                <MenuItem value={'new'} primaryText='New Project' />
                {projectList}
              </SelectField>
              <select
                id='project'
                className='hidden'
                value={this.state.projectValue}
                readOnly
              >
                <option value='new'>New Project</option>
                {projectListReact}
              </select>

              <TextField
                id='projectName'
                value={this.state.projectName}
                hintText='New Project Name'
                disabled={this.state.optionDisabled}
                errorText={!this.state.projectName && !this.state.optionDisabled && errorText}
                onChange={this.onChangeProjectName.bind(this)}
              />

              <SelectField
                value={this.state.speciesValue}
                disabled={this.state.optionDisabled}
                hintText='Choose Species'
                errorText={!this.state.speciesValue && !this.state.optionDisabled && errorText}
                onChange={this.onChangeSpecies.bind(this)}
              >
                {speciesList}
              </SelectField>
              <select
                id='species'
                className='hidden'
                value={this.state.speciesValue}
                readOnly
              >
                {speciesListReact}
              </select>

              <SelectField
                value={this.state.datatype}
                hintText='Choose file type'
                onChange={this.onChangeFileType.bind(this)}
              >
                <MenuItem value={'csv'} primaryText='CSV data' />
                <MenuItem value={'plink'} primaryText='PLINK data' />
                <MenuItem value={'bed'} primaryText='PLINK binary data' />
              </SelectField>
              {(this.state.datatype == 'csv') ?

                    <TextField
                      id='markerName'
                      value={this.state.markerName}
                      hintText='Marker Name'
                      errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                      onChange={this.onChangeMarkerName.bind(this)}
                    />

                    <GMFileInput
                      id='markerFile'
                      buttonLabel='Marker File'
                      accept='.csv'
                      onChange={this.onChangeMarkerFileName.bind(this)}
                      fileLabel={this.state.markerFileName}
                    />ⓘ
                    <GMFileInput
                      id='markerLabelFile'
                      buttonLabel='Marker Label File'
                      accept='.csv'
                      onChange={this.onChangeMarkerLabelFileName.bind(this)}
                      fileLabel={this.state.markerLabelFileName}
                    />ⓘ

                    <TextField
                      id='traitName'
                      value={this.state.traitName}
                      hintText='Trait Name'
                      errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                      onChange={this.onChangeTraitName.bind(this)}
                    />
                    <GMFileInput
                      id='traitFile'
                      buttonLabel='Trait File'
                      accept='.csv'
                      onChange={this.onChangeTraitFileName.bind(this)}
                      fileLabel={this.state.traitFileName}
                    />ⓘ
                    <GMFileInput
                      id='traitLabelFile'
                      buttonLabel='Trait Label File'
                      accept='.csv'
                      onChange={this.onChangeTraitLabelFileName.bind(this)}
                      fileLabel={this.state.traitLabelFileName}
                    />ⓘ

                    <TextField
                      id='population'
                      value={this.state.populationName}
                      hintText='Population File Name'
                      errorText={this.state.populationFileName && !this.state.populationName && errorText}
                      onChange={this.onChangePopulationName.bind(this)}
                      importOnSubmit={true}
                    />
                    <GMFileInput
                      id='populationFile'
                      buttonLabel='Population File'
                      accept='.csv'
                      onChange={this.onChangePopulationFileName.bind(this)}
                      fileLabel={this.state.populationFileName}
                      importOnSubmit={true}
                    />ⓘ

                    <TextField
                      id='snpsFeature'
                      value={this.state.snpsFeatureName}
                      hintText='SNPs Features Name'
                      errorText={this.state.snpsFeatureFileName && !this.state.snpsFeatureName && errorText}
                      onChange={this.onChangeSnpsFeatureName.bind(this)}
                      importOnSubmit={true}
                    />
                    <GMFileInput
                      id='snpsFeatureFile'
                      buttonLabel='SNPs Feature File'
                      accept='.csv'
                      onChange={this.onChangeSnpsFeatureFileName.bind(this)}
                      fileLabel={this.state.snpsFeatureFileName}
                      importOnSubmit={true}
                    />ⓘ

:
               (this.state.datatype == 'plink') ?

                    <TextField
                      id='markerName'
                      value={this.state.markerName}
                      hintText='Marker Name'
                      errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                      onChange={this.onChangeMarkerName.bind(this)}
                    />

                    <GMFileInput
                      id='markerFile'
                      buttonLabel='Marker File'
                      hintText= 'PED file can be put here'
                      accept='.ped'
                      onChange={this.onChangeMarkerFileName.bind(this)}
                      fileLabel={this.state.markerFileName}
                    />ⓘ

                    <TextField
                      id='traitName'
                      value={this.state.traitName}
                      hintText='Trait Name'
                      errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                      onChange={this.onChangeTraitName.bind(this)}
                    />
                    <GMFileInput
                      id='traitFile'
                      buttonLabel='Trait File'
                      hintText = 'MAP file can be put here'
                      accept='.map'
                      onChange={this.onChangeTraitFileName.bind(this)}
                      fileLabel={this.state.traitFileName}
                    />ⓘ

:
               (this.state.datatype == 'bed') ?

                  <TextField
                    id='markerName'
                    value={this.state.markerName}
                    hintText='Marker Name'
                    errorText={(this.state.markerFileName || this.state.markerLabelFileName) && !this.state.markerName && errorText}
                    onChange={this.onChangeMarkerName.bind(this)}
                  />

                  <TextField
                    id='traitName'
                    value={this.state.traitName}
                    hintText='Trait Name'
                    errorText={(this.state.traitFileName || this.state.traitLabelFileName) && !this.state.traitName && errorText}
                    onChange={this.onChangeTraitName.bind(this)}
                  />

                  <GMFileInput
                    id='bedFile'
                    buttonLabel='BED File'
                    hintText= 'BED file can be put here'
                    accept='.ped'
                    onChange={this.onChangeMarkerFileName.bind(this)}
                    fileLabel={this.state.markerFileName}
                  />

                  <GMFileInput
                    id='File'
                    buttonLabel='BIM File'
                    hintText = 'BIM file can be put here'
                    accept='.map'
                    onChange={this.onChangeTraitFileName.bind(this)}
                    fileLabel={this.state.traitFileName}
                  />

                  <GMFileInput
                    id='traitFile'
                    buttonLabel='FAM File'
                    hintText = 'FAM file can be put here'
                    accept='.map'
                    onChange={this.onChangeTraitFileName.bind(this)}
                    fileLabel={this.state.traitFileName}
                  />

:
                null}
          </form>
        </Dialog>

    )
  }
}

GMImportDialog.propTypes = {
  projects: PropTypes.array.isRequired
}

export default GMImportDialog
<|endoftext|>