<commit_before>/**
 * Appcelerator Drillbit
 * Copyright (c) 2010 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
var TFS = Titanium.Filesystem;
var TA  = Titanium.App;
var Drillbit = Titanium.Drillbit;

var runLinkDisabled = false;
var frontend = {
	passed: 0, failed: 0,

	setup_finished: function() {
		runLinkDisabled = false;
		$("#run-link").removeClass("disabled");
	},

	status: function(text, loading) {
		loading = typeof(loading) == 'undefined' ? false : !!loading;

		var html = ''+text+'';
		if (loading) {
			html = ' '+html;
		}

		$('#current-test').html(html);
	},

	test_platform_status: function(name, classname, platform)
	{
		var id = genSuiteId(name);
		var el = $('#'+id+'_'+platform+'_status');
		el.html(classname);
		el.removeClass('untested').removeClass('failed').removeClass('running')
			.removeClass('passed').removeClass('init').addClass(classname.toLowerCase());
	},

	test_status: function(name, classname)
	{
		var id = genSuiteId(name);
		$('#'+id).removeClass('suite-untested').removeClass('suite-failed')
			.removeClass('suite-running').removeClass('suite-passed').addClass('suite-'+classname.toLowerCase());
	},

	test_passed: function(suite, test)
	{
		this.passed++;
	},

	test_failed: function(suite, test, line_number, error)
	{
		this.failed++;
	},

	suite_started: function(suite, platforms)
	{
		this.test_status(suite, 'Running');
		var self = this;
		platforms.forEach(function(platform) {
			self.test_platform_status(suite, 'Init', platform);
		});
	},

	building_test_harness: function(suite, platform)
	{
		this.test_platform_status(suite, 'Building', platform);
	},

	running_test_harness: function(suite, platform)
	{
		this.test_platform_status(suite, 'Running', platform);
	},

	total_progress: function(passed,failed,total)
	{
		$('#passed-count').html('  '+passed+' passed');
		$('#failed-count').html('  '+failed+' failed');
	},

	show_current_test: function(suite_name, test_name)
	{
		$('#current-test').html(''+suite_name + ':  ' + test_name);
	},

	add_assertion: function(test_name, line_number)
	{
		$('#assertion-count').html(Drillbit.totalAssertions+' assertions');
	},

	process_data: function(data)
	{
		var drillbit_console = $('#console');
		drillbit_console.append(data+"\n");
		drillbit_console.scrollTop(drillbit_console[0].scrollHeight);
		Drillbit.logStream.write(data+"\n");
	},

	all_finished: function()
	{
		var drillbit_console = $('#console');
		$("#run-link").removeClass("disabled");
		runLinkDisabled = false;
		$('#current-test').html('Finished. Took ' + Drillbit.testDuration + 's');
		$("#log-link").removeClass("disabled");
		drillbit_console.append("**********************FINISHED LOGGING**********************\n");
	}
};

function showTestDetails(name)
{
	var w = Titanium.UI.currentWindow.createWindow();
	w.setHeight(600);
	w.setWidth(850);
	w.setURL('app://test_results/' + name + '.html');
	w.open();
}

function toggleTestIncludes()
{
	$.each($("img.platform-check"),function()
	{
		if ($(this).attr('src').indexOf('check_on') == -1)
		{
			$(this).attr('src', 'images/check_on.png');
		}
		else
		{
			$(this).attr('src', 'images/check_off.png');
		}
	});
}

function clearCurrentTest()
{
	$('#current-test').html('<no tests currently running>')
}

function resetAll()
{
	$('img.platform-check').attr('src', 'images/check_on.png');
	$('div[id^=suite_]').removeClass().addClass('suite');
	$('span[id^=suite_]').removeClass().addClass('untested').html('untested');
	$('#assertion-count').html('0 assertions');
	$('#passed-count').html('  0 passed');
	$('#failed-count').html('  0 failed');
	clearCurrentTest();
	Drillbit.reset();
}

var suiteIds = {};
function genSuiteId(suite) {
	var id = "suite_" + suite.replace(/\./g, "_").replace(/\#/g, "_");
	suiteIds[id] = suite;
	return id;
}

function initUI() {
	clearCurrentTest();
	$("#test-count").html(Drillbit.totalTests + ' tests in ' + Drillbit.totalFiles + ' files');

	var suites_html = '';
	Drillbit.testNames.forEach(function(name) {
		var entry = Drillbit.tests[name];
		var id = genSuiteId(name);
		suites_html +=
		'
'+
			''+name+'
'+
			''+entry.description+'
'+
			'
';

		entry.platforms.forEach(function(platform) {
			suites_html += '
'+
				''+
				'untested
';
		});

		suites_html += '

';
	});

	$('div.suites').html(suites_html);
	$('div[class=suite-status]>div').click(function() {
		var checkImg = $(this).find('img[class$=-check]');
		if (checkImg.attr('src').indexOf('check_on') != -1) {
			checkImg.attr('src', 'images/check_off.png');
		} else {
			checkImg.attr('src', 'images/check_on.png');
		}
	});
	$('div[id^=suite_]').dblclick(function()
	{
		var suite = suiteIds[$(this).attr('id')];
		showTestDetails(suite);
	});
}

function reloadUI() {
	// try to preserve checkbox state
	var checks = {};
	$.each($("img.platform-check"), function() {
		var platformClass = $(this).attr("class");
		var platform = platformClass.substring(0, platformClass.indexOf('-'));

		var suiteDivId = $(this).parent().parent().parent().attr("id");
		var suite = suiteIds[suiteDivId];
		if (!(suiteDivId in checks)) {
			checks[suiteDivId] = {};
		}
		var checked = $(this).attr('src').indexOf('check_on') != -1;
		checks[suiteDivId][platform] = checked;
	});

	initUI();
	for (var suiteId in checks) {
		for (var platform in checks[suiteId]) {
			var check = $('#'+suiteId+'>div.suite-status>div>img.'+platform+'-check');
			var checked = checks[suiteId][platform];
			var src = checked ? 'images/check_on.png' : 'images/check_off.png';
			$(check).attr('src', src);
		}
	}
}

function reloadTests() {
	Drillbit.rescan();
	reloadUI();
}

$(window).ready(function()
{
	var mouseDown = false,
		startY = 0,
		drillbitConsole= document.getElementById('console'),
		drillbitResize= document.getElementById('resize-bar'),
		drillbitSuite=document.getElementsByClassName('suites')[0],
		startHeightConsole = $(drillbitConsole).height(),
		resizerHeight = 12,
		spaceBuffer = 85;

	window.moveTo(Titanium.App.Properties.getInt("windowX",400),Titanium.App.Properties.getInt("windowY", 600));
	window.resizeTo(Titanium.App.Properties.getInt("width", 600),Titanium.App.Properties.getInt("height", 800));
	$(drillbitConsole).height(Titanium.App.Properties.getInt("consoleHeight", 275));
	$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
	drillbitResize.style.bottom = $(drillbitConsole).height() + resizerHeight;

	if ('webConsole' in Drillbit.argv) {
		Titanium.UI.currentWindow.showInspector(true);
	}

	Drillbit.runTestsAsync = true;
	Drillbit.frontend = frontend;
	Drillbit.window = window;
	initUI();

	var suitesStatus = JSON.parse(Titanium.App.Properties.getString("suitesStatus", "{ }"));
	if (!('tests' in Drillbit.argv)) {
		loopThroughSuites(suitesStatus, "setup");
	}

	var runLink = $('#run-link');
	$('#toggle-link').click(function() {
		toggleTestIncludes();
	});
	$('#reset-link').click(function() {
		resetAll();
	});
	$('#reload-link').click(function() {
		reloadTests();
	});
	$('#clear-link').click(function() {
		$("#console").html("");
		return false;
	});
	$('#force-build-android').click(function() {
		if ('android' in Drillbit.emulators) {
			Drillbit.emulators.android.needsBuild = $(this).is(':checked');
		}
	});
	$('#log-link').click(function() {

		if(!$("#log-link").hasClass("disabled")){
			Titanium.Platform.openApplication(Drillbit.logPath.nativePath());
		}
	});

	$("#resize-bar").mousedown(function() {
		mouseDown = true;
		startHeightConsole = $(drillbitConsole).height();
		startY = event.clientY;
	});
	$("body").mousemove(function() {
		if (mouseDown)
		{
			mouseY = event.clientY;
			$(drillbitConsole).height((startY - mouseY) + startHeightConsole);
			$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
			drillbitResize.style.bottom = (startY - mouseY) + startHeightConsole + resizerHeight;

		}
	});
	$("body").mouseup(function() {
		if (mouseDown) {
			mouseDown = false;
			mouseY = event.clientY;
			$(drillbitConsole).height((startY - mouseY) + startHeightConsole);
			$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
			drillbitResize.style.bottom = (startY - mouseY) + startHeightConsole + resizerHeight;
		}
	});
	$(window).resize(function() {
		$(drillbitConsole).height(window.innerHeight-$(drillbitSuite).height()-spaceBuffer);
		drillbitResize.style.bottom = $(drillbitConsole).height() + resizerHeight;
	});
	function loopThroughSuites(suitesStatus, setupOrSave) {
		Drillbit.testNames.forEach(function(name) {
			var suiteId = genSuiteId(name);
			var suiteDiv = $('#' + suiteId);
			var entry = Drillbit.tests[name];
			if (setupOrSave == "save") {
				suitesStatus[name] = {};
			}
			entry.platforms.forEach(function(platform) {
				var platformCheck = suiteDiv.find('img.' + platform + '-check');
				if (setupOrSave == "save") {
					if ($(platformCheck).attr('src').indexOf('check_on') == -1) {
						suitesStatus[name][platform] = false;
					}
					else {
						suitesStatus[name][platform] = true;
					}
				}
				else {
					if (name in suitesStatus && platform in suitesStatus[name]) {
						var checked = suitesStatus[name][platform];
						if (!checked) {
							platformCheck.attr('src', 'images/check_off.png');
						}
						else {
							platformCheck.attr('src', 'images/check_on.png');
						}
					}
				}
			});
		});
		Titanium.App.Properties.setString("suitesStatus", JSON.stringify(suitesStatus));
	};
	function saveSettings() {
		var bounds = Titanium.UI.currentWindow.getBounds();
		Titanium.App.Properties.setInt("windowX", bounds.x);
		Titanium.App.Properties.setInt("windowY", bounds.y);
		Titanium.App.Properties.setInt("height", bounds.height);
		Titanium.App.Properties.setInt("width", bounds.width);
		Titanium.App.Properties.setInt("consoleHeight", $(drillbitConsole).height());
		var suitesStatus = {};
		loopThroughSuites(suitesStatus, "save");
	};
	Titanium.UI.currentWindow.addEventListener("close", saveSettings);
	runLink.click(function () {
		if (!runLinkDisabled)
		{
			reloadTests();

			runLinkDisabled = true;
			$("#run-link").addClass("disabled");
			$("#clear-link").click();

			var tests = [];
			$.each($('div[id^=suite_]'),function()
			{
				var name = suiteIds[$(this).attr('id')];
				frontend.test_status(name, 'untested');

				var test = {suite: name, tests: 'all', platforms: []};
				var add_test = false;
				$(this).find('div.suite-status > div > img[class$=\'-check\']').each(function() {
					if ($(this).attr('src').indexOf('check_on') != -1) {
						var className = $(this).attr('class');
						var platform = className.substring(0, className.indexOf('-'));
						Titanium.API.debug("checked: " + name + " platform: " + platform);
						test.platforms.push(platform);
						add_test = true;
					}
				});
				if (add_test) {
					tests.push(test);
				}
			});

			Titanium.API.debug("running tests: " + tests.length);
			Drillbit.runTests(tests, true);
		}
		else
		{
			alert("Tests are currently running");
		}
	});

	if ('tests' in Drillbit.argv) {
		toggleTestIncludes();
		Drillbit.argv.tests.split(",").forEach(function(test) {
			var suiteId = genSuiteId(test);
			$('#'+suiteId+'>div.suite-status>div>img.platform-check').attr('src', 'images/check_on.png');
		});
	}

	if ('autoclose' in Drillbit.argv) {
		Drillbit.autoClose = true;
	}

	if ('autorun' in Drillbit.argv) {
		runLink.click();
	}
});

<commit_msg>Made the function take a handler function as a parameter to handle whether or not to save or setup. timob-2285<commit_after>/**
 * Appcelerator Drillbit
 * Copyright (c) 2010 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Apache Public License
 * Please see the LICENSE included with this distribution for details.
 */
var TFS = Titanium.Filesystem;
var TA  = Titanium.App;
var Drillbit = Titanium.Drillbit;

var runLinkDisabled = false;
var frontend = {
	passed: 0, failed: 0,

	setup_finished: function() {
		runLinkDisabled = false;
		$("#run-link").removeClass("disabled");
	},

	status: function(text, loading) {
		loading = typeof(loading) == 'undefined' ? false : !!loading;

		var html = ''+text+'';
		if (loading) {
			html = ' '+html;
		}

		$('#current-test').html(html);
	},

	test_platform_status: function(name, classname, platform)
	{
		var id = genSuiteId(name);
		var el = $('#'+id+'_'+platform+'_status');
		el.html(classname);
		el.removeClass('untested').removeClass('failed').removeClass('running')
			.removeClass('passed').removeClass('init').addClass(classname.toLowerCase());
	},

	test_status: function(name, classname)
	{
		var id = genSuiteId(name);
		$('#'+id).removeClass('suite-untested').removeClass('suite-failed')
			.removeClass('suite-running').removeClass('suite-passed').addClass('suite-'+classname.toLowerCase());
	},

	test_passed: function(suite, test)
	{
		this.passed++;
	},

	test_failed: function(suite, test, line_number, error)
	{
		this.failed++;
	},

	suite_started: function(suite, platforms)
	{
		this.test_status(suite, 'Running');
		var self = this;
		platforms.forEach(function(platform) {
			self.test_platform_status(suite, 'Init', platform);
		});
	},

	building_test_harness: function(suite, platform)
	{
		this.test_platform_status(suite, 'Building', platform);
	},

	running_test_harness: function(suite, platform)
	{
		this.test_platform_status(suite, 'Running', platform);
	},

	total_progress: function(passed,failed,total)
	{
		$('#passed-count').html('  '+passed+' passed');
		$('#failed-count').html('  '+failed+' failed');
	},

	show_current_test: function(suite_name, test_name)
	{
		$('#current-test').html(''+suite_name + ':  ' + test_name);
	},

	add_assertion: function(test_name, line_number)
	{
		$('#assertion-count').html(Drillbit.totalAssertions+' assertions');
	},

	process_data: function(data)
	{
		var drillbit_console = $('#console');
		drillbit_console.append(data+"\n");
		drillbit_console.scrollTop(drillbit_console[0].scrollHeight);
		Drillbit.logStream.write(data+"\n");
	},

	all_finished: function()
	{
		var drillbit_console = $('#console');
		$("#run-link").removeClass("disabled");
		runLinkDisabled = false;
		$('#current-test').html('Finished. Took ' + Drillbit.testDuration + 's');
		$("#log-link").removeClass("disabled");
		drillbit_console.append("**********************FINISHED LOGGING**********************\n");
	}
};

function showTestDetails(name)
{
	var w = Titanium.UI.currentWindow.createWindow();
	w.setHeight(600);
	w.setWidth(850);
	w.setURL('app://test_results/' + name + '.html');
	w.open();
}

function toggleTestIncludes()
{
	$.each($("img.platform-check"),function()
	{
		if ($(this).attr('src').indexOf('check_on') == -1)
		{
			$(this).attr('src', 'images/check_on.png');
		}
		else
		{
			$(this).attr('src', 'images/check_off.png');
		}
	});
}

function clearCurrentTest()
{
	$('#current-test').html('<no tests currently running>')
}

function resetAll()
{
	$('img.platform-check').attr('src', 'images/check_on.png');
	$('div[id^=suite_]').removeClass().addClass('suite');
	$('span[id^=suite_]').removeClass().addClass('untested').html('untested');
	$('#assertion-count').html('0 assertions');
	$('#passed-count').html('  0 passed');
	$('#failed-count').html('  0 failed');
	clearCurrentTest();
	Drillbit.reset();
}

var suiteIds = {};
function genSuiteId(suite) {
	var id = "suite_" + suite.replace(/\./g, "_").replace(/\#/g, "_");
	suiteIds[id] = suite;
	return id;
}

function initUI() {
	clearCurrentTest();
	$("#test-count").html(Drillbit.totalTests + ' tests in ' + Drillbit.totalFiles + ' files');

	var suites_html = '';
	Drillbit.testNames.forEach(function(name) {
		var entry = Drillbit.tests[name];
		var id = genSuiteId(name);
		suites_html +=
		'
'+
			''+name+'
'+
			''+entry.description+'
'+
			'
';

		entry.platforms.forEach(function(platform) {
			suites_html += '
'+
				''+
				'untested
';
		});

		suites_html += '

';
	});

	$('div.suites').html(suites_html);
	$('div[class=suite-status]>div').click(function() {
		var checkImg = $(this).find('img[class$=-check]');
		if (checkImg.attr('src').indexOf('check_on') != -1) {
			checkImg.attr('src', 'images/check_off.png');
		} else {
			checkImg.attr('src', 'images/check_on.png');
		}
	});
	$('div[id^=suite_]').dblclick(function()
	{
		var suite = suiteIds[$(this).attr('id')];
		showTestDetails(suite);
	});
}

function reloadUI() {
	// try to preserve checkbox state
	var checks = {};
	$.each($("img.platform-check"), function() {
		var platformClass = $(this).attr("class");
		var platform = platformClass.substring(0, platformClass.indexOf('-'));

		var suiteDivId = $(this).parent().parent().parent().attr("id");
		var suite = suiteIds[suiteDivId];
		if (!(suiteDivId in checks)) {
			checks[suiteDivId] = {};
		}
		var checked = $(this).attr('src').indexOf('check_on') != -1;
		checks[suiteDivId][platform] = checked;
	});

	initUI();
	for (var suiteId in checks) {
		for (var platform in checks[suiteId]) {
			var check = $('#'+suiteId+'>div.suite-status>div>img.'+platform+'-check');
			var checked = checks[suiteId][platform];
			var src = checked ? 'images/check_on.png' : 'images/check_off.png';
			$(check).attr('src', src);
		}
	}
}

function reloadTests() {
	Drillbit.rescan();
	reloadUI();
}

$(window).ready(function()
{
	var mouseDown = false,
		startY = 0,
		drillbitConsole= document.getElementById('console'),
		drillbitResize= document.getElementById('resize-bar'),
		drillbitSuite=document.getElementsByClassName('suites')[0],
		startHeightConsole = $(drillbitConsole).height(),
		resizerHeight = 12,
		spaceBuffer = 85;

	window.moveTo(Titanium.App.Properties.getInt("windowX",400),Titanium.App.Properties.getInt("windowY", 600));
	window.resizeTo(Titanium.App.Properties.getInt("width", 600),Titanium.App.Properties.getInt("height", 800));
	$(drillbitConsole).height(Titanium.App.Properties.getInt("consoleHeight", 275));
	$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
	drillbitResize.style.bottom = $(drillbitConsole).height() + resizerHeight;

	if ('webConsole' in Drillbit.argv) {
		Titanium.UI.currentWindow.showInspector(true);
	}

	Drillbit.runTestsAsync = true;
	Drillbit.frontend = frontend;
	Drillbit.window = window;
	initUI();

	if (!('tests' in Drillbit.argv)) {
		eachPlatformCheck(function(name, platform, platformCheck, suitesStatus) {
			if (name in suitesStatus && platform in suitesStatus[name]) {
				var checked = suitesStatus[name][platform];
				platformCheck.attr('src', 'images/check_' + (checked ? 'on' : 'off') + '.png');
			}
		});
	}

	var runLink = $('#run-link');
	$('#toggle-link').click(function() {
		toggleTestIncludes();
	});
	$('#reset-link').click(function() {
		resetAll();
	});
	$('#reload-link').click(function() {
		reloadTests();
	});
	$('#clear-link').click(function() {
		$("#console").html("");
		return false;
	});
	$('#force-build-android').click(function() {
		if ('android' in Drillbit.emulators) {
			Drillbit.emulators.android.needsBuild = $(this).is(':checked');
		}
	});
	$('#log-link').click(function() {

		if(!$("#log-link").hasClass("disabled")){
			Titanium.Platform.openApplication(Drillbit.logPath.nativePath());
		}
	});

	$("#resize-bar").mousedown(function() {
		mouseDown = true;
		startHeightConsole = $(drillbitConsole).height();
		startY = event.clientY;
	});
	$("body").mousemove(function() {
		if (mouseDown)
		{
			mouseY = event.clientY;
			$(drillbitConsole).height((startY - mouseY) + startHeightConsole);
			$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
			drillbitResize.style.bottom = (startY - mouseY) + startHeightConsole + resizerHeight;

		}
	});
	$("body").mouseup(function() {
		if (mouseDown) {
			mouseDown = false;
			mouseY = event.clientY;
			$(drillbitConsole).height((startY - mouseY) + startHeightConsole);
			$(drillbitSuite).height(window.innerHeight - spaceBuffer - $(drillbitConsole).height());
			drillbitResize.style.bottom = (startY - mouseY) + startHeightConsole + resizerHeight;
		}
	});
	$(window).resize(function() {
		$(drillbitConsole).height(window.innerHeight-$(drillbitSuite).height()-spaceBuffer);
		drillbitResize.style.bottom = $(drillbitConsole).height() + resizerHeight;
	});

	function eachPlatformCheck(fn) {
		var suitesStatus = JSON.parse(Titanium.App.Properties.getString("suitesStatus", "{ }"));
		Drillbit.testNames.forEach(function(name) {
			var suiteId = genSuiteId(name);
			var suiteDiv = $('#' + suiteId);
			var entry = Drillbit.tests[name];
			entry.platforms.forEach(function(platform) {
				var platformCheck = suiteDiv.find('img.' + platform + '-check');
				fn(name, platform, platformCheck,suitesStatus);
			});
		});
		Titanium.App.Properties.setString("suitesStatus", JSON.stringify(suitesStatus));
	};

	function saveSettings() {
		var bounds = Titanium.UI.currentWindow.getBounds();
		Titanium.App.Properties.setInt("windowX", bounds.x);
		Titanium.App.Properties.setInt("windowY", bounds.y);
		Titanium.App.Properties.setInt("height", bounds.height);
		Titanium.App.Properties.setInt("width", bounds.width);
		Titanium.App.Properties.setInt("consoleHeight", $(drillbitConsole).height());
		eachPlatformCheck(function(name, platform, platformCheck, suitesStatus) {
			suitesStatus[name][platform] = $(platformCheck).attr('src').indexOf('check_on') != -1;
		});
	};
	Titanium.UI.currentWindow.addEventListener("close", saveSettings);
	runLink.click(function () {
		if (!runLinkDisabled)
		{
			reloadTests();

			runLinkDisabled = true;
			$("#run-link").addClass("disabled");
			$("#clear-link").click();

			var tests = [];
			$.each($('div[id^=suite_]'),function()
			{
				var name = suiteIds[$(this).attr('id')];
				frontend.test_status(name, 'untested');

				var test = {suite: name, tests: 'all', platforms: []};
				var add_test = false;
				$(this).find('div.suite-status > div > img[class$=\'-check\']').each(function() {
					if ($(this).attr('src').indexOf('check_on') != -1) {
						var className = $(this).attr('class');
						var platform = className.substring(0, className.indexOf('-'));
						Titanium.API.debug("checked: " + name + " platform: " + platform);
						test.platforms.push(platform);
						add_test = true;
					}
				});
				if (add_test) {
					tests.push(test);
				}
			});

			Titanium.API.debug("running tests: " + tests.length);
			Drillbit.runTests(tests, true);
		}
		else
		{
			alert("Tests are currently running");
		}
	});

	if ('tests' in Drillbit.argv) {
		toggleTestIncludes();
		Drillbit.argv.tests.split(",").forEach(function(test) {
			var suiteId = genSuiteId(test);
			$('#'+suiteId+'>div.suite-status>div>img.platform-check').attr('src', 'images/check_on.png');
		});
	}

	if ('autoclose' in Drillbit.argv) {
		Drillbit.autoClose = true;
	}

	if ('autorun' in Drillbit.argv) {
		runLink.click();
	}
});

<|endoftext|>


<commit_before>'use strict';
var React = require('react');

var Util = require('./util');
var Layout = require('./layout');
var Depot = require('./depot');

var Carousel = React.createClass({displayName: "Carousel",
    getInitialState: function () {
        return {
            cards: this.props.cards,
            figures: Layout[this.props.layout].figures(this.props.width, this.props.cards, 0),
            rotationY: 0
        };
    },
    componentWillMount: function () {
        this.depot = Depot(this.getInitialState(), this.props, this.setState.bind(this));
        this.onRotate = this.depot.onRotate.bind(this);
    },
    componentWillReceiveProps: function (nextProps) {
        this.depot.onNextProps(nextProps);
    },
    render: function () {
        var angle = (2 * Math.PI) / this.state.figures.length;
        var translateZ = -Layout[this.props.layout].distance(this.props.width,
            this.state.figures.length);
        var figures = this.state.figures.map(function (d, i) {
            return (React.createElement("figure", {key: i, style: Util.figureStyle(d)},
               React.createElement("div", {className: "ui card"},
                 React.createElement("div", {className: "image"},
                   React.createElement("img", {src: d.card.hash.image_url})
                 ),
                 React.createElement("div", {className: "content"},
                   React.createElement("a", {className: "header", href: d.card.hash.url, target: "_new"}, d.card.hash.name)
                 ),
                 React.createElement("div", {className: "extra content"},
                   React.createElement("span", null,
                    React.createElement("i", {className: "red star icon"}), d.card.hash.rating
                   ),
                   React.createElement("span", {className: "card-category"}, d.card.hash.categories[0][0]),
                   React.createElement("span", {className: "right floated"},
                     React.createElement("a", {href: "https://maps.google.com/maps?q="+d.card.hash.location.display_address[0] + " " + d.card.hash.location.display_address[1], target: "_blank"}, React.createElement("i", {className: "red map icon"}), d.card.hash.location.display_address[0])
                   )
                 )
               )
               ));
        });
        return (
          React.createElement("div", null,
            React.createElement("section", {className: "react-3d-carousel"},
            React.createElement("div", {className: "carousel",
            style: {transform: "translateZ("+translateZ+"px)"}},
            figures
            ),
            React.createElement("div", {className: "prev", onClick: Util.partial(this.onRotate,+angle)}),
            React.createElement("div", {className: "next", onClick: Util.partial(this.onRotate,-angle)})
            ),
            React.createElement("div", {className: "spin-button"},
              React.createElement("button", {className: "massive ui red button", onClick: Util.partial(this.onRotate,-((Math.floor(Math.random() * (39 - 19 + 1)) + 19)*angle))},
                React.createElement("i", {className: "refresh icon spinning-button"})
              )
            )
          )
        );
    }
});
module.exports = Carousel;
<commit_msg>change google maps address to be more specific<commit_after>'use strict';
var React = require('react');

var Util = require('./util');
var Layout = require('./layout');
var Depot = require('./depot');

var Carousel = React.createClass({displayName: "Carousel",
    getInitialState: function () {
        return {
            cards: this.props.cards,
            figures: Layout[this.props.layout].figures(this.props.width, this.props.cards, 0),
            rotationY: 0
        };
    },
    componentWillMount: function () {
        this.depot = Depot(this.getInitialState(), this.props, this.setState.bind(this));
        this.onRotate = this.depot.onRotate.bind(this);
    },
    componentWillReceiveProps: function (nextProps) {
        this.depot.onNextProps(nextProps);
    },
    render: function () {
        var angle = (2 * Math.PI) / this.state.figures.length;
        var translateZ = -Layout[this.props.layout].distance(this.props.width,
            this.state.figures.length);
        var figures = this.state.figures.map(function (d, i) {
            return (React.createElement("figure", {key: i, style: Util.figureStyle(d)},
               React.createElement("div", {className: "ui card"},
                 React.createElement("div", {className: "image"},
                   React.createElement("img", {src: d.card.hash.image_url})
                 ),
                 React.createElement("div", {className: "content"},
                   React.createElement("a", {className: "header", href: d.card.hash.url, target: "_new"}, d.card.hash.name)
                 ),
                 React.createElement("div", {className: "extra content"},
                   React.createElement("span", null,
                    React.createElement("i", {className: "red star icon"}), d.card.hash.rating
                   ),
                   React.createElement("span", {className: "card-category"}, d.card.hash.categories[0][0]),
                   React.createElement("span", {className: "right floated"},
                     React.createElement("a", {href: "https://maps.google.com/maps?q="+d.card.hash.location.address[0] + " " + d.card.hash.location.city, target: "_blank"}, React.createElement("i", {className: "red map icon"}), d.card.hash.location.display_address[0])
                   )
                 )
               )
               ));
        });
        return (
          React.createElement("div", null,
            React.createElement("section", {className: "react-3d-carousel"},
            React.createElement("div", {className: "carousel",
            style: {transform: "translateZ("+translateZ+"px)"}},
            figures
            ),
            React.createElement("div", {className: "prev", onClick: Util.partial(this.onRotate,+angle)}),
            React.createElement("div", {className: "next", onClick: Util.partial(this.onRotate,-angle)})
            ),
            React.createElement("div", {className: "spin-button"},
              React.createElement("button", {className: "massive ui red button", onClick: Util.partial(this.onRotate,-((Math.floor(Math.random() * (39 - 19 + 1)) + 19)*angle))},
                React.createElement("i", {className: "refresh icon spinning-button"})
              )
            )
          )
        );
    }
});
module.exports = Carousel;
<|endoftext|>


<commit_before>/*
 * Copyright 2008-2012 Microarray Informatics Team, EMBL-European Bioinformatics Institute
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *
 * For further details of the Gene Expression Atlas project, including source code,
 * downloads and documentation, please see:
 *
 * http://gxa.github.com/gxa
 */

/*global $, jQuery, console:false */
var helpTooltipsModule = (function($) {
    "use strict";

    var _contextRoot;

    function buildHelpAnchor() {
        return $("<a/>", {
                    'class': 'help-icon',
                    'href': '#',
                    'title': '',
                    'text': '?'
                });
    }

    function getHelpFileName(pageName){
        return 'help-tooltips.' + pageName + '-page.html';
    }

    function getHelpLocation(pageName, inlineAnchor) {
        return _contextRoot + '/resources/html/' + getHelpFileName(pageName) + ' ' + inlineAnchor;
    }

    function initTooltips(pageName, parentElementId){

        var anchor = buildHelpAnchor();

        var helpSelector = (typeof parentElementId === "object") ? parentElementId : (parentElementId == '') ? "[data-help-loc]" : "#" + parentElementId + " [data-help-loc]";

        $(helpSelector)
            .append(anchor)
            .click(function(e) {
                e.preventDefault();
            })
            .tooltip(
            {
                tooltipClass: "gxaHelpTooltip",
                content: function(callback) {
                    var tooltipHelpHtmlId = $(this).parent().attr('data-help-loc');

                    // load help text into #help-placeholder. NB: page must contain a div with id help-placeholder
                    $("#help-placeholder").load(getHelpLocation(pageName, tooltipHelpHtmlId),
                        function (response, status, xhr) {
                            var tooltipContent;
                            if (status === "error") {
                                tooltipContent = "Sorry but there was an error: " + xhr.status + " " + xhr.statusText;
                                callback(tooltipContent);
                                return;
                            }
                            tooltipContent = $(this).text();
                            if (!tooltipContent){
                                tooltipContent = "Missing help section for id = " + tooltipHelpHtmlId + " in html file " + getHelpFileName(pageName);
                            }
                            callback(tooltipContent);

                        }
                    );

                }
            });

    }

    return {
        init:  function(pageName, contextRoot, parentElementId) {
                    _contextRoot = contextRoot;
                    initTooltips(pageName, parentElementId);
                },
        buildHelpAnchor: buildHelpAnchor,
        getHelpFileName: getHelpFileName
    };

}(jQuery));
<commit_msg>Remove global help tooltips module<commit_after><|endoftext|>


<commit_before>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * @toc {Sensors} Sensors
 * @featureID blackberry.sensors
 * @namespace The Sensors object allows you to get access to system level sensors and attributes of the BlackBerry device.

 *
The sensors object has various event listeners for sensors on the device.
 * @example
 * <script type="text/javascript">
 *
 * // Create a callback to handle each sensor
 * function compassCallback(sensor, data) {
 *     alert("Current azimuth: " + data.value);
 * }
 *
 * // Start listening to the compass sensor with a delay feedback of 1000
 * blackberry.sensors.setOptions("devicecompass", { delay : 1000 });
 *
 * // Start the event listener for the sensors callback
 * blackberry.event.addEventListener("devicecompass", compassCallback);
 *
 * </script>
 */
blackberry.sensors ={

    /**
     * Device accelerometer sensor.
     *
This sensor returns accelerometer data. Returned as m/s/s (meters/second/second).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    deviceaccelerometer: function(data) {
    },

    /**
     * Device magnetometer sensor.
     *
This sensor returns values from the device's magnetometer. Returned as µT (micro Tesla).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicemagnetometer: function(data) {
    },

    /**
     * Device gyroscope sensor.
     *
This sensor returns data from the gyroscope sensor. Returned as r/s (radians/second).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @param {Float} [data.temperature] The temperature of the gyroscope sensor (in degrees Celsius).
     * @event
     * @BB10X
     */
    devicegyroscope: function (data) {
    },

    /**
     * Device compass sensor.
     *
This sensor returns directional information from the compass sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.value] Azimuth from 0 -> 360 degrees from magnetic north.
     * @param {Number} [data.isFaceDown] 1 if face is down and compass heading is flipped, 0 otherwise.
     * @event
     * @BB10X
     */
    devicecompass: function (data) {
    },

    /**
     * Device proximity sensor.
     *
This sensor returns data from the proximity sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.value] Discrete steps of distance or actual value in cm.
     * @param {Float} [data.normalized] 0.0 -> 1.0 (close -> far), normalized unit-less signal from raw sensor.
     * @event
     * @BB10X
     */
    deviceproximity: function (data) {
    },

    /**
     * Device light sensor.
     *
This sensor returns brightness information from the light sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.value] Illuminance in lux.
     * @event
     * @BB10X
     */
    devicelight: function (data) {
    },

    /**
     * Device gravity sensor.
     *
This sensor returns gravity information from the gravity sensor. Returned as m/s/s (meters/second/second).
     *
Only the acceleration caused by gravity is reported. Movements of the device caused by the user have no effect other than changing the direction when the device is rotated.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicegravity: function (data) {
    },

    /**
     * Device linear acceleration sensor.
     *
This sensor returns linear acceleration data from the device accelerometer. Returned as m/s/s (meters/second/second).
     *
Only the acceleration caused by the user moving the device is reported, the effect of gravity is canceled out.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicelinearacceleration: function (data) {
    },

    /**
     * Device rotation matrix sensor.
     *
This sensor returns a rotation matrix based on the orientation of the device.
     * @param {Object} data The object containing the sensor data.
     * @param {Array} [data.matrix] Float array of data values representing the matrix.
     * @event
     * @BB10X
     */
    devicerotationmatrix: function (data) {
    },

    /**
     * Device orientation sensor.
     *
This sensor returns device orientation information.
     *
This relates to the physical device orientation.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.screen] Screen rotation in degrees: 0, 90, 180 or 270.
     * @param {String} [data.face] String-based representation of device face.
     * @event
     * @BB10X
     */
    deviceorientation: function (data) {
    },

    /**
     * Device sensor azimuth pitch roll sensor.
     *
This sensor returns a rotation matrix based on the orientation of the device.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.azimuth] Azimuth from 0 -> 360 degrees from magnetic north.
     * @param {Float} [data.pitch] Pitch from -180 to 180 degrees.
     * @param {Float} [data.roll] Roll from -90 to 90 degrees.
     * @event
     * @BB10X
     */
    deviceazimuthpitchroll: function (data) {
    },

    /**
     * Device holster detection sensor.
     *
This sensor returns the status of the holster sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.value] 1 if device is holstered, 0 otherwise.
     * @event
     * @BB10X
     */
    deviceholster: function (data) {
    },

    /**
     * @param {String} sensor The sensor to listen to.
     * @param {Object} options The options for the sensor being started.
     * @description This method will start a sensor with the specifed options and begin returning it to the added event listener.

     *
The supported object fields for 'options' are:
     * @param {String} [options.delay] Time in µs (microseconds) to report back between sensor updates.
     * @param {Boolean} [options.background] Allow sensor to send updates while the screen is off.
     * @param {Boolean} [options.batching] When batching is enabled and supported by the hardware, sensors will report samples in hardware-specific batch sizes to conserve power.
     * @param {Boolean} [options.queue] Enabling the queue creates a client-specific service side queue of events, this is useful to not miss any events.
     * @param {Boolean} [options.reducedReporting] When reduced reporting is enabled, only a significant change between the last read event and the current unread event will cause an event to be delivered (useful for power saving).
     * @BB10X
     */
    setOptions: function(sensor, options){},
};
<commit_msg>Updated sensors documentation to include supportedSensors property<commit_after>/*
* Copyright 2010-2011 Research In Motion Limited.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
 * @toc {Sensors} Sensors
 * @featureID blackberry.sensors
 * @namespace The Sensors object allows you to get access to system level sensors and attributes of the BlackBerry device.

 *
The sensors object has various event listeners for sensors on the device.
 * @example
 * <script type="text/javascript">
 *
 * // Create a callback to handle each sensor
 * function compassCallback(sensor, data) {
 *     alert("Current azimuth: " + data.value);
 * }
 *
 * // Start listening to the compass sensor with a delay feedback of 1000 microseconds
 * blackberry.sensors.setOptions("devicecompass", { delay: 1000 });
 *
 * // Start the event listener for the sensors callback
 * blackberry.event.addEventListener("devicecompass", compassCallback);
 *
 * // Set the sensor to work in the background and use batching mode
 * blackberry.sensors.setOptions("devicecompass", { background: true, batching: true });
 *
 * </script>
 */
blackberry.sensors ={

    /**
     * Device accelerometer sensor.
     *
This sensor returns accelerometer data. Returned as m/s/s (meters/second/second).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    deviceaccelerometer: function(data) {
    },

    /**
     * Device magnetometer sensor.
     *
This sensor returns values from the device's magnetometer. Returned as µT (micro Tesla).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicemagnetometer: function(data) {
    },

    /**
     * Device gyroscope sensor.
     *
This sensor returns data from the gyroscope sensor. Returned as r/s (radians/second).
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @param {Float} [data.temperature] The temperature of the gyroscope sensor (in degrees Celsius).
     * @event
     * @BB10X
     */
    devicegyroscope: function (data) {
    },

    /**
     * Device compass sensor.
     *
This sensor returns directional information from the compass sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.value] Azimuth from 0 -> 360 degrees from magnetic north.
     * @param {Number} [data.isFaceDown] 1 if face is down and compass heading is flipped, 0 otherwise.
     * @event
     * @BB10X
     */
    devicecompass: function (data) {
    },

    /**
     * Device proximity sensor.
     *
This sensor returns data from the proximity sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.value] Discrete steps of distance or actual value in cm.
     * @param {Float} [data.normalized] 0.0 -> 1.0 (close -> far), normalized unit-less signal from raw sensor.
     * @event
     * @BB10X
     */
    deviceproximity: function (data) {
    },

    /**
     * Device light sensor.
     *
This sensor returns brightness information from the light sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.value] Illuminance in lux.
     * @event
     * @BB10X
     */
    devicelight: function (data) {
    },

    /**
     * Device gravity sensor.
     *
This sensor returns gravity information from the gravity sensor. Returned as m/s/s (meters/second/second).
     *
Only the acceleration caused by gravity is reported. Movements of the device caused by the user have no effect other than changing the direction when the device is rotated.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicegravity: function (data) {
    },

    /**
     * Device linear acceleration sensor.
     *
This sensor returns linear acceleration data from the device accelerometer. Returned as m/s/s (meters/second/second).
     *
Only the acceleration caused by the user moving the device is reported, the effect of gravity is canceled out.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.x] The x-axis value.
     * @param {Float} [data.y] The y-axis value.
     * @param {Float} [data.z] The z-axis value.
     * @event
     * @BB10X
     */
    devicelinearacceleration: function (data) {
    },

    /**
     * Device rotation matrix sensor.
     *
This sensor returns a rotation matrix based on the orientation of the device.
     * @param {Object} data The object containing the sensor data.
     * @param {Array} [data.matrix] Float array of data values representing the matrix.
     * @event
     * @BB10X
     */
    devicerotationmatrix: function (data) {
    },

    /**
     * Device orientation sensor.
     *
This sensor returns device orientation information.
     *
This relates to the physical device orientation.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.screen] Screen rotation in degrees: 0, 90, 180 or 270.
     * @param {String} [data.face] String-based representation of device face.
     * @event
     * @BB10X
     */
    deviceorientation: function (data) {
    },

    /**
     * Device sensor azimuth pitch roll sensor.
     *
This sensor returns a rotation matrix based on the orientation of the device.
     * @param {Object} data The object containing the sensor data.
     * @param {Float} [data.azimuth] Azimuth from 0 -> 360 degrees from magnetic north.
     * @param {Float} [data.pitch] Pitch from -180 to 180 degrees.
     * @param {Float} [data.roll] Roll from -90 to 90 degrees.
     * @event
     * @BB10X
     */
    deviceazimuthpitchroll: function (data) {
    },

    /**
     * Device holster detection sensor.
     *
This sensor returns the status of the holster sensor.
     * @param {Object} data The object containing the sensor data.
     * @param {Number} [data.value] 1 if device is holstered, 0 otherwise.
     * @event
     * @BB10X
     */
    deviceholster: function (data) {
    },

    /**
     * @param {String} sensor The sensor to listen to.
     * @param {Object} options The options for the sensor being started.
     * @description This function will set a sensor with the specifed options. Sensor options can be set before or after the sensor is active.

     *
The supported object fields for 'options' are:
     * @param {String} [options.delay] Time in µs (microseconds) to report back between sensor updates.
     * @param {Boolean} [options.background] Allow sensor to send updates while the screen is off.
     * @param {Boolean} [options.batching] When batching is enabled and supported by the hardware, sensors will report samples in hardware-specific batch sizes to conserve power.
     * @param {Boolean} [options.queue] Enabling the queue creates a client-specific service side queue of events, this is useful to not miss any events.
     * @param {Boolean} [options.reducedReporting] When reduced reporting is enabled, only a significant change between the last read event and the current unread event will cause an event to be delivered (useful for power saving).
     * @BB10X
     */
    setOptions: function(sensor, options){},

    /**
     * Returns an array of the supported sensors on the current device.
     * @readOnly
     * @BB10X
     */
    supportedSensors: []
};
<|endoftext|>


<commit_before>import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { View, TextInput, TouchableOpacity, Dimensions, Animated, Image } from 'react-native'
import KeyboardComponent from './KeyboardComponent'
import * as actions from '../store/reducer/sendMoney'
import { openLoginForm, LOGIN_STATUSES } from '../store/reducer/login'
import merge from '../util/merge'
import DefaultText from './DefaultText'
import color from '../util/colors'
import { setOverlayOpen } from '../store/reducer/navigation'
import { dimensions, border } from '../util/StyleUtils'
import commonStyle from './style'
import Price from './Price'

const Page = {
  Ready: 0,
  EnterAmount: 1,
  MakingPayment: 2,
  PaymentComplete: 3,
}

const { width } = Dimensions.get('window')
export const sectionHeight = 68

const styles = {
  button: {
    height: sectionHeight,
    justifyContent: 'center',
    alignItems: 'center',
    flexDirection: 'row',
  },
  textInput: {
    ...dimensions(width, sectionHeight),
    padding: 10,
    textAlign: 'center'
  },
  balanceContainer: {
    ...border(['bottom'], color.gray5, 1),
    backgroundColor: color.offWhite,
    height: 46,
    flexDirection: 'row',
    alignItems: 'center',
  },
  priceContainer: {
    flex: 1,
    right: 14,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: color.transparent,
    justifyContent: 'flex-end'
  }
}

const BalanceMessage = ({ balance }) => {
  return (
    <View style={styles.balanceContainer}>
      <DefaultText style={commonStyle.sectionHeader.text}>CURRENT BALANCE</DefaultText>
      <View style={styles.priceContainer}>
        <Image source={require('./tabbar/assets/balance_symbol.png')}/>
        <Price prefix=''
            price={balance}
            size={30}
            color={color.bristolBlue}/>
      </View>
    </View>
  )
}

class InputComponent extends KeyboardComponent {
  getButtonColor() {
    if (this.props.invalidInput) {
      return color.offWhite
    }
    return color.bristolBlue
  }

  getButtonTextColor() {
    return this.getButtonColor() === color.offWhite ? 'black' : 'white'
  }

  // To fix issue #636
  componentWillReceiveProps(nextProps) {
    if (nextProps.accessibilityLabel === 'Payment complete') {
      this.keyboardDidHide()
    }
  }

  render() {
    let { onButtonPress, buttonText, input, invalidInput, accessibilityLabel, balance } = this.props

    const button = <View style={merge(styles.button, { backgroundColor: this.getButtonColor() })}>
      <DefaultText style={{fontSize: 24, color: this.getButtonTextColor(), textAlign: 'center', width: Dimensions.get('window').width - 20}}>
        {buttonText}
      </DefaultText>
    </View>

    return <Animated.View style={{backgroundColor: 'white', bottom: input ? this.state.keyboardHeight : 0}} accessibilityLabel={accessibilityLabel}>

      {accessibilityLabel === 'Payment complete'
        ? button
        : <TouchableOpacity onPress={invalidInput ? undefined : onButtonPress}>
            {button}
          </TouchableOpacity>}

      {input
        ? <View>
            <TextInput style={styles.textInput}
                {...input}
                autoFocus={true}
                accessibilityLabel={input.placeholder} />
            <BalanceMessage balance={balance}/>
          </View>
        : undefined}

    </Animated.View>
  }
}

class SendMoney extends React.Component {

  constructor() {
    super()
  }

  nextPage() {
    const nextPage = (this.props.inputPage + 1) % Object.keys(Page).length
    this.props.updatePage(nextPage)
    if (nextPage === Page.EnterAmount) {
      this.props.setOverlayOpen(true)
    }
  }

  componentDidUpdate(prevProps) {
    if (this.props.payeeId !== prevProps.payeeId) {
      this.props.updateAmount('')
      this.props.updatePage(Page.Ready)
    } else if (prevProps.loading && !this.props.loading && this.props.inputPage === 2) {
      this.nextPage()
    } else if (prevProps.inputPage === Page.MakingPayment
      && this.props.inputPage === Page.PaymentComplete
      && !this.props.success) {
      setTimeout(() => this.props.inputPage === Page.PaymentComplete && this.nextPage(), 1800)
    }
  }

  isInputInvalid() {
    const { amount } = this.props
    return (
      isNaN(Number(this.props.amount))
        || Number(amount) > this.props.balance
        || Number(amount) <= 0
        || (amount.charAt(0) === '0' && amount.charAt(1) !== '.')
        || amount.charAt(amount.length - 1) === '.'
        || (amount.split('.')[1] && amount.split('.')[1].length > 2)
    )
  }

  render() {
    let inputProps

    if (this.props.connection) {
      if (this.props.inputPage === Page.PaymentComplete) {
        inputProps = {
          buttonText: this.props.message,
          onButtonPress: () => {},
          accessibilityLabel: 'Payment complete'
        }
      } else if (this.props.loggedIn) {
        switch (this.props.inputPage){
          case Page.Ready: // Initial state, ready to begin
            inputProps = {
              buttonText: 'Send Payment',
              onButtonPress: () => { this.nextPage() },
              accessibilityLabel: 'Ready',
            }
            break
          case Page.EnterAmount: // provide amount
            inputProps = {
              buttonText: 'Pay ' + this.props.payee.display,
              onButtonPress: () => { this.props.sendTransaction(); this.nextPage() },
              input: {
                keyboardType: 'numeric',
                value: this.props.amount,
                placeholder: 'Amount',
                onChangeText: amt => this.props.updateAmount(amt),
              },
              invalidInput: this.isInputInvalid(),
              accessibilityLabel: 'Enter Amount',
              balance: this.props.balance
            }
            break
          case Page.MakingPayment: // in progress
            inputProps = {
              buttonText: 'Making Payment',
              loading: true,
              accessibilityLabel: 'Making Payment',
            }
            break
        }
      } else {
        inputProps = {
          buttonText: 'Log in to make payment',
          onButtonPress: () => this.props.openLoginForm(true),
          accessibilityLabel: 'Log in to make payment',
        }
      }
    } else {
      inputProps = {
        buttonText: 'No internet connection',
        accessibilityLabel: 'No internet connection',
      }
    }

    return <InputComponent {...inputProps} />
  }
}

const mapDispatchToProps = (dispatch) =>
  bindActionCreators({ ...actions, openLoginForm, setOverlayOpen }, dispatch)

const mapStateToProps = (state) => ({
  ...state.sendMoney,
  payee: state.business.businessList.find(b => b.id === state.sendMoney.payeeId)
    || state.person.personList.find(p => p.id === state.sendMoney.payeeId)
    || {},
  balance: state.account.balance,
  loggedIn: state.login.loginStatus === LOGIN_STATUSES.LOGGED_IN,
  connection: state.networkConnection.status
})

export default connect(mapStateToProps, mapDispatchToProps)(SendMoney)
<commit_msg>clearing clipboard while making a payment and restoring afterwards<commit_after>import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { View, TextInput, TouchableOpacity, Dimensions, Animated, Image, Clipboard } from 'react-native'
import KeyboardComponent from './KeyboardComponent'
import * as actions from '../store/reducer/sendMoney'
import { openLoginForm, LOGIN_STATUSES } from '../store/reducer/login'
import merge from '../util/merge'
import DefaultText from './DefaultText'
import color from '../util/colors'
import { setOverlayOpen } from '../store/reducer/navigation'
import { dimensions, border } from '../util/StyleUtils'
import commonStyle from './style'
import Price from './Price'

const Page = {
  Ready: 0,
  EnterAmount: 1,
  MakingPayment: 2,
  PaymentComplete: 3,
}

const tempClipboardString = ''
const { width } = Dimensions.get('window')
export const sectionHeight = 68

const styles = {
  button: {
    height: sectionHeight,
    justifyContent: 'center',
    alignItems: 'center',
    flexDirection: 'row',
  },
  textInput: {
    ...dimensions(width, sectionHeight),
    padding: 10,
    textAlign: 'center'
  },
  balanceContainer: {
    ...border(['bottom'], color.gray5, 1),
    backgroundColor: color.offWhite,
    height: 46,
    flexDirection: 'row',
    alignItems: 'center',
  },
  priceContainer: {
    flex: 1,
    right: 14,
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: color.transparent,
    justifyContent: 'flex-end'
  }
}

const BalanceMessage = ({ balance }) => {
  return (
    <View style={styles.balanceContainer}>
      <DefaultText style={commonStyle.sectionHeader.text}>CURRENT BALANCE</DefaultText>
      <View style={styles.priceContainer}>
        <Image source={require('./tabbar/assets/balance_symbol.png')}/>
        <Price prefix=''
            price={balance}
            size={30}
            color={color.bristolBlue}/>
      </View>
    </View>
  )
}

class InputComponent extends KeyboardComponent {
  getButtonColor() {
    if (this.props.invalidInput) {
      return color.offWhite
    }
    return color.bristolBlue
  }

  getButtonTextColor() {
    return this.getButtonColor() === color.offWhite ? 'black' : 'white'
  }

  // To fix issue #636
  componentWillReceiveProps(nextProps) {
    if (nextProps.accessibilityLabel === 'Payment complete') {
      this.keyboardDidHide()
    }
  }

  render() {
    let { onButtonPress, buttonText, input, invalidInput, accessibilityLabel, balance } = this.props

    const button = <View style={merge(styles.button, { backgroundColor: this.getButtonColor() })}>
      <DefaultText style={{fontSize: 24, color: this.getButtonTextColor(), textAlign: 'center', width: Dimensions.get('window').width - 20}}>
        {buttonText}
      </DefaultText>
    </View>

    return <Animated.View style={{backgroundColor: 'white', bottom: input ? this.state.keyboardHeight : 0}} accessibilityLabel={accessibilityLabel}>

      {accessibilityLabel === 'Payment complete'
        ? button
        : <TouchableOpacity onPress={invalidInput ? undefined : onButtonPress}>
            {button}
          </TouchableOpacity>}

      {input
        ? <View>
            <TextInput style={styles.textInput}
                {...input}
                autoFocus={true}
                accessibilityLabel={input.placeholder} />
            <BalanceMessage balance={balance}/>
          </View>
        : undefined}

    </Animated.View>
  }
}

class SendMoney extends React.Component {

  constructor() {
    super()
  }

  setClipboardContent = async () => {
    try {
      tempClipboardString = await Clipboard.getString()
    } catch (e) {
      console.log(e)
    } finally {
      Clipboard.setString('')
    }
  }

  nextPage() {
    const nextPage = (this.props.inputPage + 1) % Object.keys(Page).length
    this.props.updatePage(nextPage)
    if (nextPage === Page.EnterAmount) {
      this.setClipboardContent()
      this.props.setOverlayOpen(true)
    } else if (nextPage === Page.MakingPayment) {
      Clipboard.setString(tempClipboardString)
    }
  }

  componentDidUpdate(prevProps) {
    if (this.props.payeeId !== prevProps.payeeId) {
      this.props.updateAmount('')
      this.props.updatePage(Page.Ready)
    } else if (prevProps.loading && !this.props.loading && this.props.inputPage === 2) {
      this.nextPage()
    } else if (prevProps.inputPage === Page.MakingPayment
      && this.props.inputPage === Page.PaymentComplete
      && !this.props.success) {
      setTimeout(() => this.props.inputPage === Page.PaymentComplete && this.nextPage(), 1800)
    }
  }

  isInputInvalid() {
    const { amount } = this.props
    return (
      isNaN(Number(this.props.amount))
        || Number(amount) > this.props.balance
        || Number(amount) <= 0
        || (amount.charAt(0) === '0' && amount.charAt(1) !== '.')
        || amount.charAt(amount.length - 1) === '.'
        || (amount.split('.')[1] && amount.split('.')[1].length > 2)
    )
  }

  render() {
    let inputProps

    if (this.props.connection) {
      if (this.props.inputPage === Page.PaymentComplete) {
        inputProps = {
          buttonText: this.props.message,
          onButtonPress: () => {},
          accessibilityLabel: 'Payment complete'
        }
      } else if (this.props.loggedIn) {
        switch (this.props.inputPage){
          case Page.Ready: // Initial state, ready to begin
            inputProps = {
              buttonText: 'Send Payment',
              onButtonPress: () => { this.nextPage() },
              accessibilityLabel: 'Ready',
            }
            break
          case Page.EnterAmount: // provide amount
            inputProps = {
              buttonText: 'Pay ' + this.props.payee.display,
              onButtonPress: () => { this.props.sendTransaction(); this.nextPage() },
              input: {
                keyboardType: 'numeric',
                value: this.props.amount,
                placeholder: 'Amount',
                onChangeText: amt => this.props.updateAmount(amt),
              },
              invalidInput: this.isInputInvalid(),
              accessibilityLabel: 'Enter Amount',
              balance: this.props.balance
            }
            break
          case Page.MakingPayment: // in progress
            inputProps = {
              buttonText: 'Making Payment',
              loading: true,
              accessibilityLabel: 'Making Payment',
            }
            break
        }
      } else {
        inputProps = {
          buttonText: 'Log in to make payment',
          onButtonPress: () => this.props.openLoginForm(true),
          accessibilityLabel: 'Log in to make payment',
        }
      }
    } else {
      inputProps = {
        buttonText: 'No internet connection',
        accessibilityLabel: 'No internet connection',
      }
    }

    return <InputComponent {...inputProps} />
  }
}

const mapDispatchToProps = (dispatch) =>
  bindActionCreators({ ...actions, openLoginForm, setOverlayOpen }, dispatch)

const mapStateToProps = (state) => ({
  ...state.sendMoney,
  payee: state.business.businessList.find(b => b.id === state.sendMoney.payeeId)
    || state.person.personList.find(p => p.id === state.sendMoney.payeeId)
    || {},
  balance: state.account.balance,
  loggedIn: state.login.loginStatus === LOGIN_STATUSES.LOGGED_IN,
  connection: state.networkConnection.status
})

export default connect(mapStateToProps, mapDispatchToProps)(SendMoney)
<|endoftext|>


<commit_before>
/*****************************************************************************/
/* ProcurementReport: Event Handlers */
/*****************************************************************************/
Template.ProcurementReport.events({
    'click #getResult': function(e, tmpl) {
        e.preventDefault();
        const startTime = $('[name="startTime"]').val();
        const endTime = $('[name="endTime"]').val();

        if(startTime && endTime) {
            tmpl.$('#getResult').text('Preparing... ');
            tmpl.$('#getResult').attr('disabled', true);
            try {
                let l = Ladda.create(tmpl.$('#getReportForPeriodForDisplay')[0]);
                l.start();
            } catch(e) {
            }
            //--
            let resetButton = function() {
                try {
                    let l = Ladda.create(tmpl.$('#getResult')[0]);
                    l.stop();
                    l.remove();
                } catch(e) {
                }

                tmpl.$('#getResult').text(' View');
                tmpl.$('#getResult').removeAttr('disabled');
            };
            //--
            let startTimeAsDate = tmpl.getDateFromString(startTime)
            let endTimeAsDate = tmpl.getDateFromString(endTime)

            let selectedEmployees = tmpl.selectedEmployees.get()

            Meteor.call('reports/procurement', Session.get('context'),
                startTimeAsDate, endTimeAsDate, selectedEmployees, function(err, res) {
                resetButton()
                if(res){
                    tmpl.procurementReports.set(res)
                } else {
                    swal('No result found', err.reason, 'error');
                }
            });
        }
    },
    'click #excel': function(e, tmpl) {
        e.preventDefault();
        const startTime = $('[name="startTime"]').val();
        const endTime = $('[name="endTime"]').val();

        if(startTime && endTime) {
            tmpl.$('#excel').text('Preparing... ');
            tmpl.$('#excel').attr('disabled', true);
            try {
                let l = Ladda.create(tmpl.$('#excel')[0]);
                l.start();
            } catch(e) {
            }
            //--
            let resetButton = function() {
                try {
                    let l = Ladda.create(tmpl.$('#excel')[0]);
                    l.stop();
                    l.remove();
                } catch(e) {
                }

                tmpl.$('#excel').text('Export');
                $('#excel').prepend("");
                tmpl.$('#excel').removeAttr('disabled');
            };
            //--
            let startTimeAsDate = tmpl.getDateFromString(startTime)
            let endTimeAsDate = tmpl.getDateFromString(endTime)

            let selectedEmployees = tmpl.selectedEmployees.get()

            Meteor.call('reports/procurement', Session.get('context'),
                startTimeAsDate, endTimeAsDate, selectedEmployees, function(err, res) {
                resetButton()
                if(res){
                    tmpl.procurementReports.set(res)
                    tmpl.exportProcurementReportData(res, startTime, endTime)
                } else {
                    swal('No result found', err.reason, 'error');
                }
            });
        }
    },
    'change [name="employee"]': (e, tmpl) => {
        let selected = Core.returnSelection($(e.target));
        tmpl.selectedEmployees.set(selected)
    }
});

/*****************************************************************************/
/* ProcurementReport: Helpers */
/*****************************************************************************/
Template.registerHelper('formatDate', function(date) {
  return moment(date).format('MMYYYY');
});

Template.ProcurementReport.helpers({
    'tenant': function(){
        let tenant = Tenants.findOne();
        return tenant.name;
    },
    'month': function(){
        return Core.months()
    },
    'year': function(){
        return Core.years();
    },
    'employees': () => {
        return Meteor.users.find({"employee": true});
    },
    'procurementReports': function() {
        return Template.instance().procurementReports.get()
    },
    'isLastIndex': function(array, currentIndex) {
        return (currentIndex === (array.length - 1))
    },
    'getSupervisor': function(procurement) {
        return Template.instance().getSupervisor(procurement)
    },
    limitText: function(text) {
        if(text && text.length > 10) {
            return `${text.substring(0, 30)} ...`
        }
        return text
    },
});

/*****************************************************************************/
/* ProcurementReport: Lifecycle Hooks */
/*****************************************************************************/
Template.ProcurementReport.onCreated(function () {
    let self = this;
    // self.subscribe("getPositions", Session.get('context'));

    self.procurementReports = new ReactiveVar()

    self.selectedEmployees = new ReactiveVar()

    self.getDateFromString = function(str1) {
        let theDate = moment(str1);
        return theDate.add('hours', 1).toDate()
    }

    self.getSupervisor = function(procurement) {
        let supervisor = Meteor.users.findOne({
            'employeeProfile.employment.position': procurement.supervisorPositionId
        })
        if(supervisor) {
            return supervisor.profile.fullName || '---'
        }
    }

    self.exportProcurementReportData = function(theData, startTime, endTime) {
        let formattedHeader = ["Description", "Created By", "Unit", "Date required", "Approver", "Status"]

        let reportData = []

        theData.forEach(aDatum => {
            reportData.push([aDatum.description, aDatum.createdByFullName, aDatum.unitName, aDatum.createdAt,
                self.getSupervisor(aDatum), aDatum.status])
        })
        BulkpayExplorer.exportAllData({fields: formattedHeader, data: reportData},
            `Procurement Requisition Report ${startTime} - ${endTime}`);
    }

});

Template.ProcurementReport.onRendered(function () {
    self.$('select.dropdown').dropdown();

    $("html, body").animate({ scrollTop: 0 }, "slow");
});

Template.ProcurementReport.onDestroyed(function () {
});
<commit_msg>Added requisiton reason to procurement report csv download<commit_after>
/*****************************************************************************/
/* ProcurementReport: Event Handlers */
/*****************************************************************************/
Template.ProcurementReport.events({
    'click #getResult': function(e, tmpl) {
        e.preventDefault();
        const startTime = $('[name="startTime"]').val();
        const endTime = $('[name="endTime"]').val();

        if(startTime && endTime) {
            tmpl.$('#getResult').text('Preparing... ');
            tmpl.$('#getResult').attr('disabled', true);
            try {
                let l = Ladda.create(tmpl.$('#getReportForPeriodForDisplay')[0]);
                l.start();
            } catch(e) {
            }
            //--
            let resetButton = function() {
                try {
                    let l = Ladda.create(tmpl.$('#getResult')[0]);
                    l.stop();
                    l.remove();
                } catch(e) {
                }

                tmpl.$('#getResult').text(' View');
                tmpl.$('#getResult').removeAttr('disabled');
            };
            //--
            let startTimeAsDate = tmpl.getDateFromString(startTime)
            let endTimeAsDate = tmpl.getDateFromString(endTime)

            let selectedEmployees = tmpl.selectedEmployees.get()

            Meteor.call('reports/procurement', Session.get('context'),
                startTimeAsDate, endTimeAsDate, selectedEmployees, function(err, res) {
                resetButton()
                if(res){
                    tmpl.procurementReports.set(res)
                } else {
                    swal('No result found', err.reason, 'error');
                }
            });
        }
    },
    'click #excel': function(e, tmpl) {
        e.preventDefault();
        const startTime = $('[name="startTime"]').val();
        const endTime = $('[name="endTime"]').val();

        if(startTime && endTime) {
            tmpl.$('#excel').text('Preparing... ');
            tmpl.$('#excel').attr('disabled', true);
            try {
                let l = Ladda.create(tmpl.$('#excel')[0]);
                l.start();
            } catch(e) {
            }
            //--
            let resetButton = function() {
                try {
                    let l = Ladda.create(tmpl.$('#excel')[0]);
                    l.stop();
                    l.remove();
                } catch(e) {
                }

                tmpl.$('#excel').text('Export');
                $('#excel').prepend("");
                tmpl.$('#excel').removeAttr('disabled');
            };
            //--
            let startTimeAsDate = tmpl.getDateFromString(startTime)
            let endTimeAsDate = tmpl.getDateFromString(endTime)

            let selectedEmployees = tmpl.selectedEmployees.get()

            Meteor.call('reports/procurement', Session.get('context'),
                startTimeAsDate, endTimeAsDate, selectedEmployees, function(err, res) {
                resetButton()
                if(res){
                    tmpl.procurementReports.set(res)
                    tmpl.exportProcurementReportData(res, startTime, endTime)
                } else {
                    swal('No result found', err.reason, 'error');
                }
            });
        }
    },
    'change [name="employee"]': (e, tmpl) => {
        let selected = Core.returnSelection($(e.target));
        tmpl.selectedEmployees.set(selected)
    }
});

/*****************************************************************************/
/* ProcurementReport: Helpers */
/*****************************************************************************/
Template.registerHelper('formatDate', function(date) {
  return moment(date).format('MMYYYY');
});

Template.ProcurementReport.helpers({
    'tenant': function(){
        let tenant = Tenants.findOne();
        return tenant.name;
    },
    'month': function(){
        return Core.months()
    },
    'year': function(){
        return Core.years();
    },
    'employees': () => {
        return Meteor.users.find({"employee": true});
    },
    'procurementReports': function() {
        return Template.instance().procurementReports.get()
    },
    'isLastIndex': function(array, currentIndex) {
        return (currentIndex === (array.length - 1))
    },
    'getSupervisor': function(procurement) {
        return Template.instance().getSupervisor(procurement)
    },
    limitText: function(text) {
        if(text && text.length > 10) {
            return `${text.substring(0, 30)} ...`
        }
        return text
    },
});

/*****************************************************************************/
/* ProcurementReport: Lifecycle Hooks */
/*****************************************************************************/
Template.ProcurementReport.onCreated(function () {
    let self = this;
    // self.subscribe("getPositions", Session.get('context'));

    self.procurementReports = new ReactiveVar()

    self.selectedEmployees = new ReactiveVar()

    self.getDateFromString = function(str1) {
        let theDate = moment(str1);
        return theDate.add('hours', 1).toDate()
    }

    self.getSupervisor = function(procurement) {
        let supervisor = Meteor.users.findOne({
            'employeeProfile.employment.position': procurement.supervisorPositionId
        })
        if(supervisor) {
            return supervisor.profile.fullName || '---'
        }
    }

    self.exportProcurementReportData = function(theData, startTime, endTime) {
        let formattedHeader = ["Description", "Requisition reason", "Created By", "Unit", "Date required", "Approver", "Status"]

        let reportData = []

        theData.forEach(aDatum => {
            reportData.push([aDatum.description, aDatum.requisitionReason, aDatum.createdByFullName, aDatum.unitName, aDatum.createdAt,
                self.getSupervisor(aDatum), aDatum.status])
        })
        BulkpayExplorer.exportAllData({fields: formattedHeader, data: reportData},
            `Procurement Requisition Report ${startTime} - ${endTime}`);
    }

});

Template.ProcurementReport.onRendered(function () {
    self.$('select.dropdown').dropdown();

    $("html, body").animate({ scrollTop: 0 }, "slow");
});

Template.ProcurementReport.onDestroyed(function () {
});
<|endoftext|>