<commit_before>'use strict';

function clicked(){
    audio_start({
      'id': 'boop',
      'volume-multiplier': settings_settings['audio-volume'],
    });

    document.getElementById('score').innerHTML = parseInt(
      document.getElementById('score').innerHTML,
      10
    ) + 1;
    generate();
}

function clear_links(){
    // Remove all target links from text.
    document.getElementById('text').innerHTML =
      document.getElementById('text').innerHTML.replace('', '').replace('', '');
}

function decisecond(){
    time = (time - .1).toFixed(1);

    document.getElementById('time').innerHTML = time;

    if(time <= 0){
        stop();
    }
}

function generate(){
    clear_links();
    var range = 0;
    var text = document.getElementById('text').innerHTML;

    // Generate a range of link-length that doesn't overwrite any HTML.
    do{
        range = random_integer(text.length - settings_settings['link-length']);
    }while(text.substr(range, settings_settings['link-length']).indexOf('<') !== -1
      || text.substr(range, settings_settings['link-length']).indexOf('>') != -1);

    // Replace the text with the new target link in it.
    document.getElementById('text').innerHTML = text.substr(0, range)
      + '' + text.substr(range, settings_settings['link-length']) + ''
      + text.substr(range + settings_settings['link-length'], text.length - range);
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('settings-button').value === '+'
      : state;

    if(state){
        document.getElementById('settings').style.display = 'inline-block';
        document.getElementById('settings-button').value = '-';

    }else{
        document.getElementById('settings').style.display = 'none';
        document.getElementById('settings-button').value = '+';
    }
}

function start(){
    document.getElementById('start-button').onclick = stop;

    settings_save();

    time = 30;

    document.getElementById('score').innerHTML = 0;
    document.getElementById('start-button').value = 'End [ESC]';
    document.getElementById('time').innerHTML = time;
    generate();

    interval = window.setInterval(
      decisecond,
      100
    );
}

function stop(){
    window.clearInterval(interval);
    clear_links();
    document.getElementById('start-button').onclick = start;
    document.getElementById('start-button').value =
      'Start [' + settings_settings['start-key'] + ']';
}

var interval = 0;
var time = 0;

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    // ESC: stop current game.
    if(key === 27){
        stop();

    }else if(String.fromCharCode(key) === settings_settings['start-key']){
        stop();
        start();

    // +: show settings.
    }else if(key === 187){
        settings_toggle(true);

    // -: hide settings.
    }else if(key === 189){
        settings_toggle(false);
    }
};

window.onload = function(e){
    settings_init({
      'prefix': 'SpeedText.htm-',
      'settings': {
        'audio-volume': 1,
        'link-length': 5,
        'start-key': 'H',
      },
    });
    audio_init({
      'volume': settings_settings['audio-volume'],
    });
    audio_create({
      'id': 'boop',
      'properties': {
        'duration': .1,
        'volume': .1,
      },
    });

    document.getElementById('settings').innerHTML =
      '<input id=audio-volume max=1 min=0 step=0.01 type=range>Audio
'
        + '<input id=link-length maxlength=2>Link Length
'
        + '<input id=start-key maxlength=1>Start
'
        + '<input id=reset-button onclick=settings_reset() type=button value=Reset>';
    settings_update();

    document.getElementById('settings-button').onclick = function(){
        settings_toggle();
    };
    document.getElementById('start-button').onclick = start;
    document.getElementById('text').innerHTML = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nibh ligula, dictum ut pulvinar sed, fringilla non lectus. Nunc fermentum aliquam condimentum. Aenean iaculis varius massa, vel rutrum nunc dictum eget. Sed sed ante at diam gravida luctus. Mauris tellus sapien, fringilla convallis mollis nec, tempor et velit. Morbi est odio, aliquet non interdum rutrum, facilisis egestas felis. Curabitur quis nisl et lacus congue ultricies. Sed enim justo, varius condimentum egestas quis, sodales condimentum orci. Praesent porttitor consectetur leo, ac consequat magna vulputate et. Donec non sem sem.

Integer quis enim at odio facilisis rhoncus. Nunc id ipsum eu massa eleifend placerat. Duis luctus lacus vel urna consequat scelerisque. Maecenas diam risus, interdum sed gravida in, posuere a ipsum. Nulla in nunc vitae velit tincidunt viverra vitae nec sem. Aliquam quis tellus magna. Donec nisl diam, ornare vehicula mattis nec, hendrerit sed ipsum.

Etiam iaculis vehicula lectus sed fringilla. In ut mauris augue, at facilisis tellus. Maecenas sed eros vitae turpis adipiscing dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi vitae sodales odio. In sit amet magna sit amet erat sodales congue non sit amet justo. Suspendisse lobortis, neque in cursus tincidunt, neque magna sagittis massa, eu adipiscing magna elit et tellus. Nullam tincidunt leo in sem pretium mollis. Nam ac consequat risus.

Donec a porttitor orci. Fusce vestibulum massa velit, at ullamcorper tortor. Donec iaculis, quam non sodales pellentesque, enim mi venenatis ipsum, semper auctor nunc massa et ipsum. Praesent eget nisl lectus, non luctus felis. Aenean euismod lacinia mauris, at lacinia ante cursus id. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sodales, lorem ultricies molestie cursus, sapien erat congue quam, et vehicula eros massa ac libero. Nunc sit amet magna non turpis facilisis aliquet id sed risus. Mauris quis tellus nibh.

Nulla facilisi. Curabitur scelerisque, lectus ac sodales sollicitudin, justo massa convallis quam, eget tristique sapien eros eget urna. Fusce et neque lorem. Sed enim est, dapibus quis fermentum ac, mollis eget ligula. Aliquam erat volutpat. Aliquam odio erat, accumsan in sollicitudin ac, elementum nec augue. Sed vel tortor sit amet sapien elementum varius. Morbi sollicitudin mauris vitae augue suscipit hendrerit. Morbi nec elementum massa. Praesent condimentum dignissim nibh, eu scelerisque leo sollicitudin rutrum. Cras sit amet nibh eu leo scelerisque laoreet. Aliquam eu mauris at sapien placerat imperdiet vel eget turpis. Etiam posuere sem et justo ultrices suscipit. Vestibulum nibh dolor, lobortis sed eleifend sed, suscipit sit amet diam.';

    stop();
    settings_toggle(false);
};
<commit_msg>switched random.js to args<commit_after>'use strict';

function clicked(){
    audio_start({
      'id': 'boop',
      'volume-multiplier': settings_settings['audio-volume'],
    });

    document.getElementById('score').innerHTML = parseInt(
      document.getElementById('score').innerHTML,
      10
    ) + 1;
    generate();
}

function clear_links(){
    // Remove all target links from text.
    document.getElementById('text').innerHTML =
      document.getElementById('text').innerHTML.replace('', '').replace('', '');
}

function decisecond(){
    time = (time - .1).toFixed(1);

    document.getElementById('time').innerHTML = time;

    if(time <= 0){
        stop();
    }
}

function generate(){
    clear_links();
    var range = 0;
    var text = document.getElementById('text').innerHTML;

    // Generate a range of link-length that doesn't overwrite any HTML.
    do{
        range = random_integer({
          'max': text.length - settings_settings['link-length'],
        });
    }while(text.substr(range, settings_settings['link-length']).indexOf('<') !== -1
      || text.substr(range, settings_settings['link-length']).indexOf('>') != -1);

    // Replace the text with the new target link in it.
    document.getElementById('text').innerHTML = text.substr(0, range)
      + '' + text.substr(range, settings_settings['link-length']) + ''
      + text.substr(range + settings_settings['link-length'], text.length - range);
}

function settings_toggle(state){
    state = state == void 0
      ? document.getElementById('settings-button').value === '+'
      : state;

    if(state){
        document.getElementById('settings').style.display = 'inline-block';
        document.getElementById('settings-button').value = '-';

    }else{
        document.getElementById('settings').style.display = 'none';
        document.getElementById('settings-button').value = '+';
    }
}

function start(){
    document.getElementById('start-button').onclick = stop;

    settings_save();

    time = 30;

    document.getElementById('score').innerHTML = 0;
    document.getElementById('start-button').value = 'End [ESC]';
    document.getElementById('time').innerHTML = time;
    generate();

    interval = window.setInterval(
      decisecond,
      100
    );
}

function stop(){
    window.clearInterval(interval);
    clear_links();
    document.getElementById('start-button').onclick = start;
    document.getElementById('start-button').value =
      'Start [' + settings_settings['start-key'] + ']';
}

var interval = 0;
var time = 0;

window.onkeydown = function(e){
    var key = e.keyCode || e.which;

    // ESC: stop current game.
    if(key === 27){
        stop();

    }else if(String.fromCharCode(key) === settings_settings['start-key']){
        stop();
        start();

    // +: show settings.
    }else if(key === 187){
        settings_toggle(true);

    // -: hide settings.
    }else if(key === 189){
        settings_toggle(false);
    }
};

window.onload = function(e){
    settings_init({
      'prefix': 'SpeedText.htm-',
      'settings': {
        'audio-volume': 1,
        'link-length': 5,
        'start-key': 'H',
      },
    });
    audio_init({
      'volume': settings_settings['audio-volume'],
    });
    audio_create({
      'id': 'boop',
      'properties': {
        'duration': .1,
        'volume': .1,
      },
    });

    document.getElementById('settings').innerHTML =
      '<input id=audio-volume max=1 min=0 step=0.01 type=range>Audio
'
        + '<input id=link-length maxlength=2>Link Length
'
        + '<input id=start-key maxlength=1>Start
'
        + '<input id=reset-button onclick=settings_reset() type=button value=Reset>';
    settings_update();

    document.getElementById('settings-button').onclick = function(){
        settings_toggle();
    };
    document.getElementById('start-button').onclick = start;
    document.getElementById('text').innerHTML = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur nibh ligula, dictum ut pulvinar sed, fringilla non lectus. Nunc fermentum aliquam condimentum. Aenean iaculis varius massa, vel rutrum nunc dictum eget. Sed sed ante at diam gravida luctus. Mauris tellus sapien, fringilla convallis mollis nec, tempor et velit. Morbi est odio, aliquet non interdum rutrum, facilisis egestas felis. Curabitur quis nisl et lacus congue ultricies. Sed enim justo, varius condimentum egestas quis, sodales condimentum orci. Praesent porttitor consectetur leo, ac consequat magna vulputate et. Donec non sem sem.

Integer quis enim at odio facilisis rhoncus. Nunc id ipsum eu massa eleifend placerat. Duis luctus lacus vel urna consequat scelerisque. Maecenas diam risus, interdum sed gravida in, posuere a ipsum. Nulla in nunc vitae velit tincidunt viverra vitae nec sem. Aliquam quis tellus magna. Donec nisl diam, ornare vehicula mattis nec, hendrerit sed ipsum.

Etiam iaculis vehicula lectus sed fringilla. In ut mauris augue, at facilisis tellus. Maecenas sed eros vitae turpis adipiscing dapibus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi vitae sodales odio. In sit amet magna sit amet erat sodales congue non sit amet justo. Suspendisse lobortis, neque in cursus tincidunt, neque magna sagittis massa, eu adipiscing magna elit et tellus. Nullam tincidunt leo in sem pretium mollis. Nam ac consequat risus.

Donec a porttitor orci. Fusce vestibulum massa velit, at ullamcorper tortor. Donec iaculis, quam non sodales pellentesque, enim mi venenatis ipsum, semper auctor nunc massa et ipsum. Praesent eget nisl lectus, non luctus felis. Aenean euismod lacinia mauris, at lacinia ante cursus id. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam sodales, lorem ultricies molestie cursus, sapien erat congue quam, et vehicula eros massa ac libero. Nunc sit amet magna non turpis facilisis aliquet id sed risus. Mauris quis tellus nibh.

Nulla facilisi. Curabitur scelerisque, lectus ac sodales sollicitudin, justo massa convallis quam, eget tristique sapien eros eget urna. Fusce et neque lorem. Sed enim est, dapibus quis fermentum ac, mollis eget ligula. Aliquam erat volutpat. Aliquam odio erat, accumsan in sollicitudin ac, elementum nec augue. Sed vel tortor sit amet sapien elementum varius. Morbi sollicitudin mauris vitae augue suscipit hendrerit. Morbi nec elementum massa. Praesent condimentum dignissim nibh, eu scelerisque leo sollicitudin rutrum. Cras sit amet nibh eu leo scelerisque laoreet. Aliquam eu mauris at sapien placerat imperdiet vel eget turpis. Etiam posuere sem et justo ultrices suscipit. Vestibulum nibh dolor, lobortis sed eleifend sed, suscipit sit amet diam.';

    stop();
    settings_toggle(false);
};
<|endoftext|>


<commit_before>var Tween = function(elem, css, opts) {
	var from = {}, //new WebKitCSSMatrix(elem.style.WebkitTransform),
		fromElem = document.createElement('div'),
		to = {},
		toElem = document.createElement('div'),

		length = function(val) {
			return val;
		},
		opacity = function(val){
			return 	val === "" ? 1 : parseFloat(val);
		},
		// List of properties that can be modified and the function which handles the values
		allowedProps = {
			WebkitTransform: true,
			width: 			length,
			height: 		length,
			marginTop: 		length,
			marginBottom: 	length,
			marginLeft: 	length,
			marginRight: 	length,
			paddingTop: 	length,
			paddingBottom: 	length,
			paddingLeft: 	length,
			paddingRight: 	length,
			opacity: 		opacity,
			borderWidth: 	length
		},
		options = {
			timingFunction: 'ease',
			duration: null,
			increment: 0.01,
			debug: false
		};

	// Setup the options
	for(var i in opts)
		options[i] = opts[i];

	// If timingFunction is a natively supported function then just triger normal transition
	if(	options.timingFunction === 'ease' ||
		options.timingFunction === 'linear' ||
		options.timingFunction === 'ease-in' ||
		options.timingFunction === 'ease-out' ||
		options.timingFunction === 'ease-in-out' ||
		/^cubic-bezier/.test(options.timingFunction)) {

		elem.style.webkitTransitionDuration = options.duration;
		elem.style.webkitTransitionTimingFunction = options.timingFunction;

		for(var rule in css) {
			var camel = rule.toCamel();
			elem.style[camel] = css[rule];
		}

		this.css = '';

		return;
	}
	else
	{
		elem.style.webkitTransitionTimingFunction = null;
		elem.style.webkitTransitionDuration = 0;
	}

	for(var rule in css)
	{
		var camel = rule.toCamel();

		toElem.style[camel] = css[rule];

		if(allowedProps[camel] !== undefined)
		{
			// Set the from/start state
			from[camel] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix(elem.style.WebkitTransform) : allowedProps[camel](elem.style[rule]);

			// Set the to/end state
			to[camel] 	= (camel == 'WebkitTransform') ? new WebKitCSSMatrix(toElem.style.WebkitTransform) : allowedProps[camel](css[rule]);
		}
		else
		{
			console.log("can't handle: "+camel);
		}
	}

	// --- At this point we know that our CSS values are in DOM style camelCase ----------------

	// Adds the CSS to the current page
	var addKeyframeRule = function(rule) {
		if (document.styleSheets && document.styleSheets.length)
			document.styleSheets[0].insertRule(rule, 0);
		else
		{
			var style = document.createElement('style');
			style.innerHTML = rule;
			document.head.appendChild(style);
		}
	},

	// Produces a CSS string representation of the Keyframes
	createAnimationCSS = function(kf, name) {
		var str = '@-webkit-keyframes '+name+' {\n', f = null, fStr = '';

		for(var pos in kf)
		{
			f = kf[pos];
			fStr = '\t'+pos+' {\n';

			for(var rule in f)
				fStr += '\t\t'+rule.toDash()+': '+f[rule]+';\n';

			fStr += "\t}\n\n";

			str += fStr;
		}

		return str + " }";
	},

	keyframes = {},

	// Create a unique name for this animation
	animName = 'anim'+(new Date().getTime());

	// Produce decompositions of matrices here so we don't have to redo it on each iteration
	// Decomposing the matrix is expensive so we need to minimise these requests
	if(from['WebkitTransform'])
	{
		var m1 = from.WebkitTransform.decompose(),
			m2 = to.WebkitTransform.decompose();
	}

	// Produce style keyframes
	for(var progress = 0; progress <= 1; progress += options.increment) {
		var frame = {};

		for(var ruleName in from) {
			var rule = from[ruleName];
			if(ruleName === 'WebkitTransform')
				frame[ruleName] = m1.tween(m2, progress, this.fn[options.timingFunction]);
			else
				frame[ruleName] = rule.tween(to[ruleName], progress, this.fn[options.timingFunction]);
		}

		keyframes[parseInt(progress*100)+'%'] = frame;
	}

	// Ensure the last frame has been added
	keyframes['100%'] = to;

	// Add the new animation to the document
	this.css = createAnimationCSS(keyframes, animName);
	addKeyframeRule(this.css);

	var listener = function(event){
		// Dispatch a faux webkitTransitionEnd event to complete the appearance of this being a transition rather than an animation
		elem.removeEventListener('webkitTransitionEnd', listener, true);
		var event = document.createEvent("Event");
		event.initEvent("webkitTransitionEnd", true, true);
		elem.dispatchEvent(event);
	};

	// Set the final position from as this should be a transition not an animation
	for(var rule in to)
		elem.style[rule] = to[rule];

	// Trigger the animation
	elem.addEventListener('webkitAnimationEnd', listener);
	elem.style.webkitAnimationDuration = options.duration;
	elem.style.webkitAnimationTimingFunction = 'linear';
	elem.style.webkitAnimationName = animName;

	if(options.debug)
		console.log(createAnimationCSS(keyframes, animName));
};

// Setup a placeholder to load custom easing functions
Tween.prototype.fn = {};

String.prototype.tween = function(dest, progress, fn){
	var v1 = parseInt(this), v2 = parseInt(dest);
	return parseInt(v1 + ((v2-v1) * fn(progress))) + "px";
};

Number.prototype.tween = function(dest, progress, fn){
	return parseFloat(this + ((dest-this) * fn(progress)));
};

String.prototype.toDash = function(){
	var str = this.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
	return /^webkit/.test(str) ? '-'+str : str;
};

String.prototype.toCamel = function(){
	return this.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
};<commit_msg>Fixed a bug with removing the event listener for the end of the animation<commit_after>var Tween = function(elem, css, opts) {
	var from = {},
		fromElem = document.createElement('div'),
		to = {},
		toElem = document.createElement('div'),

		length = function(val) {
			return val;
		},
		opacity = function(val){
			return 	val === "" ? 1 : parseFloat(val);
		},

		// List of properties that can be modified and the function which handles the values
		allowedProps = {
			WebkitTransform: true,
			width: 			length,
			height: 		length,
			marginTop: 		length,
			marginBottom: 	length,
			marginLeft: 	length,
			marginRight: 	length,
			paddingTop: 	length,
			paddingBottom: 	length,
			paddingLeft: 	length,
			paddingRight: 	length,
			opacity: 		opacity,
			borderWidth: 	length
		},
		options = {
			timingFunction: 'ease',
			duration: null,
			increment: 0.01,
			debug: false
		},

	// Define all other var's used in the function
	i = rule = ruleName = camel = m1 = m2 = progress = frame = rule = transEvent = null,

	// Event listener for the webkitAnimationEnd Event
	animationEndListener = function(event){
		// Dispatch a faux webkitTransitionEnd event to complete the appearance of this being a transition rather than an animation
		elem.removeEventListener('webkitAnimationEnd', animationEndListener, true);
		transEvent = document.createEvent("Event");
		transEvent.initEvent("webkitTransitionEnd", true, true);
		elem.dispatchEvent(transEvent);
	};

	// Setup the options
	for(i in opts)
		options[i] = opts[i];

	// If timingFunction is a natively supported function then just trigger normal transition
	if(	options.timingFunction === 'ease' ||
		options.timingFunction === 'linear' ||
		options.timingFunction === 'ease-in' ||
		options.timingFunction === 'ease-out' ||
		options.timingFunction === 'ease-in-out' ||
		/^cubic-bezier/.test(options.timingFunction)) {

		elem.style.webkitTransitionDuration = options.duration;
		elem.style.webkitTransitionTimingFunction = options.timingFunction;

		for(rule in css) {
			camel = rule.toCamel();
			elem.style[camel] = css[rule];
		}

		this.css = '';

		return;
	}
	else
	{
		elem.style.webkitTransitionTimingFunction = null;
		elem.style.webkitTransitionDuration = 0;
	}

	for(rule in css)
	{
		camel = rule.toCamel();

		toElem.style[camel] = css[rule];

		if(allowedProps[camel] !== undefined)
		{
			// Set the from/start state
			from[camel] = (camel == 'WebkitTransform') ? new WebKitCSSMatrix(elem.style.WebkitTransform) : allowedProps[camel](elem.style[rule]);

			// Set the to/end state
			to[camel] 	= (camel == 'WebkitTransform') ? new WebKitCSSMatrix(toElem.style.WebkitTransform) : allowedProps[camel](css[rule]);
		}
	}

	// --- At this point we know that our CSS values are in DOM style camelCase ----------------

	// Adds the CSS to the current page
	var addKeyframeRule = function(rule) {
		if (document.styleSheets && document.styleSheets.length)
			document.styleSheets[0].insertRule(rule, 0);
		else
		{
			var style = document.createElement('style');
			style.innerHTML = rule;
			document.head.appendChild(style);
		}
	},

	// Produces a CSS string representation of the Keyframes
	createAnimationCSS = function(kf, name) {
		var str = '@-webkit-keyframes '+name+' {\n', f = pos = rule = null, fStr = '';

		for(pos in kf)
		{
			f = kf[pos];
			fStr = '\t'+pos+' {\n';

			for(rule in f)
				fStr += '\t\t'+rule.toDash()+': '+f[rule]+';\n';

			fStr += "\t}\n\n";

			str += fStr;
		}

		return str + " }";
	},

	keyframes = {},

	// Create a unique name for this animation
	animName = 'anim'+(new Date().getTime());

	// Produce decompositions of matrices here so we don't have to redo it on each iteration
	// Decomposing the matrix is expensive so we need to minimise these requests
	if(from['WebkitTransform'])
	{
		m1 = from.WebkitTransform.decompose();
		m2 = to.WebkitTransform.decompose();
	}

	// Produce style keyframes
	for(progress = 0; progress <= 1; progress += options.increment) {
		frame = {};

		for(ruleName in from) {
			rule = from[ruleName];
			if(ruleName === 'WebkitTransform')
				frame[ruleName] = m1.tween(m2, progress, this.fn[options.timingFunction]);
			else
				frame[ruleName] = rule.tween(to[ruleName], progress, this.fn[options.timingFunction]);
		}

		keyframes[parseInt(progress*100)+'%'] = frame;
	}

	// Ensure the last frame has been added
	keyframes['100%'] = to;

	// Add the new animation to the document
	this.css = createAnimationCSS(keyframes, animName);
	addKeyframeRule(this.css);

	// Set the final position from as this should be a transition not an animation
	for(rule in to)
		elem.style[rule] = to[rule];

	// Trigger the animation
	elem.addEventListener('webkitAnimationEnd', animationEndListener);
	elem.style.webkitAnimationDuration = options.duration;
	elem.style.webkitAnimationTimingFunction = 'linear';
	elem.style.webkitAnimationName = animName;

	if(options.debug && window.console && window.console.log)
		console.log(createAnimationCSS(keyframes, animName));
};

// Setup a placeholder to load custom easing functions
Tween.prototype.fn = {};

String.prototype.tween = function(dest, progress, fn){
	var v1 = parseInt(this), v2 = parseInt(dest);
	return parseInt(v1 + ((v2-v1) * fn(progress))) + "px";
};

Number.prototype.tween = function(dest, progress, fn){
	return parseFloat(this + ((dest-this) * fn(progress)));
};

String.prototype.toDash = function(){
	var str = this.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();});
	return /^webkit/.test(str) ? '-'+str : str;
};

String.prototype.toCamel = function(){
	return this.replace(/(\-[a-z])/g, function($1){return $1.toUpperCase().replace('-','');});
};<|endoftext|>


<commit_before>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'single_project': {
      init: function() {
			$("#slide0").addClass("active");
			$("#data0").addClass("active");
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

$(function(){
	$('#carousel-example-generic').carousel({
		interval:false
	});
})

})(jQuery); // Fully reference jQuery after this point.

<commit_msg>added missing semi colon<commit_after>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // JavaScript to be fired on all pages
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'single_project': {
      init: function() {
			$("#slide0").addClass("active");
			$("#data0").addClass("active");
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

$(function(){
	$('#carousel-example-generic').carousel({
		interval:false
	});
});

})(jQuery); // Fully reference jQuery after this point.

<|endoftext|>


<commit_before>
/*
 * Superfish v1.6.0 - jQuery menu widget
 * Copyright (c) 2013 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 * 	http://www.opensource.org/licenses/mit-license.php
 * 	http://www.gnu.org/licenses/gpl.html
 *
 */

;(function($){
	$.fn.superfish = function(op){

		var sf = $.fn.superfish,
			c = sf.c,
			$arrow = $(' »'),
			over = function(){
				var $$ = $(this), o = getOptions($$);
				clearTimeout( o.sfTimer );
				$$.showSuperfishUl().siblings().hideSuperfishUl();
			},
			out = function(e){
				var $$ = $(this),
					o = getOptions($$);

				if (e.type === 'click' || sf.ios){
					$.proxy(close,$$,o)();
				} else {
					clearTimeout(o.sfTimer);
					o.sfTimer=setTimeout($.proxy(close,$$,o), o.delay);
				}
			},
			close = function(o){
				o.retainPath=( $.inArray(this[0],o.$path) > -1);
				this.hideSuperfishUl();
				if (!this.parents('.'+o.hoverClass).length){
					o.onIdle.call(getMenu(this));
					if (o.$path.length){
						$.proxy(over,o.$path)();
					}
				}
			},
			getMenu = function($el){
				return $el.closest('.'+c.menuClass);
			},
			getOptions = function($el) {
				return getMenu($el).data('sf-options');
			},
			applyTouchAction = function($menu){
       //needed by MS pointer events
				$menu.css('ms-touch-action','none');
			},
			applyHandlers = function($menu,o){
				var targets = 'li:has(ul)';
				if (!o.useClick){
					if ($.fn.hoverIntent && !o.disableHI){
						$menu.hoverIntent(over, out, targets);
					} else {
						$menu
							.on('mouseenter', targets, over)
							.on('mouseleave', targets, out);
					}
				}
				var touchstart = 'MSPointerDown';
				if ( !sf.ios ){
					touchstart += ' touchstart';
				}
				$menu
					.on('focusin', 'li', over)
					.on('focusout', 'li', out)
					.on('click', 'a', o, clickHandler)
					.on(touchstart, 'a', touchHandler);
			},
			touchHandler = function(e){
        var $$ = $(this),
          $ul = $$.siblings('ul');
        if ($ul.length > 0 && $ul.is(':hidden')){
          $$.data('follow', false);
          if (e.type === 'MSPointerDown'){
						$$.trigger('focus');
						return false;
					}
        }
      },
			clickHandler = function(e){
				var $a = $(this),
						o = e.data,
						$submenu = $a.siblings('ul'),
						follow = ($a.data('follow') === false) ? false : true;

				if ( $submenu.length && (o.useClick || !follow) ){
					e.preventDefault();
					if ($submenu.is(':hidden')){
						$.proxy(over,$a.parent('li'))();
					} else if (o.useClick && follow) {
						$.proxy(out,$a.parent('li'),e)();
					}
				}
			},
			setPathToCurrent = function($menu,o) {
				return $menu.find('li.'+o.pathClass).slice(0,o.pathLevels)
					.addClass(o.hoverClass+' '+c.bcClass)
						.filter(function(){
							return ($(this).children('ul').hide().show().length);
						}).removeClass(o.pathClass);
			},
			addArrows = function($li,o){
				if (o.autoArrows) {
					$li.children('a').each(function() {
						addArrow( $(this) );
					});
				}
			},
			addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };

		sf.getOptions = getOptions;

		return this.addClass(c.menuClass).each(function() {
			var $$ = $(this);
			var	o = $.extend({}, sf.defaults, op);
			var $liHasUl = $$.find('ul').parent();

			o.$path = setPathToCurrent($$,o);

			$$.data('sf-options',o);

			addArrows($liHasUl,o);
			applyTouchAction($$);
			applyHandlers($$,o);

			$liHasUl.not('.'+c.bcClass).children('ul').show().hide();

			o.onInit.call(this);

		});
	};

	var sf = $.fn.superfish;
	sf.o = [];
	sf.op = {};

	sf.c = {
		bcClass: 'sf-breadcrumb',
		menuClass: 'sf-js-enabled',
		anchorClass: 'sf-with-ul',
		arrowClass: 'sf-sub-indicator'
	};
	sf.defaults = {
		hoverClass: 'sfHover',
		pathClass: 'overrideThisToUse',
		pathLevels: 1,
		delay: 800,
		animation: {opacity:'show'},
		animationOut: {opacity:'hide'},
		speed: 'normal',
		speedOut: 'fast',
		autoArrows: true,
		disableHI: false,		// true disables hoverIntent detection
		useClick: false,
		onInit: $.noop, // callback functions
		onBeforeShow: $.noop,
		onShow: $.noop,
		onBeforeHide: $.noop,
		onHide: $.noop,
		onIdle: $.noop
	};
	sf.ios = /iPhone|iPad|iPod/i.test(navigator.userAgent);
	$.fn.extend({
		hideSuperfishUl: function(){
			var $$ = this,
				o = sf.getOptions($$),
				not = (o.retainPath===true) ? o.$path : '';
			o.retainPath = false;
			var $ul = $$.find('li.'+o.hoverClass).addBack().not(not).removeClass(o.hoverClass).children('ul');
				o.onBeforeHide.call($ul);
				$ul.stop(true,true).animate(o.animationOut,o.speedOut,function(){
					o.onHide.call($(this));
					if (o.useClick){
						$$.children('a').data('follow', false);
					}
				});
			return this;
		},
		showSuperfishUl: function(){
			var o = sf.getOptions(this),
				$$ = this.addClass(o.hoverClass),
				$ul = $$.children('ul');
			o.onBeforeShow.call($ul);
			$ul.stop(true,true).animate(o.animation,o.speed,function(){
				o.onShow.call($ul);
				$$.children('a').data('follow', true);
			});
			return this;
		}
	});

	if ( sf.ios ){
		//iOS click won't bubble to body, attach to closest possible
		$(function(){ $('body').children().on('click',$.noop); });
		$(window).on('pageshow', function(e) {
			//only way to reset subs after back button click. Seriously.
		  if (e.originalEvent.persisted) { window.location.reload(); }
		});
	}

})(jQuery);
<commit_msg>More succinct code for subs setup.<commit_after>
/*
 * Superfish v1.6.0 - jQuery menu widget
 * Copyright (c) 2013 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 * 	http://www.opensource.org/licenses/mit-license.php
 * 	http://www.gnu.org/licenses/gpl.html
 *
 */

;(function($){
	$.fn.superfish = function(op){

		var sf = $.fn.superfish,
			c = sf.c,
			$arrow = $(' »'),
			over = function(){
				var $$ = $(this), o = getOptions($$);
				clearTimeout( o.sfTimer );
				$$.showSuperfishUl().siblings().hideSuperfishUl();
			},
			out = function(e){
				var $$ = $(this),
					o = getOptions($$);

				if (e.type === 'click' || sf.ios){
					$.proxy(close,$$,o)();
				} else {
					clearTimeout(o.sfTimer);
					o.sfTimer=setTimeout($.proxy(close,$$,o), o.delay);
				}
			},
			close = function(o){
				o.retainPath=( $.inArray(this[0],o.$path) > -1);
				this.hideSuperfishUl();
				if (!this.parents('.'+o.hoverClass).length){
					o.onIdle.call(getMenu(this));
					if (o.$path.length){
						$.proxy(over,o.$path)();
					}
				}
			},
			getMenu = function($el){
				return $el.closest('.'+c.menuClass);
			},
			getOptions = function($el) {
				return getMenu($el).data('sf-options');
			},
			applyTouchAction = function($menu){
       //needed by MS pointer events
				$menu.css('ms-touch-action','none');
			},
			applyHandlers = function($menu,o){
				var targets = 'li:has(ul)';
				if (!o.useClick){
					if ($.fn.hoverIntent && !o.disableHI){
						$menu.hoverIntent(over, out, targets);
					} else {
						$menu
							.on('mouseenter', targets, over)
							.on('mouseleave', targets, out);
					}
				}
				var touchstart = 'MSPointerDown';
				if ( !sf.ios ){
					touchstart += ' touchstart';
				}
				$menu
					.on('focusin', 'li', over)
					.on('focusout', 'li', out)
					.on('click', 'a', o, clickHandler)
					.on(touchstart, 'a', touchHandler);
			},
			touchHandler = function(e){
        var $$ = $(this),
          $ul = $$.siblings('ul');
        if ($ul.length > 0 && $ul.is(':hidden')){
          $$.data('follow', false);
          if (e.type === 'MSPointerDown'){
						$$.trigger('focus');
						return false;
					}
        }
      },
			clickHandler = function(e){
				var $a = $(this),
						o = e.data,
						$submenu = $a.siblings('ul'),
						follow = ($a.data('follow') === false) ? false : true;

				if ( $submenu.length && (o.useClick || !follow) ){
					e.preventDefault();
					if ($submenu.is(':hidden')){
						$.proxy(over,$a.parent('li'))();
					} else if (o.useClick && follow) {
						$.proxy(out,$a.parent('li'),e)();
					}
				}
			},
			setPathToCurrent = function($menu,o) {
				return $menu.find('li.'+o.pathClass).slice(0,o.pathLevels)
					.addClass(o.hoverClass+' '+c.bcClass)
						.filter(function(){
							return ($(this).children('ul').hide().show().length);
						}).removeClass(o.pathClass);
			},
			addArrows = function($li,o){
				if (o.autoArrows) {
					$li.children('a').each(function() {
						addArrow( $(this) );
					});
				}
			},
			addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };

		sf.getOptions = getOptions;

		return this.addClass(c.menuClass).each(function() {
			var $$ = $(this);
			var	o = $.extend({}, sf.defaults, op);
			var $liHasUl = $$.find('ul')
				.not('.'+c.bcClass).show().hide().end()
				.parent();

			o.$path = setPathToCurrent($$,o);

			$$.data('sf-options',o);

			addArrows($liHasUl,o);
			applyTouchAction($$);
			applyHandlers($$,o);

			o.onInit.call(this);

		});
	};

	var sf = $.fn.superfish;
	sf.o = [];
	sf.op = {};

	sf.c = {
		bcClass: 'sf-breadcrumb',
		menuClass: 'sf-js-enabled',
		anchorClass: 'sf-with-ul',
		arrowClass: 'sf-sub-indicator'
	};
	sf.defaults = {
		hoverClass: 'sfHover',
		pathClass: 'overrideThisToUse',
		pathLevels: 1,
		delay: 800,
		animation: {opacity:'show'},
		animationOut: {opacity:'hide'},
		speed: 'normal',
		speedOut: 'fast',
		autoArrows: true,
		disableHI: false,		// true disables hoverIntent detection
		useClick: false,
		onInit: $.noop, // callback functions
		onBeforeShow: $.noop,
		onShow: $.noop,
		onBeforeHide: $.noop,
		onHide: $.noop,
		onIdle: $.noop
	};
	sf.ios = /iPhone|iPad|iPod/i.test(navigator.userAgent);
	$.fn.extend({
		hideSuperfishUl: function(){
			var $$ = this,
				o = sf.getOptions($$),
				not = (o.retainPath===true) ? o.$path : '';
			o.retainPath = false;
			var $ul = $$.find('li.'+o.hoverClass).addBack().not(not).removeClass(o.hoverClass).children('ul');
				o.onBeforeHide.call($ul);
				$ul.stop(true,true).animate(o.animationOut,o.speedOut,function(){
					o.onHide.call($(this));
					if (o.useClick){
						$$.children('a').data('follow', false);
					}
				});
			return this;
		},
		showSuperfishUl: function(){
			var o = sf.getOptions(this),
				$$ = this.addClass(o.hoverClass),
				$ul = $$.children('ul');
			o.onBeforeShow.call($ul);
			$ul.stop(true,true).animate(o.animation,o.speed,function(){
				o.onShow.call($ul);
				$$.children('a').data('follow', true);
			});
			return this;
		}
	});

	if ( sf.ios ){
		//iOS click won't bubble to body, attach to closest possible
		$(function(){ $('body').children().on('click',$.noop); });
		$(window).on('pageshow', function(e) {
			//only way to reset subs after back button click. Seriously.
		  if (e.originalEvent.persisted) { window.location.reload(); }
		});
	}

})(jQuery);
<|endoftext|>


<commit_before>var igv = (function (igv) {

    igv.TrackView = function (track, browser) {

        this.browser = browser;
        this.track = track;
        this.order = track.order || 0;
        this.marginBottom = 10;

        var viewportDiv,
            trackDiv,
            controlDiv,
            controlCanvas,
            contentDiv,
            canvas,
            closeButton,
            labelButton;

        // track
        trackDiv = document.createElement("div");
        browser.trackContainerDiv.appendChild(trackDiv);
        trackDiv.className = "igv-track-div";
        trackDiv.style.height = track.height + "px";
        this.trackDiv = trackDiv;

        // controls
        var controlWidth = browser.controlPanelWidth ? browser.controlPanelWidth : 50;

        controlDiv = document.createElement("div");
        controlDiv.className = "igv-control-div";
        controlDiv.style.width = controlWidth + "px";
        controlDiv.style.height = track.height + "px";
        this.controlDiv = controlDiv;

        controlCanvas = document.createElement('canvas');
        controlDiv.style.width = controlWidth + "px";
        trackDiv.appendChild(controlDiv);
        this.controlDiv = controlDiv;

        controlDiv.appendChild(controlCanvas);
        controlCanvas.style.width = controlDiv.clientWidth + "px";
        controlCanvas.style.height = controlDiv.clientHeight + "px";
        controlCanvas.setAttribute('width', controlDiv.clientWidth);
        controlCanvas.setAttribute('height', controlDiv.clientHeight);
        this.controlCanvas = controlCanvas;
        this.controlCtx = controlCanvas.getContext("2d");

        // viewport
        viewportDiv = document.createElement("div");
        viewportDiv.className = "igv-viewport-div";
        viewportDiv.style.left = controlDiv.clientWidth + "px";
        viewportDiv.style.height = track.height + "px";
        trackDiv.appendChild(viewportDiv);
        this.viewportDiv = viewportDiv;

        // content
        contentDiv = document.createElement("div");
        viewportDiv.appendChild(contentDiv);
        contentDiv.className = "igv-content-div";
        contentDiv.style.height = track.height + "px";
        this.contentDiv = contentDiv;

        canvas = document.createElement('canvas');
        contentDiv.appendChild(canvas);
        canvas.style.position = 'absolute';
        canvas.style.width = contentDiv.clientWidth + "px";
        canvas.style.height = track.height + "px";
        canvas.setAttribute('width', contentDiv.clientWidth);
        canvas.setAttribute('height', track.height);

        // CURSOR specific functions
        if (browser.type === "CURSOR") {

            this.track.cursorHistogram = new cursor.CursorHistogram(controlDiv.clientHeight, this.track.max);
            this.track.cursorHistogram.createMarkupWithTrackPanelDiv(this);

            igv.cursorAddTrackControlButtons(this, browser, controlDiv)

        }

        // Close button
        if (!track.disableButtons) {

            closeButton = document.createElement("i");
            contentDiv.appendChild(closeButton);
            closeButton.className = "fa fa-times-circle igv-track-disable-button-fontawesome";
            closeButton.onclick = function () {
                browser.removeTrack(track);
            };
            contentDiv.appendChild(closeButton);

            if (track.label) {

                labelButton = document.createElement("button");
                viewportDiv.appendChild(labelButton);
                labelButton.className = "btn btn-xs btn-cursor-deselected igv-track-label";
                labelButton.innerHTML = track.label;
                track.labelButton = labelButton;

                labelButton.onclick = function (e) {

                    if (browser.cursorModel) {
                        track.featureSource.allFeatures(function (featureList) {

                            browser.referenceFrame.start = 0;
                            browser.cursorModel.setRegions(featureList);

                        });

                    }
                    else {

                        if (track.description) {
                            igv.popover.show(e.pageX, e.pageY, track.description);
                        }

                    }

                }

            }
        }

        this.canvas = canvas;
        this.ctx = canvas.getContext("2d");

        addTrackHandlers(this);

    };

    igv.TrackView.prototype.resize = function () {
        var canvas = this.canvas,
            contentDiv = this.contentDiv,
            contentWidth = this.viewportDiv.clientWidth;
        //      contentHeight = this.canvas.getAttribute("height");  // Maintain the current height

        contentDiv.style.width = contentWidth + "px";      // Not sure why css is not working for this
        //  contentDiv.style.height = contentHeight + "px";

        canvas.style.width = contentWidth + "px";
        canvas.setAttribute('width', contentWidth);    //Must set the width & height of the canvas
        this.update();
    };

    igv.TrackView.prototype.setTrackHeight = function (newHeight) {

        var heightStr = newHeight + "px";
        this.track.height = newHeight;
        this.trackDiv.style.height = heightStr;
        // this.controlDiv.style.height = heightStr;
        // this.controlCanvas.style.height = heightStr;
        // this.controlCanvas.setAttribute("height", newHeight);
        this.viewportDiv.style.height = heightStr;
        this.contentDiv.style.height = heightStr;
        this.canvas.style.height = heightStr;
        this.canvas.setAttribute("height", newHeight);

        this.track.cursorHistogram.updateHeight(this.track, newHeight);

        this.update();
    };

    igv.TrackView.prototype.update = function () {
        this.tile = null;
        this.repaint();

    };

    igv.TrackView.prototype.repaint = function () {

        if (!this.track) {
            return;
        }

        var tileWidth,
            tileStart,
            tileEnd,
            spinner,
            buffer,
            myself = this,
            igvCanvas,
            referenceFrame = this.browser.referenceFrame;

        if (!this.tile || !this.tile.containsRange(referenceFrame.chr, referenceFrame.start, referenceFrame.start + referenceFrame.toBP(this.canvas.width), referenceFrame.bpPerPixel)) {

            buffer = document.createElement('canvas');
            buffer.width = 3 * this.canvas.width;
            buffer.height = this.canvas.height;
            igvCanvas = new igv.Canvas(buffer);

            tileWidth = Math.round(referenceFrame.toBP(buffer.width));
            tileStart = Math.max(0, Math.round(referenceFrame.start - tileWidth / 3));
            tileEnd = tileStart + tileWidth;

            spinner = igv.getSpinner(this.trackDiv);   // Start a spinner

            if (this.currentTask) {
                this.currentTask.abort();
            }
            this.currentTask = {
                canceled: false,
                abort: function () {
                    this.canceled = true;
                    if (this.xhrRequest) {
                        this.xhrRequest.abort();
                    }
                    spinner.stop();
                }

            };

            this.track.draw(igvCanvas, referenceFrame, tileStart, tileEnd, buffer.width, buffer.height, function (task) {

                    spinner.stop();

                    if (task) console.log(task.canceled);

                    if (!(task && task.canceled)) {
                        myself.tile = new Tile(referenceFrame.chr, tileStart, tileEnd, referenceFrame.bpPerPixel, buffer);
                        myself.paintImage();
                    }
                },
                this.currentTask);

            if (this.track.paintControl) {

                var buffer2 = document.createElement('canvas');
                buffer2.width = this.controlCanvas.width;
                buffer2.height = this.controlCanvas.height;

                var bufferCanvas = new igv.Canvas(buffer2);

                this.track.paintControl(bufferCanvas, buffer2.width, buffer2.height);

                this.controlCtx.drawImage(buffer2, 0, 0);
            }

        }
        else {
            this.paintImage();
        }

    };

    igv.TrackView.prototype.paintImage = function () {

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

        if (this.tile) {
            this.xOffset = Math.round(this.browser.referenceFrame.toPixels(this.tile.startBP - this.browser.referenceFrame.start));
            this.ctx.drawImage(this.tile.image, this.xOffset, 0);
            this.ctx.save();
            this.ctx.restore();
        }
    };

    igv.TrackView.prototype.setSortButtonDisplay = function (onOff) {
        this.track.sortButton.style.color = onOff ? "red" : "black";
    };

    function Tile(chr, tileStart, tileEnd, scale, image) {
        this.chr = chr;
        this.startBP = tileStart;
        this.endBP = tileEnd;
        this.scale = scale;
        this.image = image;
    }

    Tile.prototype.containsRange = function (chr, start, end, scale) {
        var hit = this.scale == scale && start >= this.startBP && end <= this.endBP && chr === this.chr;
        return hit;
    };

    function addTrackHandlers(trackView) {

        var isMouseDown = false,
            lastMouseX = undefined,
            mouseDownX = undefined,
            referenceFrame = trackView.browser.referenceFrame,
            canvas = trackView.canvas,
            dragThreshold = 3,
            popupTimer = undefined;

        $(canvas).mousedown(function (e) {

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (igv.popover) igv.popover.hide();

            isMouseDown = true;
            lastMouseX = canvasCoords.x;
            mouseDownX = lastMouseX;

        });

        $(canvas).mousemove(igv.throttle(function (e) {

                var coords = igv.translateMouseCoordinates(e, canvas),
                    pixels,
                    pixelsEnd,
                    viewPortWidth;

                if (isMouseDown) { // Possibly dragging

                    if (mouseDownX && Math.abs(coords.x - mouseDownX) > dragThreshold) {

                        referenceFrame.shiftPixels(lastMouseX - coords.x);

                        // clamp left
                        referenceFrame.start = Math.max(0, referenceFrame.start);

                        // clamp right
                        if (trackView.browser.cursorModel) {

                            // CURSOR track clamping
                            viewPortWidth = $(".igv-viewport-div").first().width();
                            pixelsEnd = Math.floor(trackView.browser.cursorModel.framePixelWidth * trackView.browser.cursorModel.filteredRegions.length);
                            pixels = Math.floor(trackView.browser.referenceFrame.toPixels(referenceFrame.start) + viewPortWidth);

                            if (pixels >= pixelsEnd) {
                                referenceFrame.start = trackView.browser.referenceFrame.toBP(pixelsEnd - viewPortWidth);
                            }

                        }

                        trackView.browser.repaint();
                    }

                    lastMouseX = coords.x;

                }

            }, 20)
        );

        $(canvas).mouseup(function (e) {

            e = $.event.fix(e);   // Sets pageX and pageY for browsers that don't support them

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (popupTimer) {
                // Cancel previous timer
                window.clearTimeout(popupTimer);
                popupTimer = undefined;
            }

            if (Math.abs(canvasCoords.x - mouseDownX) <= dragThreshold && trackView.track.popupData) {
                const doubleClickDelay = 300;
                popupTimer = window.setTimeout(function () {

                        var popupData,
                            genomicLocation = Math.floor((referenceFrame.start) + referenceFrame.toBP(canvasCoords.x)),
                            xOrigin;

                        if (undefined === genomicLocation) {
                            return;
                        }

                        xOrigin = Math.round(referenceFrame.toPixels((trackView.tile.startBP - referenceFrame.start)));

                        popupData = trackView.track.popupData(genomicLocation, canvasCoords.x - xOrigin, canvasCoords.y);

//                        popupData = igv.popover.testData( Math.floor( igv.random(2, 25) ) );

                        if (popupData && popupData.length > 0) {
                            igv.popover.show(e.pageX, e.pageY, igv.formatPopoverText(popupData));
                        }
                        mouseDownX = undefined;
                    },
                    doubleClickDelay);
            }
            else {
                mouseDownX = undefined;
            }

            isMouseDown = false;
            lastMouseX = undefined;

        });

        $(canvas).mouseout(function (e) {
            isMouseDown = false;
            lastMouseX = undefined;
            mouseDownX = undefined;
        });

        $(canvas).dblclick(function (e) {

            e = $.event.fix(e);   // Sets pageX and pageY for browsers that don't support them

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (popupTimer) {
                window.clearTimeout(popupTimer);
                popupTimer = undefined;

            }

            if (trackView.track.handleDblClick) {
                trackView.track.handleDblClick(dx, dy, trackView.viewportDiv);
            }
            else {
                var newCenter = Math.round(referenceFrame.start + canvasCoords.x * referenceFrame.bpPerPixel);
                referenceFrame.bpPerPixel /= 2;
                trackView.browser.goto(referenceFrame.chr, newCenter);
            }
        });

    }

    return igv;
})
(igv || {});
<commit_msg>Fix cursor double-click zoom<commit_after>var igv = (function (igv) {

    igv.TrackView = function (track, browser) {

        this.browser = browser;
        this.track = track;
        this.order = track.order || 0;
        this.marginBottom = 10;

        var viewportDiv,
            trackDiv,
            controlDiv,
            controlCanvas,
            contentDiv,
            canvas,
            closeButton,
            labelButton;

        // track
        trackDiv = document.createElement("div");
        browser.trackContainerDiv.appendChild(trackDiv);
        trackDiv.className = "igv-track-div";
        trackDiv.style.height = track.height + "px";
        this.trackDiv = trackDiv;

        // controls
        var controlWidth = browser.controlPanelWidth ? browser.controlPanelWidth : 50;

        controlDiv = document.createElement("div");
        controlDiv.className = "igv-control-div";
        controlDiv.style.width = controlWidth + "px";
        controlDiv.style.height = track.height + "px";
        this.controlDiv = controlDiv;

        controlCanvas = document.createElement('canvas');
        controlDiv.style.width = controlWidth + "px";
        trackDiv.appendChild(controlDiv);
        this.controlDiv = controlDiv;

        controlDiv.appendChild(controlCanvas);
        controlCanvas.style.width = controlDiv.clientWidth + "px";
        controlCanvas.style.height = controlDiv.clientHeight + "px";
        controlCanvas.setAttribute('width', controlDiv.clientWidth);
        controlCanvas.setAttribute('height', controlDiv.clientHeight);
        this.controlCanvas = controlCanvas;
        this.controlCtx = controlCanvas.getContext("2d");

        // viewport
        viewportDiv = document.createElement("div");
        viewportDiv.className = "igv-viewport-div";
        viewportDiv.style.left = controlDiv.clientWidth + "px";
        viewportDiv.style.height = track.height + "px";
        trackDiv.appendChild(viewportDiv);
        this.viewportDiv = viewportDiv;

        // content
        contentDiv = document.createElement("div");
        viewportDiv.appendChild(contentDiv);
        contentDiv.className = "igv-content-div";
        contentDiv.style.height = track.height + "px";
        this.contentDiv = contentDiv;

        canvas = document.createElement('canvas');
        contentDiv.appendChild(canvas);
        canvas.style.position = 'absolute';
        canvas.style.width = contentDiv.clientWidth + "px";
        canvas.style.height = track.height + "px";
        canvas.setAttribute('width', contentDiv.clientWidth);
        canvas.setAttribute('height', track.height);

        // CURSOR specific functions
        if (browser.type === "CURSOR") {

            this.track.cursorHistogram = new cursor.CursorHistogram(controlDiv.clientHeight, this.track.max);
            this.track.cursorHistogram.createMarkupWithTrackPanelDiv(this);

            igv.cursorAddTrackControlButtons(this, browser, controlDiv)

        }

        // Close button
        if (!track.disableButtons) {

            closeButton = document.createElement("i");
            contentDiv.appendChild(closeButton);
            closeButton.className = "fa fa-times-circle igv-track-disable-button-fontawesome";
            closeButton.onclick = function () {
                browser.removeTrack(track);
            };
            contentDiv.appendChild(closeButton);

            if (track.label) {

                labelButton = document.createElement("button");
                viewportDiv.appendChild(labelButton);
                labelButton.className = "btn btn-xs btn-cursor-deselected igv-track-label";
                labelButton.innerHTML = track.label;
                track.labelButton = labelButton;

                labelButton.onclick = function (e) {

                    if (browser.cursorModel) {
                        track.featureSource.allFeatures(function (featureList) {

                            browser.referenceFrame.start = 0;
                            browser.cursorModel.setRegions(featureList);

                        });

                    }
                    else {

                        if (track.description) {
                            igv.popover.show(e.pageX, e.pageY, track.description);
                        }

                    }

                }

            }
        }

        this.canvas = canvas;
        this.ctx = canvas.getContext("2d");

        addTrackHandlers(this);

    };

    igv.TrackView.prototype.resize = function () {
        var canvas = this.canvas,
            contentDiv = this.contentDiv,
            contentWidth = this.viewportDiv.clientWidth;
        //      contentHeight = this.canvas.getAttribute("height");  // Maintain the current height

        contentDiv.style.width = contentWidth + "px";      // Not sure why css is not working for this
        //  contentDiv.style.height = contentHeight + "px";

        canvas.style.width = contentWidth + "px";
        canvas.setAttribute('width', contentWidth);    //Must set the width & height of the canvas
        this.update();
    };

    igv.TrackView.prototype.setTrackHeight = function (newHeight) {

        var heightStr = newHeight + "px";
        this.track.height = newHeight;
        this.trackDiv.style.height = heightStr;
        // this.controlDiv.style.height = heightStr;
        // this.controlCanvas.style.height = heightStr;
        // this.controlCanvas.setAttribute("height", newHeight);
        this.viewportDiv.style.height = heightStr;
        this.contentDiv.style.height = heightStr;
        this.canvas.style.height = heightStr;
        this.canvas.setAttribute("height", newHeight);

        this.track.cursorHistogram.updateHeight(this.track, newHeight);

        this.update();
    };

    igv.TrackView.prototype.update = function () {
        this.tile = null;
        this.repaint();

    };

    igv.TrackView.prototype.repaint = function () {

        if (!this.track) {
            return;
        }

        var tileWidth,
            tileStart,
            tileEnd,
            spinner,
            buffer,
            myself = this,
            igvCanvas,
            referenceFrame = this.browser.referenceFrame,
            refFrameStart = referenceFrame.start,
            refFrameEnd = refFrameStart + referenceFrame.toBP(this.canvas.width);

        if (!this.tile || !this.tile.containsRange(referenceFrame.chr, refFrameStart, refFrameEnd, referenceFrame.bpPerPixel)) {

            buffer = document.createElement('canvas');
            buffer.width = 3 * this.canvas.width;
            buffer.height = this.canvas.height;
            igvCanvas = new igv.Canvas(buffer);

            tileWidth = Math.round(referenceFrame.toBP(buffer.width));
            tileStart = Math.max(0, Math.round(referenceFrame.start - tileWidth / 3));
            tileEnd = tileStart + tileWidth;

            spinner = igv.getSpinner(this.trackDiv);   // Start a spinner

            if (this.currentTask) {
                this.currentTask.abort();
            }
            this.currentTask = {
                canceled: false,
                abort: function () {
                    this.canceled = true;
                    if (this.xhrRequest) {
                        this.xhrRequest.abort();
                    }
                    spinner.stop();
                }

            };

            this.track.draw(igvCanvas, referenceFrame, tileStart, tileEnd, buffer.width, buffer.height, function (task) {

                    spinner.stop();

                    if (task) console.log(task.canceled);

                    if (!(task && task.canceled)) {
                        myself.tile = new Tile(referenceFrame.chr, tileStart, tileEnd, referenceFrame.bpPerPixel, buffer);
                        myself.paintImage();
                    }
                },
                this.currentTask);

            if (this.track.paintControl) {

                var buffer2 = document.createElement('canvas');
                buffer2.width = this.controlCanvas.width;
                buffer2.height = this.controlCanvas.height;

                var bufferCanvas = new igv.Canvas(buffer2);

                this.track.paintControl(bufferCanvas, buffer2.width, buffer2.height);

                this.controlCtx.drawImage(buffer2, 0, 0);
            }

        }
        else {
            this.paintImage();
        }

    };

    igv.TrackView.prototype.paintImage = function () {

        this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);

        if (this.tile) {
            this.xOffset = Math.round(this.browser.referenceFrame.toPixels(this.tile.startBP - this.browser.referenceFrame.start));
            this.ctx.drawImage(this.tile.image, this.xOffset, 0);
            this.ctx.save();
            this.ctx.restore();
        }
    };

    igv.TrackView.prototype.setSortButtonDisplay = function (onOff) {
        this.track.sortButton.style.color = onOff ? "red" : "black";
    };

    function Tile(chr, tileStart, tileEnd, scale, image) {
        this.chr = chr;
        this.startBP = tileStart;
        this.endBP = tileEnd;
        this.scale = scale;
        this.image = image;
    }

    Tile.prototype.containsRange = function (chr, start, end, scale) {
        var hit = this.scale == scale && start >= this.startBP && end <= this.endBP && chr === this.chr;
        return hit;
    };

    function addTrackHandlers(trackView) {

        var isMouseDown = false,
            lastMouseX = undefined,
            mouseDownX = undefined,
            referenceFrame = trackView.browser.referenceFrame,
            canvas = trackView.canvas,
            dragThreshold = 3,
            popupTimer = undefined;

        $(canvas).mousedown(function (e) {

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (igv.popover) igv.popover.hide();

            isMouseDown = true;
            lastMouseX = canvasCoords.x;
            mouseDownX = lastMouseX;

        });

        $(canvas).mousemove(igv.throttle(function (e) {

                var coords = igv.translateMouseCoordinates(e, canvas),
                    pixels,
                    pixelsEnd,
                    viewPortWidth;

                if (isMouseDown) { // Possibly dragging

                    if (mouseDownX && Math.abs(coords.x - mouseDownX) > dragThreshold) {

                        referenceFrame.shiftPixels(lastMouseX - coords.x);

                        // clamp left
                        referenceFrame.start = Math.max(0, referenceFrame.start);

                        // clamp right
                        if (trackView.browser.cursorModel) {

                            // CURSOR track clamping
                            viewPortWidth = $(".igv-viewport-div").first().width();
                            pixelsEnd = Math.floor(trackView.browser.cursorModel.framePixelWidth * trackView.browser.cursorModel.filteredRegions.length);
                            pixels = Math.floor(trackView.browser.referenceFrame.toPixels(referenceFrame.start) + viewPortWidth);

                            if (pixels >= pixelsEnd) {
                                referenceFrame.start = trackView.browser.referenceFrame.toBP(pixelsEnd - viewPortWidth);
                            }

                        }

                        trackView.browser.repaint();
                    }

                    lastMouseX = coords.x;

                }

            }, 20)
        );

        $(canvas).mouseup(function (e) {

            e = $.event.fix(e);   // Sets pageX and pageY for browsers that don't support them

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (popupTimer) {
                // Cancel previous timer
                window.clearTimeout(popupTimer);
                popupTimer = undefined;
            }

            if (Math.abs(canvasCoords.x - mouseDownX) <= dragThreshold && trackView.track.popupData) {
                const doubleClickDelay = 300;
                popupTimer = window.setTimeout(function () {

                        var popupData,
                            genomicLocation = Math.floor((referenceFrame.start) + referenceFrame.toBP(canvasCoords.x)),
                            xOrigin;

                        if (undefined === genomicLocation) {
                            return;
                        }

                        xOrigin = Math.round(referenceFrame.toPixels((trackView.tile.startBP - referenceFrame.start)));

                        popupData = trackView.track.popupData(genomicLocation, canvasCoords.x - xOrigin, canvasCoords.y);

//                        popupData = igv.popover.testData( Math.floor( igv.random(2, 25) ) );

                        if (popupData && popupData.length > 0) {
                            igv.popover.show(e.pageX, e.pageY, igv.formatPopoverText(popupData));
                        }
                        mouseDownX = undefined;
                    },
                    doubleClickDelay);
            }
            else {
                mouseDownX = undefined;
            }

            isMouseDown = false;
            lastMouseX = undefined;

        });

        $(canvas).mouseout(function (e) {
            isMouseDown = false;
            lastMouseX = undefined;
            mouseDownX = undefined;
        });

        $(canvas).dblclick(function (e) {

            e = $.event.fix(e);   // Sets pageX and pageY for browsers that don't support them

            var canvasCoords = igv.translateMouseCoordinates(e, canvas);

            if (popupTimer) {
                window.clearTimeout(popupTimer);
                popupTimer = undefined;

            }

            if (trackView.track.handleDblClick) {
                trackView.track.handleDblClick(dx, dy, trackView.viewportDiv);
            }
            else {
                var newCenter = Math.round(referenceFrame.start + canvasCoords.x * referenceFrame.bpPerPixel);
                referenceFrame.bpPerPixel /= 2;
                if(trackView.browser.cursorModel) {
                    trackView.browser.cursorModel.framePixelWidth *= 2;
                }
                trackView.browser.goto(referenceFrame.chr, newCenter);
            }
        });

    }

    return igv;
})
(igv || {});
<|endoftext|>