<commit_before>
/**********************
* Domain general code *
**********************/

// Helper functions

// Assert functions stolen from
// http://aymanh.com/9-javascript-tips-you-may-not-know#assertion
function AssertException(message) { this.message = message; }
AssertException.prototype.toString = function () {
	return 'AssertException: ' + this.message;
};

function assert(exp, message) {
	if (!exp) {
	  throw new AssertException(message);
	}
}

function insert_hidden_into_form(findex, name, value ) {
    var form = document.forms[findex];
    var hiddenField = document.createElement('input');
    hiddenField.setAttribute('type', 'hidden');
    hiddenField.setAttribute('name', name);
    hiddenField.setAttribute('value', value );
    form.appendChild( hiddenField );
}

// Preload images (not currently in use)
function imagepreload(src)
{
	var heavyImage = new Image();
	heavyImage.src = src;
}

/**
 * SUBSTITUTE PLACEHOLDERS WITH string values
 * @param {String} str The string containing the placeholders
 * @param {Array} arr The array of values to substitute
 * From Fotiman on this forum:
 * http://www.webmasterworld.com/javascript/3484761.htm
 */
function substitute(str, arr)
{
	var i, pattern, re, n = arr.length;
	for (i = 0; i < n; i++) {
		pattern = "\\{" + i + "\\}";
		re = new RegExp(pattern, "g");
		str = str.replace(re, arr[i]);
	}
	return str;
}

function randrange ( lower, upperbound ) {
	// Finds a random integer from 'lower' to 'upperbound-1'
	return Math.floor( Math.random() * upperbound + lower );
}

// We want to be able to alias the order of stimuli to a single number which
// can be stored and which can easily replicate a given stimulus order.
function changeorder( arr, ordernum ) {
	var thisorder = ordernum;
	var shufflelocations = new Array();
	for (var i=0; i<arr.length; i++) {
		shufflelocations.push(i);
	}
	for (i=arr.length-1; i>=0; --i) {
		var loci = shufflelocations[i];
		var locj = shufflelocations[thisorder%(i+1)];
		thisorder = Math.floor(thisorder/(i+1));
		var tempi = arr[loci];
		var tempj = arr[locj];
		arr[loci] = tempj;
		arr[locj] = tempi;
	}
	return arr;
}

// Fisher-Yates shuffle algorithm.
// modified from http://sedition.com/perl/javascript-fy.html
function shuffle( arr, exceptions ) {
	var i;
	exceptions = exceptions || [];
	var shufflelocations = new Array();
	for (i=0; i<arr.length; i++) {
		if (exceptions.indexOf(i)==-1) { shufflelocations.push(i); }
	}
	for (i=shufflelocations.length-1; i>=0; --i) {
		var loci = shufflelocations[i];
		var locj = shufflelocations[randrange(0, i+1)];
		var tempi = arr[loci];
		var tempj = arr[locj];
		arr[loci] = tempj;
		arr[locj] = tempi;
	}
	return arr;
}

// This function swaps two array members at random, provided they are not in
// the exceptions list.
function swap( arr, exceptions ) {
	var i;
	var except = exceptions ? exceptions : [];
	var shufflelocations = new Array();
    for (i=0; i<arr.length; i++) {
        if (except.indexOf(i)==-1) { shufflelocations.push(i); }
    }

    for (i=shufflelocations.length-1; i>=0; --i) {
        var loci = shufflelocations[i];
        var locj = shufflelocations[randrange(0,i+1)];
        var tempi = arr[loci];
        var tempj = arr[locj];
    	arr[loci] = tempj;
    	arr[locj] = tempi;
    }

	return arr;
}

// Mean of booleans (true==1; false==0)
function boolpercent(arr) {
	var count = 0;
	for (var i=0; i<arr.length; i++) {
		if (arr[i]) { count++; }
	}
	return 100* count / arr.length;
}

// View functions
function appendtobody( tag, id, contents ) {
	var el = document.createElement( tag );
	el.id = id;
	el.innerHTML = contents;
	return el;
}

// Data submission
// NOTE: Ended up not using this.
function posterror() { alert( "There was an error. TODO: Prompt to resubmit here." ); }
function submitdata() {
	$.ajax("submit", {
			type: "POST",
			async: false,
			data: {datastring: datastring},
			// dataType: 'text',
			success: thanks,
			error: posterror
	});
}

/********************
* TASK-GENERAL CODE *
********************/

// Globals defined initially.
var maxblocks = 2;
var keydownfun = function() {};

// Stimulus info
var ncards = 8,
    cardnames = [
	"static/images/STIM00.PNG",
	"static/images/STIM01.PNG",
	"static/images/STIM02.PNG",
	"static/images/STIM03.PNG",
	"static/images/STIM04.PNG",
	"static/images/STIM05.PNG",
	"static/images/STIM06.PNG",
	"static/images/STIM07.PNG",
	"static/images/STIM08.PNG",
	"static/images/STIM09.PNG",
	"static/images/STIM10.PNG",
	"static/images/STIM11.PNG",
	"static/images/STIM12.PNG",
	"static/images/STIM13.PNG",
	"static/images/STIM14.PNG",
	"static/images/STIM15.PNG"],
	categorynames= [ "A", "B" ];

// Interface variables
var cardh = 180, cardw = 140, upper = 0, left = 0, imgh = 100, imgw = 100;

// Task objects
var testobject;

// Mutable global variables
var responsedata = [],
    currenttrial = 1,
    datastring = "",
    lastperfect = false;

// Data handling functions
function recordinstructtrial (instructname, rt ) {
	trialvals = [assignmentId, "INSTRUCT", instructname, rt];
	datastring = datastring.concat( trialvals, "\n" );
}
function recordtesttrial (word, color, trialtype, resp, hit, rt ) {
	trialvals = [assignmentId, currenttrial,  "TEST", word, color, hit, resp, hit, rt];
	datastring = datastring.concat( trialvals, "\n" );
	currenttrial++;
}

/********************
* HTML snippets
********************/
var pages = {};

var showpage = function(pagename) {
	$('body').html( pages[pagename] );
};

var pagenames = [
	"postquestionnaire",
	"test",
	"instruct"
];

/************************
* CODE FOR INSTRUCTIONS *
************************/
var Instructions = function( screens ) {
	var that = this,
		currentscreen = "",
		timestamp;
	for( i=0; i<screens.length; i++) {
		pagename = screens[i];
		$.ajax({
			url: pagename + ".html",
			success: function(pagename){ return function(page){ pages[pagename] = page; }; }(pagename),
			async: false
		});
	}

	this.recordtrial = function() {
		rt = (new Date().getTime()) - timestamp;
		recordinstructtrial( currentscreen, rt  );
	};

	this.nextForm = function () {
		var next = screens.splice(0, 1)[0];
		currentscreen = next;
		showpage( next );
		timestamp = new Date().getTime();
		if ( screens.length === 0 ) $('.continue').click(function() {
			that.recordtrial();
			that.startTest();
		});
		else $('.continue').click( function() {
			that.recordtrial();
			that.nextForm();
		});
	};
	this.startTest = function() {
		// startTask();
		testobject = new TestPhase();
	};
	this.nextForm();
};

/********************
* CODE FOR TEST     *
********************/

var TestPhase = function() {
	var i,
	    that = this, // make 'this' accessble by privileged methods
	    lock,
	    stimimage,
	    buttonson,
	    prescard,
	    testcardsleft = new Array();

	this.hits = new Array();

	var acknowledgment = '
Thanks for your response!
';
	var textprompt = '
Type
 "R" for Red
"B" for blue
"G" for green.';
	showpage( 'test' );

	var addprompt = function() {
		buttonson = new Date().getTime();
		$('#query').html( textprompt ).show();
	};

	var finishblock = function() {
		keydownfun = function() {}; // Should unbind keys.
		givequestionnaire();
	};

	var nextword = function () {
		if (! stims.length) {
			finishblock();
		}
		else {
			stim = stims.pop();
			show_word( stim[0], stim[1] );
			wordon = new Date().getTime();
			//stimimage = testcardpaper.image( cardnames[getstim(prescard)], 0, 0, imgw, imgh);
			responsefun = function( keyCode ) {
				var response;
				switch (keyCode) {
				case 82:
					// "R"
					response="red";
					break;
				case 71:
					// "G"
					response="green";
					break;
				case 66:
					// "B"
					response="blue";
					break;
				default:
					response = "";
					break;
				}
				if ( response.length>0 ) {
					responsefun = function() {};
					var hit = response == stim[1];
					var rt = new Date().getTime() - wordon;
					recordtesttrial (stim[0], stim[1], stim[2], response, hit, rt );
					remove_word();
					nextword();
				}
			};
			addprompt();
		}
	};

	//Set up stimulus.
	var R = Raphael("stim", 400, 100),
		font = "64px Helvetica";

	var show_word = function(text, color) {
		R.text( 200, 50, text ).attr({font: font, fill: color});
	};
	var remove_word = function(text, color) {
		R.clear();
	};
	$("body").focus().keydown(function(e){keydownfun(e);});
    keydownfun = function(event) {
        responsefun( event.keyCode );
    };
	//testcardpaper = Raphael(document.getElementById("testcanvas"), w, h);
	// TODO: expand out to 50
	var stims = [
		["SHIP", "red", "unrelated"],
		["MONKEY", "green", "unrelated"],
		["ZAMBONI", "blue", "unrelated"],
		["RED", "red", "congruent"],
		["GREEN", "green", "congruent"],
		["BLUE", "blue", "congruent"],
		["GREEN", "red", "incongruent"],
		["BLUE", "green", "incongruent"],
		["RED", "blue", "incongruent"]
		];
	shuffle( stims );
	nextword();
	return this;
};

/*************
* Finish up  *
*************/
var givequestionnaire = function() {
	var timestamp = new Date().getTime();
	showpage('postquestionnaire');
	recordinstructtrial( "postquestionnaire", (new Date().getTime())-timestamp );
	$("#continue").click(function () {
		finish();
		submitquestionnaire();
	});
	// $('#continue').click( function(){ trainobject = new TrainingPhase(); } );
	// postback();
};
var submitquestionnaire = function() {
	$('textarea').each( function(i, val) {
		datastring = datastring.concat( "\n", this.id, ":",  this.value);
	});
	$('select').each( function(i, val) {
		datastring = datastring.concat( "\n", this.id, ":",  this.value);
	});
	insert_hidden_into_form(0, "assignmentid", assignmentId );
	insert_hidden_into_form(0, "data", datastring );
	$('form').submit();
};

var startTask = function () {
	// Provide opt-out
	window.onbeforeunload = function(){
    	$.ajax("quitter", {
    			type: "POST",
    			async: false,
    			data: {assignmentId: assignmentId, dataString: datastring}
    	});
		alert( "By leaving this page, you opt out of the experiment.  You are forfitting your $1.00 payment and your 1/10 chance to with $10. Please confirm that this is what you meant to do." );
		return "Are you sure you want to leave the experiment?";
	};
};

var finish = function () {
	window.onbeforeunload = function(){ };
};

// vi: et! ts=4 sw=4
<commit_msg>Cleaned up javascript code, including the key listener.<commit_after>
/**********************
* Domain general code *
**********************/

// Helper functions

// Assert functions stolen from
// http://aymanh.com/9-javascript-tips-you-may-not-know#assertion
function AssertException(message) { this.message = message; }
AssertException.prototype.toString = function () {
	return 'AssertException: ' + this.message;
};

function assert(exp, message) {
	if (!exp) {
		throw new AssertException(message);
	}
}

function insert_hidden_into_form(findex, name, value ) {
	var form = document.forms[findex];
	var hiddenField = document.createElement('input');
	hiddenField.setAttribute('type', 'hidden');
	hiddenField.setAttribute('name', name);
	hiddenField.setAttribute('value', value );
	form.appendChild( hiddenField );
}

// Preload images (not currently in use)
function imagepreload(src)
{
	var heavyImage = new Image();
	heavyImage.src = src;
}

/**
 * SUBSTITUTE PLACEHOLDERS WITH string values
 * @param {String} str The string containing the placeholders
 * @param {Array} arr The array of values to substitute
 * From Fotiman on this forum:
 * http://www.webmasterworld.com/javascript/3484761.htm
 */
function substitute(str, arr)
{
	var i, pattern, re, n = arr.length;
	for (i = 0; i < n; i++) {
		pattern = "\\{" + i + "\\}";
		re = new RegExp(pattern, "g");
		str = str.replace(re, arr[i]);
	}
	return str;
}

function randrange ( lower, upperbound ) {
	// Finds a random integer from 'lower' to 'upperbound-1'
	return Math.floor( Math.random() * upperbound + lower );
}

// We want to be able to alias the order of stimuli to a single number which
// can be stored and which can easily replicate a given stimulus order.
function changeorder( arr, ordernum ) {
	var thisorder = ordernum;
	var shufflelocations = new Array();
	for (var i=0; i<arr.length; i++) {
		shufflelocations.push(i);
	}
	for (i=arr.length-1; i>=0; --i) {
		var loci = shufflelocations[i];
		var locj = shufflelocations[thisorder%(i+1)];
		thisorder = Math.floor(thisorder/(i+1));
		var tempi = arr[loci];
		var tempj = arr[locj];
		arr[loci] = tempj;
		arr[locj] = tempi;
	}
	return arr;
}

// Fisher-Yates shuffle algorithm.
// modified from http://sedition.com/perl/javascript-fy.html
function shuffle( arr, exceptions ) {
	var i;
	exceptions = exceptions || [];
	var shufflelocations = new Array();
	for (i=0; i<arr.length; i++) {
		if (exceptions.indexOf(i)==-1) { shufflelocations.push(i); }
	}
	for (i=shufflelocations.length-1; i>=0; --i) {
		var loci = shufflelocations[i];
		var locj = shufflelocations[randrange(0, i+1)];
		var tempi = arr[loci];
		var tempj = arr[locj];
		arr[loci] = tempj;
		arr[locj] = tempi;
	}
	return arr;
}

// This function swaps two array members at random, provided they are not in
// the exceptions list.
function swap( arr, exceptions ) {
	var i;
	var except = exceptions ? exceptions : [];
	var shufflelocations = new Array();
	for (i=0; i<arr.length; i++) {
		if (except.indexOf(i)==-1) shufflelocations.push(i);
	}

	for (i=shufflelocations.length-1; i>=0; --i) {
		var loci = shufflelocations[i];
		var locj = shufflelocations[randrange(0,i+1)];
		var tempi = arr[loci];
		var tempj = arr[locj];
		arr[loci] = tempj;
		arr[locj] = tempi;
	}
	return arr;
}

// Mean of booleans (true==1; false==0)
function boolpercent(arr) {
	var count = 0;
	for (var i=0; i<arr.length; i++) {
		if (arr[i]) { count++; }
	}
	return 100* count / arr.length;
}

// View functions
function appendtobody( tag, id, contents ) {
	var el = document.createElement( tag );
	el.id = id;
	el.innerHTML = contents;
	return el;
}

// Data submission
// NOTE: Ended up not using this.
function posterror() { alert( "There was an error. TODO: Prompt to resubmit here." ); }
function submitdata() {
	$.ajax("submit", {
			type: "POST",
			async: false,
			data: {datastring: datastring},
			// dataType: 'text',
			success: thanks,
			error: posterror
	});
}

/********************
* TASK-GENERAL CODE *
********************/

// Globals defined initially.
var maxblocks = 2;
var keydownfun = function() {};

// Stimulus info
var ncards = 8,
    cardnames = [
	"static/images/STIM00.PNG",
	"static/images/STIM01.PNG",
	"static/images/STIM02.PNG",
	"static/images/STIM03.PNG",
	"static/images/STIM04.PNG",
	"static/images/STIM05.PNG",
	"static/images/STIM06.PNG",
	"static/images/STIM07.PNG",
	"static/images/STIM08.PNG",
	"static/images/STIM09.PNG",
	"static/images/STIM10.PNG",
	"static/images/STIM11.PNG",
	"static/images/STIM12.PNG",
	"static/images/STIM13.PNG",
	"static/images/STIM14.PNG",
	"static/images/STIM15.PNG"],
	categorynames= [ "A", "B" ];

// Interface variables
var cardh = 180, cardw = 140, upper = 0, left = 0, imgh = 100, imgw = 100;

// Task objects
var testobject;

// Mutable global variables
var responsedata = [],
    currenttrial = 1,
    datastring = "",
    lastperfect = false;

// Data handling functions
function recordinstructtrial (instructname, rt ) {
	trialvals = [assignmentId, "INSTRUCT", instructname, rt];
	datastring = datastring.concat( trialvals, "\n" );
}
function recordtesttrial (word, color, trialtype, resp, hit, rt ) {
	trialvals = [assignmentId, currenttrial,  "TEST", word, color, hit, resp, hit, rt];
	datastring = datastring.concat( trialvals, "\n" );
	currenttrial++;
}

/********************
* HTML snippets
********************/
var pages = {};

var showpage = function(pagename) {
	$('body').html( pages[pagename] );
};

var pagenames = [
	"postquestionnaire",
	"test",
	"instruct"
];

/************************
* CODE FOR INSTRUCTIONS *
************************/
var Instructions = function( screens ) {
	var that = this,
		currentscreen = "",
		timestamp;
	for( i=0; i<screens.length; i++) {
		pagename = screens[i];
		$.ajax({
			url: pagename + ".html",
			success: function(pagename){ return function(page){ pages[pagename] = page; }; }(pagename),
			async: false
		});
	}

	this.recordtrial = function() {
		rt = (new Date().getTime()) - timestamp;
		recordinstructtrial( currentscreen, rt  );
	};

	this.nextForm = function () {
		var next = screens.splice(0, 1)[0];
		currentscreen = next;
		showpage( next );
		timestamp = new Date().getTime();
		if ( screens.length === 0 ) $('.continue').click(function() {
			that.recordtrial();
			that.startTest();
		});
		else $('.continue').click( function() {
			that.recordtrial();
			that.nextForm();
		});
	};
	this.startTest = function() {
		// startTask();
		testobject = new TestPhase();
	};
	this.nextForm();
};

/********************
* CODE FOR TEST     *
********************/

var TestPhase = function() {
	var i,
	    that = this, // make 'this' accessble by privileged methods
	    lock,
	    stimimage,
	    buttonson,
	    prescard,
	    testcardsleft = new Array();

	this.hits = new Array();

	var acknowledgment = '
Thanks for your response!
';
	var textprompt = '
Type
 "R" for Red
"B" for blue
"G" for green.';
	showpage( 'test' );

	var addprompt = function() {
		buttonson = new Date().getTime();
		$('#query').html( textprompt ).show();
	};

	var finishblock = function() {
		keydownfun = function() {}; // Should unbind keys.
		givequestionnaire();
	};

	var responsefun = function( e) {
		if (!listening) return;
			keyCode = e.keyCode;
		var response;
		switch (keyCode) {
			case 82:
				// "R"
				response="red";
				break;
			case 71:
				// "G"
				response="green";
				break;
			case 66:
				// "B"
				response="blue";
				break;
			default:
				response = "";
				break;
		}
		if ( response.length>0 ) {
			listening = false;
			responsefun = function() {};
			var hit = response == stim[1];
			var rt = new Date().getTime() - wordon;
			recordtesttrial (stim[0], stim[1], stim[2], response, hit, rt );
			remove_word();
			nextword();
		}
	};

	var nextword = function () {
		if (! stims.length) {
			finishblock();
		}
		else {
			stim = stims.pop();
			show_word( stim[0], stim[1] );
			wordon = new Date().getTime();
			//stimimage = testcardpaper.image( cardnames[getstim(prescard)], 0, 0, imgw, imgh);

			addprompt();
                        listening = true;
		}
	};

	//Set up stimulus.
	var R = Raphael("stim", 400, 100),
		font = "64px Helvetica";

	var show_word = function(text, color) {
		R.text( 200, 50, text ).attr({font: font, fill: color});
	};
	var remove_word = function(text, color) {
		R.clear();
	};
	$("body").focus().keydown(responsefun);
        listening = false;

	var stims = [
		["SHIP", "red", "unrelated"],
		["MONKEY", "green", "unrelated"],
		["ZAMBONI", "blue", "unrelated"],
		["RED", "red", "congruent"],
		["GREEN", "green", "congruent"],
		["BLUE", "blue", "congruent"],
		["GREEN", "red", "incongruent"],
		["BLUE", "green", "incongruent"],
		["RED", "blue", "incongruent"]
		];
	shuffle( stims );
	nextword();
	return this;
};

/*************
* Finish up  *
*************/
var givequestionnaire = function() {
	var timestamp = new Date().getTime();
	showpage('postquestionnaire');
	recordinstructtrial( "postquestionnaire", (new Date().getTime())-timestamp );
	$("#continue").click(function () {
		finish();
		submitquestionnaire();
	});
	// $('#continue').click( function(){ trainobject = new TrainingPhase(); } );
	// postback();
};
var submitquestionnaire = function() {
	$('textarea').each( function(i, val) {
		datastring = datastring.concat( "\n", this.id, ":",  this.value);
	});
	$('select').each( function(i, val) {
		datastring = datastring.concat( "\n", this.id, ":",  this.value);
	});
	insert_hidden_into_form(0, "assignmentid", assignmentId );
	insert_hidden_into_form(0, "data", datastring );
	$('form').submit();
};

var startTask = function () {
	// Provide opt-out
	window.onbeforeunload = function(){
		$.ajax("quitter", {
				type: "POST",
				async: false,
				data: {assignmentId: assignmentId, dataString: datastring}
		});
		alert( "By leaving this page, you opt out of the experiment.  You are forfitting your $1.00 payment and your 1/10 chance to with $10. Please confirm that this is what you meant to do." );
		return "Are you sure you want to leave the experiment?";
	};
};

var finish = function () {
	window.onbeforeunload = function(){ };
};

// vi: et! ts=4 sw=4
<|endoftext|>


<commit_before>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeaderEditUser = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserEditTitle");}, gvm);

    gvm.edituserid = $("#usereditHeader").data('value');

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userStatus = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserStatus");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);

    gvm.rights = ko.observableArray([]);
    gvm.allRights = ko.observableArray([]);
    gvm.user = ko.observableArray([]);

    gvm.updateUser = function(user)
    {
        gvm.user.push(user);
    },

    gvm.updatePermissions = function(permission)
    {
        gvm.rights.push(permission);
    },

    gvm.updateAllPermissions = function(permission)
    {
        gvm.allRights.push(permission);
    },

    gvm.removeUser = function(user) {
        gvm.user.remove(user);
        removeUser(user);
    },

    gvm.clearStructure = function() {
        gvm.rights.destroyAll();
        gvm.user.destroyAll();
    }
}

function initPage() {
    getAllUserDataById(viewModel.edituserid);
    setRights();
    checkPermissions();
}

function setRights(){
    viewModel.updateAllPermissions("GUEST");
    viewModel.updateAllPermissions("STUDENT");
    viewModel.updateAllPermissions("USER");
    viewModel.updateAllPermissions("SUPERUSER");
}

function getAllUserDataById(edituserid){
    console.log("Get data from user with id " + edituserid);
    $.getJSON("/api/edituser/" + edituserid, function(data)
    {
        var addedUsername = "";
        $.each(data, function(i, item){
            var current = item.username;

            $.each(data, function(i, item)
            {
                if(item.username == current && addedUsername != current){
                    console.log(current + " " + item.roleid + " " + item.role );
                    viewModel.updatePermissions(new Permission(item.roleid, item.role))
                }
            });

            if (addedUsername != current){
                addedUsername = current;
                console.log("Added: " + addedUsername);
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, item.status, viewModel.rights()));
            }
        });
    });
}

function checkPermissions(){

    $.each(viewModel.allRights(), function(i, item){
        $.each(viewModel.rights, function(i, item){
            console.log(i + " " + item);
            console.log("rights");

        });
    });
}

function Permission(id, permissions) {
    return {
        id: ko.observable(id),
        permission: ko.observable(permissions)
    };
}

function User(id, username, firstname, lastname, status, permissions) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        status: ko.observable(status),
        permissions: ko.observableArray(permissions),

        removeThisUser: function() {
            if(confirm('Are you sure you want to remove this user?'))
            {
                viewModel.removeUser(this);
            }
        },

        changeStatus: function() {
            if (this.status() == "ACTIVE"){
                this.status("DISABLED");
            } else if (this.status() == "DISABLED") {
                this.status("ACTIVE");
            } else {
                this.status("WAIT_ACTIVATION");
            }
            updateUserStatus(this);
        }
    };
}<commit_msg>Admin edit user<commit_after>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminPage");}, gvm);
    gvm.pageHeaderEditUser = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserEditTitle");}, gvm);

    gvm.edituserid = $("#usereditHeader").data('value');

    gvm.userName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserName");}, gvm);
    gvm.firstName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Firstname");}, gvm);
    gvm.lastName = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("Lastname");}, gvm);
    gvm.userStatus = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserStatus");}, gvm);

    gvm.permissionRole = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionRole");}, gvm);
    gvm.permissionDescription = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("PermissionDescription");}, gvm);

    gvm.rights = ko.observableArray([]);
    gvm.allRights = ko.observableArray([]);
    gvm.user = ko.observableArray([]);

    gvm.updateUser = function(user)
    {
        gvm.user.push(user);
    },

    gvm.updatePermissions = function(permission)
    {
        gvm.rights.push(permission);
    },

    gvm.updateAllPermissions = function(permission)
    {
        gvm.allRights.push(permission);
    },

    gvm.removeUser = function(user) {
        gvm.user.remove(user);
        removeUser(user);
    },

    gvm.clearStructure = function() {
        gvm.rights.destroyAll();
        gvm.user.destroyAll();
    }
}

function initPage() {
    getAllUserDataById(viewModel.edituserid);
    setRights();
    checkPermissions();
}

function setRights(){
    viewModel.updateAllPermissions("GUEST");
    viewModel.updateAllPermissions("STUDENT");
    viewModel.updateAllPermissions("USER");
    viewModel.updateAllPermissions("SUPERUSER");
}

function getAllUserDataById(edituserid){
    console.log("Get data from user with id " + edituserid);
    $.getJSON("/api/edituser/" + edituserid, function(data)
    {
        var addedUsername = "";
        $.each(data, function(i, item){
            var current = item.username;

            $.each(data, function(i, item)
            {
                if(item.username == current && addedUsername != current){
                    console.log(current + " " + item.roleid + " " + item.role );
                    viewModel.updatePermissions(new Permission(item.roleid, item.role))
                }
            });

            if (addedUsername != current){
                addedUsername = current;
                console.log("Added: " + addedUsername);
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, item.status, viewModel.rights()));
            }
        });
    });
}

function checkPermissions(){

    $.each(viewModel.allRights(), function(i, item){
        $.each(viewModel.rights, function(i, item){
            console.log(i + " " + item.permission);
            console.log("rights");

        });
    });
}

function Permission(id, permissions) {
    return {
        id: ko.observable(id),
        permission: ko.observable(permissions)
    };
}

function User(id, username, firstname, lastname, status, permissions) {
    return {
        id: ko.observable(id),
        username: ko.observable(username),
        firstname: ko.observable(firstname),
        lastname: ko.observable(lastname),
        status: ko.observable(status),
        permissions: ko.observableArray(permissions),

        removeThisUser: function() {
            if(confirm('Are you sure you want to remove this user?'))
            {
                viewModel.removeUser(this);
            }
        },

        changeStatus: function() {
            if (this.status() == "ACTIVE"){
                this.status("DISABLED");
            } else if (this.status() == "DISABLED") {
                this.status("ACTIVE");
            } else {
                this.status("WAIT_ACTIVATION");
            }
            updateUserStatus(this);
        }
    };
}<|endoftext|>


<commit_before>var sessionID = /sessionid=(.{24})/.exec(document.cookie)[1];

$(document).ready(function() {

  // Detect if Script is active
  /////////////////////////////
  chrome.runtime.sendMessage({greeting: 'getDiscoveryQueueStatus'}, function(stopme){
    if(document.location.href == "https://store.steampowered.com/login/?redir=explore%2F") {
      // Click first entry until none is left
      setTimeout(function(){
        if (stopme == 1) {
          if ($('.names').length > 0) {
            $('.names:eq(0)').click();
          } else {
            // When finished reset queue-status
            chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
          }
        }
      }, 1500);
    } else if (document.location.href == "http://store.steampowered.com/explore/") {
      if (stopme == 1) {

        var cards_dropped = jQuery('.discovery_queue_winter_sale_cards_header h3').text().replace(/\D/g,'');

        function discQueue(){

          if (cards_dropped == '') {

            var GenerateQueue = function(queueNumber) {
            console.log('Queue #' + ++queueNumber);

            jQuery.post('http://store.steampowered.com/explore/generatenewdiscoveryqueue', {
              sessionid: sessionID,
              queuetype: 0
            }).done(function(data) {
              var requests = [];

              for (var i = 0; i < data.queue.length; i++) {
                requests.push(jQuery.post('http://store.steampowered.com/app/10', {
                  appid_to_clear_from_queue: data.queue[i],
                  sessionid: sessionID
                }));
              }

              jQuery.when.apply(jQuery, requests).done(function() {
                if (queueNumber < 3) {
                  GenerateQueue(queueNumber);
                } else {
                  location.reload();
                }
              });
            }).fail(function() {
              setTimeout(function() {
                GenerateQueue(0);
              }, 1000);
            });
            };
            setTimeout(function() {
            GenerateQueue(0);
            }, 1000);

            setTimeout(function() {
            location.reload();
            }, 10000);

          } else if(typeof cards_dropped == 'undefined'){
            chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
            alert('There was an error getting the left card-drops. Deactivating Discovery-Queue now!');
          } else if(cards_dropped >= 2){
            var user = $('#account_pulldown').text();
            chrome.runtime.sendMessage({
              greeting: 'setSkipForLogin',
              user: user
            }, function(response) {
              if (response == 1) {
                jQuery.post('https://store.steampowered.com/logout/', {
                  sessionid: sessionID
                });

                setTimeout(function(){
                  location.reload();
                }, 1000);
              }
            });
          }

        }

        // Execute
        discQueue();

      }

    } else if (document.location.href == "http://store.steampowered.com/") {
      if (stopme == 1) {
        document.location = "https://store.steampowered.com/login/?redir=explore%2F";
      }
    }
  });
});

// Awards
/*var cards_left = jQuery('.discovery_queue_winter_sale_cards_header .subtext').text().replace(/\D/g, '');
var cards_text = jQuery('.discovery_queue_winter_sale_cards_header .subtext').text();
var cards_text_compare = "Sie können heute noch eine weitere Karte erhalten, indem Sie Ihre Entdeckungsliste erkunden.";
               jQuery('.discovery_queue_winter_sale_cards_header h3').text().replace(/\D/g,'');
jQuery.ajax({
  url: 'http://store.steampowered.com/SteamAwards/',
  success: function(res){
    var awards = jQuery(res).find('.steamaward_castvote_writein');
    var arr = [];

  (function next(counter, maxLoops) {

    // all votes should be send now
    if(counter++ >= maxLoops){
      console.log("Voted! Iterating over Discovery-Queue now.");
      discQueue();
      return;
    }

    var scnt = 0;
    function processAjax(){
      scnt++;
      if(scnt <= 5){

        voteid = jQuery(awards[counter-1]).find('.vote_nominations').data('voteid');
        jQuery(awards[counter-1]).find('.vote_nomination').map(function(){
          arr.push(jQuery(this).data('vote-appid'));
        });

        jQuery.ajax({
          url: 'http://store.steampowered.com/salevote',
          type: 'POST',
          data: {
            sessionid: sessionID,
            voteid: voteid,
            appid: arr[Math.floor(Math.random()*arr.length)]
          },
          success: function(response){
            console.log(response);
            scnt = 0; arr = [];
            setTimeout(function(){ next(counter, maxLoops) }, 300);
          },
          error: function(xhr, textStatus, errorThrown){
            if(xhr.status == 403){
              setTimeout(function(){ next(counter, maxLoops) }, 300);
            } else {
              // probably some timeout - try again
              setTimeout(function(){ processAjax(); }, 3000);
            }
          }
        });

      } else {
        // to much retries
        scnt = 0;
        setTimeout(function(){ next(counter, maxLoops) }, 300);
      }
    }

    // Autostart on first iteration
    if(scnt <= 1) processAjax();

  })(0, awards.length);

  }
});

function discQueue(){

  if ((cards_left > 0 && cards_left !== '') || (cards_text == cards_text_compare)) {

    var GenerateQueue = function(queueNumber) {
    console.log('Queue #' + ++queueNumber);

    jQuery.post('http://store.steampowered.com/explore/generatenewdiscoveryqueue', {
      sessionid: sessionID,
      queuetype: 0
    }).done(function(data) {
      var requests = [];

      for (var i = 0; i < data.queue.length; i++) {
        requests.push(jQuery.post('http://store.steampowered.com/app/10', {
          appid_to_clear_from_queue: data.queue[i],
          sessionid: sessionID
        }));
      }

      jQuery.when.apply(jQuery, requests).done(function() {
        if (queueNumber < 3) {
          GenerateQueue(queueNumber);
        } else {
          location.reload();
        }
      });
    }).fail(function() {
      setTimeout(function() {
        GenerateQueue(0);
      }, 1000);
    });
    };
    setTimeout(function() {
    GenerateQueue(0);
    }, 1000);

    setTimeout(function() {
    location.reload();
    }, 10000);

  } else if(typeof cards_left == 'undefined'){
    chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
    alert('There was an error getting the left card-drops. Deactivating Discovery-Queue now!');
  } else if(cards_left == ''){
    var user = $('#account_pulldown').text();
    chrome.runtime.sendMessage({
      greeting: 'setSkipForLogin',
      user: user
    }, function(response) {
      if (response == 1) {
        jQuery.post('https://store.steampowered.com/logout/', {
          sessionid: sessionID
        });
        location.reload();
      }
    });
  }

}*/<commit_msg>There is more - A SECRET<commit_after>var sessionID = /sessionid=(.{24})/.exec(document.cookie)[1];

$(document).ready(function() {

  // Detect if Script is active
  /////////////////////////////
  chrome.runtime.sendMessage({greeting: 'getDiscoveryQueueStatus'}, function(stopme){
    if(document.location.href == "https://store.steampowered.com/login/?redir=explore%2F") {
      // Click first entry until none is left
      setTimeout(function(){
        if (stopme == 1) {
          if ($('.names').length > 0) {
            $('.names:eq(0)').click();
          } else {
            // When finished reset queue-status
            chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
          }
        }
      }, 1500);
    } else if (document.location.href == "http://store.steampowered.com/explore/") {
      if (stopme == 1) {

        var cards_dropped = jQuery('.discovery_queue_winter_sale_cards_header h3').text().replace(/\D/g,'');

        function discQueue(){

          if (cards_dropped == '' || cards_dropped == 2) {

            var GenerateQueue = function(queueNumber) {
            console.log('Queue #' + ++queueNumber);

            jQuery.post('http://store.steampowered.com/explore/generatenewdiscoveryqueue', {
              sessionid: sessionID,
              queuetype: 0
            }).done(function(data) {
              var requests = [];

              for (var i = 0; i < data.queue.length; i++) {
                requests.push(jQuery.post('http://store.steampowered.com/app/10', {
                  appid_to_clear_from_queue: data.queue[i],
                  sessionid: sessionID
                }));
              }

              jQuery.when.apply(jQuery, requests).done(function() {
                if (queueNumber < 3) {
                  GenerateQueue(queueNumber);
                } else {
                  location.reload();
                }
              });
            }).fail(function() {
              setTimeout(function() {
                GenerateQueue(0);
              }, 1000);
            });
            };
            setTimeout(function() {
            GenerateQueue(0);
            }, 1000);

            setTimeout(function() {
            location.reload();
            }, 10000);

          } else if(typeof cards_dropped == 'undefined'){
            chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
            alert('There was an error getting the left card-drops. Deactivating Discovery-Queue now!');
          } else if(cards_dropped >= 3){
            var user = $('#account_pulldown').text();
            chrome.runtime.sendMessage({
              greeting: 'setSkipForLogin',
              user: user
            }, function(response) {
              if (response == 1) {
                jQuery.post('https://store.steampowered.com/logout/', {
                  sessionid: sessionID
                });

                setTimeout(function(){
                  location.reload();
                }, 1000);
              }
            });
          }

        }

        // Execute
        discQueue();

      }

    } else if (document.location.href == "http://store.steampowered.com/") {
      if (stopme == 1) {
        document.location = "https://store.steampowered.com/login/?redir=explore%2F";
      }
    }
  });
});

// Awards
/*var cards_left = jQuery('.discovery_queue_winter_sale_cards_header .subtext').text().replace(/\D/g, '');
var cards_text = jQuery('.discovery_queue_winter_sale_cards_header .subtext').text();
var cards_text_compare = "Sie können heute noch eine weitere Karte erhalten, indem Sie Ihre Entdeckungsliste erkunden.";
               jQuery('.discovery_queue_winter_sale_cards_header h3').text().replace(/\D/g,'');
jQuery.ajax({
  url: 'http://store.steampowered.com/SteamAwards/',
  success: function(res){
    var awards = jQuery(res).find('.steamaward_castvote_writein');
    var arr = [];

  (function next(counter, maxLoops) {

    // all votes should be send now
    if(counter++ >= maxLoops){
      console.log("Voted! Iterating over Discovery-Queue now.");
      discQueue();
      return;
    }

    var scnt = 0;
    function processAjax(){
      scnt++;
      if(scnt <= 5){

        voteid = jQuery(awards[counter-1]).find('.vote_nominations').data('voteid');
        jQuery(awards[counter-1]).find('.vote_nomination').map(function(){
          arr.push(jQuery(this).data('vote-appid'));
        });

        jQuery.ajax({
          url: 'http://store.steampowered.com/salevote',
          type: 'POST',
          data: {
            sessionid: sessionID,
            voteid: voteid,
            appid: arr[Math.floor(Math.random()*arr.length)]
          },
          success: function(response){
            console.log(response);
            scnt = 0; arr = [];
            setTimeout(function(){ next(counter, maxLoops) }, 300);
          },
          error: function(xhr, textStatus, errorThrown){
            if(xhr.status == 403){
              setTimeout(function(){ next(counter, maxLoops) }, 300);
            } else {
              // probably some timeout - try again
              setTimeout(function(){ processAjax(); }, 3000);
            }
          }
        });

      } else {
        // to much retries
        scnt = 0;
        setTimeout(function(){ next(counter, maxLoops) }, 300);
      }
    }

    // Autostart on first iteration
    if(scnt <= 1) processAjax();

  })(0, awards.length);

  }
});

function discQueue(){

  if ((cards_left > 0 && cards_left !== '') || (cards_text == cards_text_compare)) {

    var GenerateQueue = function(queueNumber) {
    console.log('Queue #' + ++queueNumber);

    jQuery.post('http://store.steampowered.com/explore/generatenewdiscoveryqueue', {
      sessionid: sessionID,
      queuetype: 0
    }).done(function(data) {
      var requests = [];

      for (var i = 0; i < data.queue.length; i++) {
        requests.push(jQuery.post('http://store.steampowered.com/app/10', {
          appid_to_clear_from_queue: data.queue[i],
          sessionid: sessionID
        }));
      }

      jQuery.when.apply(jQuery, requests).done(function() {
        if (queueNumber < 3) {
          GenerateQueue(queueNumber);
        } else {
          location.reload();
        }
      });
    }).fail(function() {
      setTimeout(function() {
        GenerateQueue(0);
      }, 1000);
    });
    };
    setTimeout(function() {
    GenerateQueue(0);
    }, 1000);

    setTimeout(function() {
    location.reload();
    }, 10000);

  } else if(typeof cards_left == 'undefined'){
    chrome.runtime.sendMessage({greeting: 'setDiscoveryQueueStatusInactive'});
    alert('There was an error getting the left card-drops. Deactivating Discovery-Queue now!');
  } else if(cards_left == ''){
    var user = $('#account_pulldown').text();
    chrome.runtime.sendMessage({
      greeting: 'setSkipForLogin',
      user: user
    }, function(response) {
      if (response == 1) {
        jQuery.post('https://store.steampowered.com/logout/', {
          sessionid: sessionID
        });
        location.reload();
      }
    });
  }

}*/<|endoftext|>


<commit_before>/* ==========================================================
 * bootstrap-carousel.js v2.0.0
 * http://twitter.github.com/bootstrap/javascript.html#alerts
 * ==========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * 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.
 * ========================================================== */

!function( $ ){

  "use strict"

 /* CAROUSEL CLASS DEFINITION
  * ========================= */

  var Carousel = function (element, options) {
    this.$element = $(element)
    this.options = $.extend({}, $.fn.carousel.defaults, options)
    this.options.slide && this.slide(this.options.slide)
  }

  Carousel.prototype = {

    cycle: function () {
      this.interval = setInterval($.proxy(this.next, this), 5000)
      return this
    }

  , pause: function () {
      clearInterval(this.interval)
      return this
    }

  , next: function () {
      return this.slide('next')
    }

  , prev: function () {
      return this.slide('prev')
    }

  , slide: function (type) {
      var $active = this.$element.find('.active')
        , $next = $active[type]()
        , isCycling = this.interval
        , direction = type == 'next' ? 'left' : 'right'
        , fallback  = type == 'next' ? 'first' : 'last'
        , that = this

      isCycling && this.pause()

      $next = $next.length ? $next : this.$element.find('.item')[fallback]()

      if (!$.support.transition && this.$element.hasClass('slide')) {
        $active.removeClass('active')
        $next.addClass('active')
      } else {
        $next.addClass(type)
        $next[0].offsetWidth // force reflow
        $active.addClass(direction)
        $next.addClass(direction)
        this.$element.one($.support.transition.end, function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
        })
      }

      isCycling && this.cycle()

      return this
    }

  }

 /* CAROUSEL PLUGIN DEFINITION
  * ========================== */

  $.fn.carousel = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('carousel')
        , options = typeof option == 'object' && option
      if (!data) $this.data('carousel', (data = new Carousel(this, options)))
      if (typeof option == 'string' || (option = options.slide)) data[option]()
      else data.cycle()
    })
  }

  $.fn.carousel.defaults = {
      interval: 5000
  }

  $.fn.carousel.Constructor = Carousel

 /* CAROUSEL DATA-API
  * ================= */

  $(function () {
    $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
      var $this = $(this)
        , $target = $($this.attr('data-target') || $this.attr('href'))
        , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
      $target.carousel(options)
    })
  })

}( window.jQuery )<commit_msg>actuall use interval option :P<commit_after>/* ==========================================================
 * bootstrap-carousel.js v2.0.0
 * http://twitter.github.com/bootstrap/javascript.html#alerts
 * ==========================================================
 * Copyright 2011 Twitter, Inc.
 *
 * 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.
 * ========================================================== */

!function( $ ){

  "use strict"

 /* CAROUSEL CLASS DEFINITION
  * ========================= */

  var Carousel = function (element, options) {
    this.$element = $(element)
    this.options = $.extend({}, $.fn.carousel.defaults, options)
    this.options.slide && this.slide(this.options.slide)
  }

  Carousel.prototype = {

    cycle: function () {
      this.interval = setInterval($.proxy(this.next, this), this.options.interval)
      return this
    }

  , pause: function () {
      clearInterval(this.interval)
      return this
    }

  , next: function () {
      return this.slide('next')
    }

  , prev: function () {
      return this.slide('prev')
    }

  , slide: function (type) {
      var $active = this.$element.find('.active')
        , $next = $active[type]()
        , isCycling = this.interval
        , direction = type == 'next' ? 'left' : 'right'
        , fallback  = type == 'next' ? 'first' : 'last'
        , that = this

      isCycling && this.pause()

      $next = $next.length ? $next : this.$element.find('.item')[fallback]()

      if (!$.support.transition && this.$element.hasClass('slide')) {
        $active.removeClass('active')
        $next.addClass('active')
      } else {
        $next.addClass(type)
        $next[0].offsetWidth // force reflow
        $active.addClass(direction)
        $next.addClass(direction)
        this.$element.one($.support.transition.end, function () {
          $next.removeClass([type, direction].join(' ')).addClass('active')
          $active.removeClass(['active', direction].join(' '))
        })
      }

      isCycling && this.cycle()

      return this
    }

  }

 /* CAROUSEL PLUGIN DEFINITION
  * ========================== */

  $.fn.carousel = function ( option ) {
    return this.each(function () {
      var $this = $(this)
        , data = $this.data('carousel')
        , options = typeof option == 'object' && option
      if (!data) $this.data('carousel', (data = new Carousel(this, options)))
      if (typeof option == 'string' || (option = options.slide)) data[option]()
      else data.cycle()
    })
  }

  $.fn.carousel.defaults = {
    interval: 5000
  }

  $.fn.carousel.Constructor = Carousel

 /* CAROUSEL DATA-API
  * ================= */

  $(function () {
    $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
      var $this = $(this)
        , $target = $($this.attr('data-target') || $this.attr('href'))
        , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
      $target.carousel(options)
    })
  })

}( window.jQuery )<|endoftext|>


<commit_before>/**
 * $.inArray: friends with IE8. Use Array.prototype.indexOf in future.
 * Use this.element.hidden in future.
 * $.proxy: friends with IE8. Use Function.prototype.bind in future.
 */

'use strict';

(function(factory) {
  if (typeof define == 'function' && define.amd) {
    // AMD. Register as an anonymous module
    define(['jquery'], factory);
  }
  else if (typeof exports == 'object') {
    // Node/CommonJS
    module.exports = factory(require('jquery'));
  }
  else {
    // Browser globals
    factory(jQuery);
  }
})(function($) {
  $.create = function() {
    return $($.map(arguments, $.proxy(document, 'createElement')));
  };

  function Checkboxpicker(element, options) {
    this.element = element;
    this.$element = $(element);

    var data = this.$element.data();

    // === '': <... data-reverse>
    if (data.reverse === '') {
      data.reverse = true;
    }

    // === '': <... data-switch-always>
    if (data.switchAlways === '') {
      data.switchAlways = true;
    }

    this.options = $.extend({}, $.fn.checkboxpicker.defaults, options, data);

    if (this.$element.closest('label').length) {
      console.warn(this.options.warningMessage);

      return;
    }

    this.$group = $.create('div').addClass('btn-group');

    // .btn-group-justified works with <a> elements as the <button> doesn't pick up the styles
    this.$buttons = $.create('a', 'a').addClass('btn');

    this.$off = this.$buttons.eq(this.options.reverse ? 1 : 0);
    this.$on = this.$buttons.eq(this.options.reverse ? 0 : 1);

    this.init();
  }

  Checkboxpicker.prototype = {
    init: function() {
      var fn = this.options.html ? 'html' : 'text';

      this.$element.addClass('hidden');

      if (this.options.offLabel) {
        this.$off[fn](this.options.offLabel);
      }

      if (this.options.onLabel) {
        this.$on[fn](this.options.onLabel);
      }

      if (this.options.offIconClass) {
        if (this.options.offLabel) {
          //   -- whitespace (or wrap into span)
          this.$off.prepend(' ');
        }

        // $.addClass for XSS check
        $.create('span').addClass(this.options.offIconClass).prependTo(this.$off);
      }

      if (this.options.onIconClass) {
        if (this.options.onLabel) {
          //   -- whitespace (or wrap into span)
          this.$on.prepend(' ');
        }

        // $.addClass for XSS check
        $.create('span').addClass(this.options.onIconClass).prependTo(this.$on);
      }

      if (this.element.checked) {
        this.$on.addClass('active ' + this.options.onClass);
        this.$off.addClass(this.options.defaultClass);
      }
      else {
        this.$off.addClass('active ' + this.options.offClass);
        this.$on.addClass(this.options.defaultClass);
      }

      if (this.options.style) {
        this.$group.addClass(this.options.style);
      }

      if (this.element.title) {
        this.$group.attr('title', this.element.title);
      }
      else {
        // Attribute title (offTitle, onTitle) on this.$buttons not work (native) if this.element.disabled, fine!
        if (this.options.offTitle) {
          this.$off.attr('title', this.options.offTitle);
        }

        if (this.options.onTitle) {
          this.$on.attr('title', this.options.onTitle);
        }
      }

      // Keydown event only trigger if set tabindex, fine!
      this.$group.on('keydown', $.proxy(this, 'keydown'));

      // Don't trigger if <a> element has .disabled class, fine!
      this.$buttons.on('click', $.proxy(this, 'click'));

      this.$element.on('change', $.proxy(this, 'toggleChecked'));
      $(this.element.labels).on('click', $.proxy(this, 'focus'));
      $(this.element.form).on('reset', $.proxy(this, 'reset'));

      this.$group.append(this.$buttons).insertAfter(this.element);

      // Necessarily after this.$group.append() (autofocus)
      if (this.element.disabled) {
        this.$buttons.addClass('disabled');

        if (this.options.disabledCursor) {
          this.$group.css('cursor', this.options.disabledCursor);
        }
      }
      else {
        this.$group.attr('tabindex', this.element.tabIndex);

        if (this.element.autofocus) {
          this.focus();
        }
      }
    },
    toggleChecked: function() {
      // this.$group not focus (incorrect on form reset)
      this.$buttons.toggleClass('active ' + this.options.defaultClass);
      this.$off.toggleClass(this.options.offClass);
      this.$on.toggleClass(this.options.onClass);
    },
    toggleDisabled: function() {
      this.$buttons.toggleClass('disabled');

      if (this.element.disabled) {
        this.$group.attr('tabindex', this.element.tabIndex);
        this.$group.css('cursor', '');
      }
      else {
        this.$group.removeAttr('tabindex');

        if (this.options.disabledCursor) {
          this.$group.css('cursor', this.options.disabledCursor);
        }
      }
    },
    focus: function() {
      // Original behavior
      this.$group.trigger('focus');
    },
    click: function(event) {
      var $button = $(event.target);

      if (!$button.hasClass('active') || this.options.switchAlways) {
        this.change(!this.element.checked);
      }
    },
    change: function(value) {
      // Fix #12
      this.element.checked = value;

      this.$element.trigger('change');
    },
    keydown: function(event) {
      if ($.inArray(event.keyCode, this.options.toggleKeyCodes) != -1) {
        // Off vertical scrolling on Spacebar
        event.preventDefault();

        this.click();
      }
      else if (event.keyCode == 13) {
        $(this.element.form).trigger('submit');
      }
    },
    reset: function() {
      // this.element.checked not used (incorect on large number of form elements)
      if ((this.element.defaultChecked && this.$off.hasClass('active')) || (!this.element.defaultChecked && this.$on.hasClass('active'))) {
        this.change(this.element.defaultChecked);
      }
    }
  };

  // Be hooks friendly
  var oldPropHooks = $.extend({}, $.propHooks);

  // Support $.fn.prop setter (checked, disabled)
  $.extend($.propHooks, {
    checked: {
      set: function(element, value) {
        var data = $.data(element, 'bs.checkbox');

        if (data && element.checked != value) {
          data.change(value);
        }

        if (oldPropHooks.checked && oldPropHooks.checked.set) {
          oldPropHooks.checked.set(element, value);
        }
      }
    },
    disabled: {
      set: function(element, value) {
        var data = $.data(element, 'bs.checkbox');

        if (data && element.disabled != value) {
          data.toggleDisabled();
        }

        if (oldPropHooks.disabled && oldPropHooks.disabled.set) {
          oldPropHooks.disabled.set(element, value);
        }
      }
    }
  });

  // For AMD/Node/CommonJS used elements (optional)
  // http://learn.jquery.com/jquery-ui/environments/amd/
  $.fn.checkboxpicker = function(options, elements) {
    var $elements;

    if (this instanceof $) {
      $elements = this;
    }
    else if (typeof options == 'string') {
      $elements = $(options);
    }
    else {
      $elements = $(elements);
    }

    return $elements.each(function() {
      var data = $.data(this, 'bs.checkbox');

      if (!data) {
        data = new Checkboxpicker(this, options);

        $.data(this, 'bs.checkbox', data);
      }
    });
  };

  // HTML5 data-*.
  // <input data-on-label="43"> --> $('input').data('onLabel') == '43'.
  $.fn.checkboxpicker.defaults = {
    style: false,
    defaultClass: 'btn-default',
    disabledCursor: 'not-allowed',
    offClass: 'btn-danger',
    onClass: 'btn-success',
    offLabel: 'No',
    onLabel: 'Yes',
    offTitle: false,
    onTitle: false,
    html: false,

    // Event key codes:
    // 13: Return
    // 32: Spacebar
    toggleKeyCodes: [13, 32],

    warningMessage: 'Please do not use Bootstrap-checkbox element in label element.'
  };

  return $.fn.checkboxpicker;
});
<commit_msg>Add example with html option<commit_after>/**
 * $.inArray: friends with IE8. Use Array.prototype.indexOf in future.
 * Use this.element.hidden in future.
 * $.proxy: friends with IE8. Use Function.prototype.bind in future.
 */

'use strict';

(function(factory) {
  if (typeof define == 'function' && define.amd) {
    // AMD. Register as an anonymous module
    define(['jquery'], factory);
  }
  else if (typeof exports == 'object') {
    // Node/CommonJS
    module.exports = factory(require('jquery'));
  }
  else {
    // Browser globals
    factory(jQuery);
  }
})(function($) {
  $.create = function() {
    return $($.map(arguments, $.proxy(document, 'createElement')));
  };

  function Checkboxpicker(element, options) {
    this.element = element;
    this.$element = $(element);

    var data = this.$element.data();

    // <... data-reverse>
    if (data.reverse === '') {
      data.reverse = true;
    }

    // <... data-switch-always>
    if (data.switchAlways === '') {
      data.switchAlways = true;
    }

    // <... data-html>
    if (data.html === '') {
      data.html = true;
    }

    this.options = $.extend({}, $.fn.checkboxpicker.defaults, options, data);

    if (this.$element.closest('label').length) {
      console.warn(this.options.warningMessage);

      return;
    }

    this.$group = $.create('div').addClass('btn-group');

    // .btn-group-justified works with <a> elements as the <button> doesn't pick up the styles
    this.$buttons = $.create('a', 'a').addClass('btn');

    this.$off = this.$buttons.eq(this.options.reverse ? 1 : 0);
    this.$on = this.$buttons.eq(this.options.reverse ? 0 : 1);

    this.init();
  }

  Checkboxpicker.prototype = {
    init: function() {
      var fn = this.options.html ? 'html' : 'text';

      this.$element.addClass('hidden');

      if (this.options.offLabel) {
        this.$off[fn](this.options.offLabel);
      }

      if (this.options.onLabel) {
        this.$on[fn](this.options.onLabel);
      }

      if (this.options.offIconClass) {
        if (this.options.offLabel) {
          //   -- whitespace (or wrap into span)
          this.$off.prepend(' ');
        }

        // $.addClass for XSS check
        $.create('span').addClass(this.options.offIconClass).prependTo(this.$off);
      }

      if (this.options.onIconClass) {
        if (this.options.onLabel) {
          //   -- whitespace (or wrap into span)
          this.$on.prepend(' ');
        }

        // $.addClass for XSS check
        $.create('span').addClass(this.options.onIconClass).prependTo(this.$on);
      }

      if (this.element.checked) {
        this.$on.addClass('active ' + this.options.onClass);
        this.$off.addClass(this.options.defaultClass);
      }
      else {
        this.$off.addClass('active ' + this.options.offClass);
        this.$on.addClass(this.options.defaultClass);
      }

      if (this.options.style) {
        this.$group.addClass(this.options.style);
      }

      if (this.element.title) {
        this.$group.attr('title', this.element.title);
      }
      else {
        // Attribute title (offTitle, onTitle) on this.$buttons not work (native) if this.element.disabled, fine!
        if (this.options.offTitle) {
          this.$off.attr('title', this.options.offTitle);
        }

        if (this.options.onTitle) {
          this.$on.attr('title', this.options.onTitle);
        }
      }

      // Keydown event only trigger if set tabindex, fine!
      this.$group.on('keydown', $.proxy(this, 'keydown'));

      // Don't trigger if <a> element has .disabled class, fine!
      this.$buttons.on('click', $.proxy(this, 'click'));

      this.$element.on('change', $.proxy(this, 'toggleChecked'));
      $(this.element.labels).on('click', $.proxy(this, 'focus'));
      $(this.element.form).on('reset', $.proxy(this, 'reset'));

      this.$group.append(this.$buttons).insertAfter(this.element);

      // Necessarily after this.$group.append() (autofocus)
      if (this.element.disabled) {
        this.$buttons.addClass('disabled');

        if (this.options.disabledCursor) {
          this.$group.css('cursor', this.options.disabledCursor);
        }
      }
      else {
        this.$group.attr('tabindex', this.element.tabIndex);

        if (this.element.autofocus) {
          this.focus();
        }
      }
    },
    toggleChecked: function() {
      // this.$group not focus (incorrect on form reset)
      this.$buttons.toggleClass('active ' + this.options.defaultClass);
      this.$off.toggleClass(this.options.offClass);
      this.$on.toggleClass(this.options.onClass);
    },
    toggleDisabled: function() {
      this.$buttons.toggleClass('disabled');

      if (this.element.disabled) {
        this.$group.attr('tabindex', this.element.tabIndex);
        this.$group.css('cursor', '');
      }
      else {
        this.$group.removeAttr('tabindex');

        if (this.options.disabledCursor) {
          this.$group.css('cursor', this.options.disabledCursor);
        }
      }
    },
    focus: function() {
      // Original behavior
      this.$group.trigger('focus');
    },
    click: function(event) {
      var $button = $(event.target);

      if (!$button.hasClass('active') || this.options.switchAlways) {
        this.change();
      }
    },
    change: function() {
      this.set(!this.element.checked);
    },
    set: function(value) {
      // Fix #12
      this.element.checked = value;

      this.$element.trigger('change');
    },
    keydown: function(event) {
      if ($.inArray(event.keyCode, this.options.toggleKeyCodes) != -1) {
        // Off vertical scrolling on Spacebar
        event.preventDefault();

        this.change();
      }
      else if (event.keyCode == 13) {
        $(this.element.form).trigger('submit');
      }
    },
    reset: function() {
      // this.element.checked not used (incorect on large number of form elements)
      if ((this.element.defaultChecked && this.$off.hasClass('active')) || (!this.element.defaultChecked && this.$on.hasClass('active'))) {
        this.set(this.element.defaultChecked);
      }
    }
  };

  // Be hooks friendly
  var oldPropHooks = $.extend({}, $.propHooks);

  // Support $.fn.prop setter (checked, disabled)
  $.extend($.propHooks, {
    checked: {
      set: function(element, value) {
        var data = $.data(element, 'bs.checkbox');

        if (data && element.checked != value) {
          data.change(value);
        }

        if (oldPropHooks.checked && oldPropHooks.checked.set) {
          oldPropHooks.checked.set(element, value);
        }
      }
    },
    disabled: {
      set: function(element, value) {
        var data = $.data(element, 'bs.checkbox');

        if (data && element.disabled != value) {
          data.toggleDisabled();
        }

        if (oldPropHooks.disabled && oldPropHooks.disabled.set) {
          oldPropHooks.disabled.set(element, value);
        }
      }
    }
  });

  // For AMD/Node/CommonJS used elements (optional)
  // http://learn.jquery.com/jquery-ui/environments/amd/
  $.fn.checkboxpicker = function(options, elements) {
    var $elements;

    if (this instanceof $) {
      $elements = this;
    }
    else if (typeof options == 'string') {
      $elements = $(options);
    }
    else {
      $elements = $(elements);
    }

    return $elements.each(function() {
      var data = $.data(this, 'bs.checkbox');

      if (!data) {
        data = new Checkboxpicker(this, options);

        $.data(this, 'bs.checkbox', data);
      }
    });
  };

  // HTML5 data-*.
  // <input data-on-label="43"> --> $('input').data('onLabel') == '43'.
  $.fn.checkboxpicker.defaults = {
    style: false,
    defaultClass: 'btn-default',
    disabledCursor: 'not-allowed',
    offClass: 'btn-danger',
    onClass: 'btn-success',
    offLabel: 'No',
    onLabel: 'Yes',
    offTitle: false,
    onTitle: false,

    // Event key codes:
    // 13: Return
    // 32: Spacebar
    toggleKeyCodes: [13, 32],

    warningMessage: 'Please do not use Bootstrap-checkbox element in label element.'
  };

  return $.fn.checkboxpicker;
});
<|endoftext|>


<commit_before>// Copyright 2020, University of Colorado Boulder

/**
 * ButtonNode is the base class for the sun button hierarchy.
 *
 * @author John Blanco (PhET Interactive Simulations)
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import merge from '../../../phet-core/js/merge.js';
import AlignBox from '../../../scenery/js/nodes/AlignBox.js';
import Node from '../../../scenery/js/nodes/Node.js';
import PaintColorProperty from '../../../scenery/js/util/PaintColorProperty.js';
import Tandem from '../../../tandem/js/Tandem.js';
import ColorConstants from '../ColorConstants.js';
import sun from '../sun.js';
import ButtonInteractionState from './ButtonInteractionState.js';

// constants
const X_ALIGN_VALUES = [ 'center', 'left', 'right' ];
const Y_ALIGN_VALUES = [ 'center', 'top', 'bottom' ];

class ButtonNode extends Node {

  /**
   * @param {ButtonModel} buttonModel
   * @param {Node,Paintable} buttonBackground - the background of the button (like a circle or rectangle).
   * @param {Property} interactionStateProperty - a Property that is used to drive the visual appearance of the button
   * @param {Object} [options] - this type does not mutate its options, but relies on the subtype to
   */
  constructor( buttonModel, buttonBackground, interactionStateProperty, options ) {

    options = merge( {

      // {Node|null} what appears on the button (icon, label, etc.)
      content: null,

      xMargin: 10, // margin in x direction, i.e. on left and right
      yMargin: 5, // margin in y direction, i.e. on top and bottom

      // Alignment, relevant only when options minWidth or minHeight are greater than the size of options.content
      xAlign: 'center', // {string} see X_ALIGN_VALUES
      yAlign: 'center', // {string} see Y_ALIGN_VALUES

      // By default, icons are centered in the button, but icons with odd
      // shapes that are not wrapped in a normalizing parent node may need to
      // specify offsets to line things up properly
      xContentOffset: 0,
      yContentOffset: 0,

      // Options that will be passed through to the main input listener (PressListener)
      listenerOptions: null,

      // {ColorDef} initial color of the button's background
      baseColor: ColorConstants.LIGHT_BLUE,

      // {string} default cursor
      cursor: 'pointer',

      // Class that determines the button's appearance for the values of interactionStateProperty.
      // Constructor is {function( backgroundNode:Node, interactionStateProperty:Property, options:*)},
      // and the class has an optional dispose method.
      // See ButtonNode.FlatAppearanceStrategy for an example.
      buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy,

      // Optional class that determines the content's appearance for the values of interactionStateProperty.
      // Constructor is {function( content:Node, interactionStateProperty:Property, options:*)},
      // and the class has an optional dispose method.
      // See RectangularRadioButton.ContentAppearanceStrategy for an example.
      contentAppearanceStrategy: null,

      // phet-io
      tandem: Tandem.OPTIONAL,
      visiblePropertyOptions: { phetioFeatured: true },
      enabledPropertyPhetioInstrumented: true // opt into default PhET-iO instrumented enabledProperty
    }, options );

    options.listenerOptions = merge( {
      tandem: options.tandem.createTandem( 'pressListener' )
    }, options.listenerOptions );

    assert && options.enabledProperty && assert( options.enabledProperty === buttonModel.enabledProperty,
      'if options.enabledProperty is provided, it must === buttonModel.enabledProperty' );
    options.enabledProperty = buttonModel.enabledProperty;

    // validate options - TODO: are these needed? Won't AlignBox handle this validation? https://github.com/phetsims/sun/issues/643
    assert && assert( _.includes( X_ALIGN_VALUES, options.xAlign ), 'invalid xAlign: ' + options.xAlign );
    assert && assert( _.includes( Y_ALIGN_VALUES, options.yAlign ), 'invalid yAlign: ' + options.yAlign );

    super();

    // @protected
    this.buttonModel = buttonModel;

    // Make the base color into a Property so that the appearance strategy can update itself if changes occur.
    this.baseColorProperty = new PaintColorProperty( options.baseColor ); // @private

    // @private {PressListener}
    this._pressListener = buttonModel.createPressListener( options.listenerOptions );
    this.addInputListener( this._pressListener );

    assert && assert( buttonBackground.fill === null, 'ButtonNode controls the fill for the buttonBackground' );
    buttonBackground.fill = this.baseColorProperty;
    this.addChild( buttonBackground );

    // Hook up the strategy that will control the button's appearance.
    const buttonAppearanceStrategy = new options.buttonAppearanceStrategy( buttonBackground, interactionStateProperty,
      this.baseColorProperty, options );

    // Optionally hook up the strategy that will control the content's appearance.
    let contentAppearanceStrategy;
    if ( options.contentAppearanceStrategy ) {
      contentAppearanceStrategy = new options.contentAppearanceStrategy( options.content, interactionStateProperty, options );
    }

    let alignBox = null;
    if ( options.content ) {

      // For performance, in case content is a complicated icon or shape.
      // See https://github.com/phetsims/sun/issues/654#issuecomment-718944669
      options.content.pickable = false;

      // Align content in the button rectangle. Must be disposed since it adds listener to content bounds.
      alignBox = new AlignBox( options.content, {

        alignBounds: buttonBackground.bounds,
        xAlign: options.xAlign,
        yAlign: options.yAlign,

        // Apply offsets via margins, so that bounds of the AlignBox doesn't unnecessarily extend past the
        // buttonBackground. See https://github.com/phetsims/sun/issues/649
        leftMargin: options.xMargin + options.xContentOffset,
        rightMargin: options.xMargin - options.xContentOffset,
        topMargin: options.yMargin + options.yContentOffset,
        bottomMargin: options.yMargin - options.yContentOffset
      } );
      this.addChild( alignBox );
    }

    this.mutate( options );

    // @private - define a dispose function
    this.disposeButtonNode = () => {
      alignBox && alignBox.dispose();
      buttonAppearanceStrategy.dispose && buttonAppearanceStrategy.dispose();
      contentAppearanceStrategy && contentAppearanceStrategy.dispose && contentAppearanceStrategy.dispose();
      this._pressListener.dispose();
      this.baseColorProperty.dispose();
    };
  }

  /**
   * @public
   * @override
   */
  dispose() {
    this.disposeButtonNode();
    super.dispose();
  }

  /**
   * Sets the base color, which is the main background fill color used for the button.
   * @param {Color|String} baseColor
   * @public
   */
  setBaseColor( baseColor ) { this.baseColorProperty.paint = baseColor; }

  set baseColor( baseColor ) { this.setBaseColor( baseColor ); }

  /**
   * Gets the base color for this button.
   * @returns {Color}
   * @public
   */
  getBaseColor() { return this.baseColorProperty.paint; }

  get baseColor() { return this.getBaseColor(); }

  /**
   * Manually click the button, as it would be clicked in response to alternative input. Recommended only for
   * accessibility usages. For the most part, PDOM button functionality should be managed by PressListener, this should
   * rarely be used.
   * @public
   */
  pdomClick() {
    this._pressListener.click();
  }

  /**
   * Is the button currently firing because of accessibility input coming from the PDOM?
   * @public (pdom)
   * @returns {boolean}
   */
  isPDOMClicking() {
    return this._pressListener.pdomClickingProperty.get();
  }
}

/**
 * FlatAppearanceStrategy is a value for ButtonNode options.buttonAppearanceStrategy. It makes a
 * button look flat, i.e. no shading or highlighting, with color changes on mouseover, press, etc.
 */
class FlatAppearanceStrategy {

  /*
   * @param {Node,Paintable} buttonBackground - the Node for the button's background, sans content
   * @param {Property.<ButtonInteractionState>} interactionStateProperty
   * @param {Property.<ColorDef>} baseColorProperty
   * @param {Object} [options]
   */
  constructor( buttonBackground, interactionStateProperty, baseColorProperty, options ) {

    // Dynamic colors
    const baseBrighter4 = new PaintColorProperty( baseColorProperty, { luminanceFactor: 0.4 } );
    const baseDarker4 = new PaintColorProperty( baseColorProperty, { luminanceFactor: -0.4 } );

    // Various fills that are used to alter the button's appearance
    const upFill = baseColorProperty;
    const overFill = baseBrighter4;
    const downFill = baseDarker4;

    // If the stroke wasn't provided, set a default
    buttonBackground.stroke = ( typeof ( options.stroke ) === 'undefined' ) ? baseDarker4 : options.stroke;

    // Cache colors
    buttonBackground.cachedPaints = [ upFill, overFill, downFill ];

    // Change colors to match interactionState
    function interactionStateListener( interactionState ) {
      switch( interactionState ) {

        case ButtonInteractionState.IDLE:
          buttonBackground.fill = upFill;
          break;

        case ButtonInteractionState.OVER:
          buttonBackground.fill = overFill;
          break;

        case ButtonInteractionState.PRESSED:
          buttonBackground.fill = downFill;
          break;

        default:
          throw new Error( `unsupported interactionState: ${interactionState}` );
      }
    }

    // Do the initial update explicitly, then lazy link to the properties.  This keeps the number of initial updates to
    // a minimum and allows us to update some optimization flags the first time the base color is actually changed.
    interactionStateProperty.link( interactionStateListener );

    // @public
    this.dispose = () => {
      if ( interactionStateProperty.hasListener( interactionStateListener ) ) {
        interactionStateProperty.unlink( interactionStateListener );
      }

      baseBrighter4.dispose();
      baseDarker4.dispose();
    };
  }
}

ButtonNode.FlatAppearanceStrategy = FlatAppearanceStrategy;

sun.register( 'ButtonNode', ButtonNode );
export default ButtonNode;<commit_msg>Adding default to grayscale sun buttons when disabled, see https://github.com/phetsims/sun/issues/658<commit_after>// Copyright 2020, University of Colorado Boulder

/**
 * ButtonNode is the base class for the sun button hierarchy.
 *
 * @author John Blanco (PhET Interactive Simulations)
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Michael Kauzmann (PhET Interactive Simulations)
 */

import merge from '../../../phet-core/js/merge.js';
import AlignBox from '../../../scenery/js/nodes/AlignBox.js';
import Node from '../../../scenery/js/nodes/Node.js';
import Grayscale from '../../../scenery/js/util/Grayscale.js';
import PaintColorProperty from '../../../scenery/js/util/PaintColorProperty.js';
import Tandem from '../../../tandem/js/Tandem.js';
import ColorConstants from '../ColorConstants.js';
import sun from '../sun.js';
import ButtonInteractionState from './ButtonInteractionState.js';

// constants
const X_ALIGN_VALUES = [ 'center', 'left', 'right' ];
const Y_ALIGN_VALUES = [ 'center', 'top', 'bottom' ];

class ButtonNode extends Node {

  /**
   * @param {ButtonModel} buttonModel
   * @param {Node,Paintable} buttonBackground - the background of the button (like a circle or rectangle).
   * @param {Property} interactionStateProperty - a Property that is used to drive the visual appearance of the button
   * @param {Object} [options] - this type does not mutate its options, but relies on the subtype to
   */
  constructor( buttonModel, buttonBackground, interactionStateProperty, options ) {

    options = merge( {

      // {Node|null} what appears on the button (icon, label, etc.)
      content: null,

      xMargin: 10, // margin in x direction, i.e. on left and right
      yMargin: 5, // margin in y direction, i.e. on top and bottom

      // Alignment, relevant only when options minWidth or minHeight are greater than the size of options.content
      xAlign: 'center', // {string} see X_ALIGN_VALUES
      yAlign: 'center', // {string} see Y_ALIGN_VALUES

      // By default, icons are centered in the button, but icons with odd
      // shapes that are not wrapped in a normalizing parent node may need to
      // specify offsets to line things up properly
      xContentOffset: 0,
      yContentOffset: 0,

      // Options that will be passed through to the main input listener (PressListener)
      listenerOptions: null,

      // {ColorDef} initial color of the button's background
      baseColor: ColorConstants.LIGHT_BLUE,

      // {string} default cursor
      cursor: 'pointer',

      // Class that determines the button's appearance for the values of interactionStateProperty.
      // Constructor is {function( backgroundNode:Node, interactionStateProperty:Property, options:*)},
      // and the class has an optional dispose method.
      // See ButtonNode.FlatAppearanceStrategy for an example.
      buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy,

      // Optional class that determines the content's appearance for the values of interactionStateProperty.
      // Constructor is {function( content:Node, interactionStateProperty:Property, options:*)},
      // and the class has an optional dispose method.
      // See RectangularRadioButton.ContentAppearanceStrategy for an example.
      contentAppearanceStrategy: null,

      // phet-io
      tandem: Tandem.OPTIONAL,
      visiblePropertyOptions: { phetioFeatured: true },
      enabledPropertyPhetioInstrumented: true // opt into default PhET-iO instrumented enabledProperty
    }, options );

    options.listenerOptions = merge( {
      tandem: options.tandem.createTandem( 'pressListener' )
    }, options.listenerOptions );

    assert && options.enabledProperty && assert( options.enabledProperty === buttonModel.enabledProperty,
      'if options.enabledProperty is provided, it must === buttonModel.enabledProperty' );
    options.enabledProperty = buttonModel.enabledProperty;

    // validate options - TODO: are these needed? Won't AlignBox handle this validation? https://github.com/phetsims/sun/issues/643
    assert && assert( _.includes( X_ALIGN_VALUES, options.xAlign ), 'invalid xAlign: ' + options.xAlign );
    assert && assert( _.includes( Y_ALIGN_VALUES, options.yAlign ), 'invalid yAlign: ' + options.yAlign );

    super();

    // @protected
    this.buttonModel = buttonModel;

    // Make the base color into a Property so that the appearance strategy can update itself if changes occur.
    this.baseColorProperty = new PaintColorProperty( options.baseColor ); // @private

    // @private {PressListener}
    this._pressListener = buttonModel.createPressListener( options.listenerOptions );
    this.addInputListener( this._pressListener );

    assert && assert( buttonBackground.fill === null, 'ButtonNode controls the fill for the buttonBackground' );
    buttonBackground.fill = this.baseColorProperty;
    this.addChild( buttonBackground );

    // Hook up the strategy that will control the button's appearance.
    const buttonAppearanceStrategy = new options.buttonAppearanceStrategy( buttonBackground, interactionStateProperty,
      this.baseColorProperty, options );

    // Optionally hook up the strategy that will control the content's appearance.
    let contentAppearanceStrategy;
    if ( options.contentAppearanceStrategy ) {
      contentAppearanceStrategy = new options.contentAppearanceStrategy( options.content, interactionStateProperty, options );
    }

    let alignBox = null;
    if ( options.content ) {

      // For performance, in case content is a complicated icon or shape.
      // See https://github.com/phetsims/sun/issues/654#issuecomment-718944669
      options.content.pickable = false;

      // Align content in the button rectangle. Must be disposed since it adds listener to content bounds.
      alignBox = new AlignBox( options.content, {

        alignBounds: buttonBackground.bounds,
        xAlign: options.xAlign,
        yAlign: options.yAlign,

        // Apply offsets via margins, so that bounds of the AlignBox doesn't unnecessarily extend past the
        // buttonBackground. See https://github.com/phetsims/sun/issues/649
        leftMargin: options.xMargin + options.xContentOffset,
        rightMargin: options.xMargin - options.xContentOffset,
        topMargin: options.yMargin + options.yContentOffset,
        bottomMargin: options.yMargin - options.yContentOffset
      } );
      this.addChild( alignBox );
    }

    this.mutate( options );

    // @private - define a dispose function
    this.disposeButtonNode = () => {
      alignBox && alignBox.dispose();
      buttonAppearanceStrategy.dispose && buttonAppearanceStrategy.dispose();
      contentAppearanceStrategy && contentAppearanceStrategy.dispose && contentAppearanceStrategy.dispose();
      this._pressListener.dispose();
      this.baseColorProperty.dispose();
    };
  }

  /**
   * @public
   * @override
   */
  dispose() {
    this.disposeButtonNode();
    super.dispose();
  }

  /**
   * Sets the base color, which is the main background fill color used for the button.
   * @param {Color|String} baseColor
   * @public
   */
  setBaseColor( baseColor ) { this.baseColorProperty.paint = baseColor; }

  set baseColor( baseColor ) { this.setBaseColor( baseColor ); }

  /**
   * Gets the base color for this button.
   * @returns {Color}
   * @public
   */
  getBaseColor() { return this.baseColorProperty.paint; }

  get baseColor() { return this.getBaseColor(); }

  /**
   * Manually click the button, as it would be clicked in response to alternative input. Recommended only for
   * accessibility usages. For the most part, PDOM button functionality should be managed by PressListener, this should
   * rarely be used.
   * @public
   */
  pdomClick() {
    this._pressListener.click();
  }

  /**
   * Is the button currently firing because of accessibility input coming from the PDOM?
   * @public (pdom)
   * @returns {boolean}
   */
  isPDOMClicking() {
    return this._pressListener.pdomClickingProperty.get();
  }

  /**
   * @protected
   * @override
   *
   * @param {boolean} enabled
   */
  onEnabledPropertyChange( enabled ) {
    super.onEnabledPropertyChange( enabled );

    this.opacity = 1.0;
    this.filters = enabled ? [] : [ Grayscale.FULL ];
  }
}

/**
 * FlatAppearanceStrategy is a value for ButtonNode options.buttonAppearanceStrategy. It makes a
 * button look flat, i.e. no shading or highlighting, with color changes on mouseover, press, etc.
 */
class FlatAppearanceStrategy {

  /*
   * @param {Node,Paintable} buttonBackground - the Node for the button's background, sans content
   * @param {Property.<ButtonInteractionState>} interactionStateProperty
   * @param {Property.<ColorDef>} baseColorProperty
   * @param {Object} [options]
   */
  constructor( buttonBackground, interactionStateProperty, baseColorProperty, options ) {

    // Dynamic colors
    const baseBrighter4 = new PaintColorProperty( baseColorProperty, { luminanceFactor: 0.4 } );
    const baseDarker4 = new PaintColorProperty( baseColorProperty, { luminanceFactor: -0.4 } );

    // Various fills that are used to alter the button's appearance
    const upFill = baseColorProperty;
    const overFill = baseBrighter4;
    const downFill = baseDarker4;

    // If the stroke wasn't provided, set a default
    buttonBackground.stroke = ( typeof ( options.stroke ) === 'undefined' ) ? baseDarker4 : options.stroke;

    // Cache colors
    buttonBackground.cachedPaints = [ upFill, overFill, downFill ];

    // Change colors to match interactionState
    function interactionStateListener( interactionState ) {
      switch( interactionState ) {

        case ButtonInteractionState.IDLE:
          buttonBackground.fill = upFill;
          break;

        case ButtonInteractionState.OVER:
          buttonBackground.fill = overFill;
          break;

        case ButtonInteractionState.PRESSED:
          buttonBackground.fill = downFill;
          break;

        default:
          throw new Error( `unsupported interactionState: ${interactionState}` );
      }
    }

    // Do the initial update explicitly, then lazy link to the properties.  This keeps the number of initial updates to
    // a minimum and allows us to update some optimization flags the first time the base color is actually changed.
    interactionStateProperty.link( interactionStateListener );

    // @public
    this.dispose = () => {
      if ( interactionStateProperty.hasListener( interactionStateListener ) ) {
        interactionStateProperty.unlink( interactionStateListener );
      }

      baseBrighter4.dispose();
      baseDarker4.dispose();
    };
  }
}

ButtonNode.FlatAppearanceStrategy = FlatAppearanceStrategy;

sun.register( 'ButtonNode', ButtonNode );
export default ButtonNode;<|endoftext|>


<commit_before>var storageChange="Google.com";
function convertURL(url){
    console.log(url)
    url = url.replace(/%20/g,"+")
    var uri = /\?q\=([0-9a-zA-Z-._~:\/?#[\]@!$'()*+,;=%]*)($|(\&))/.exec(url)[1]
    console.log(url)
    console.log(uri)

    var match = /^((go\+to\+)|(open\+)|())([0-9a-zA-Z-._~:\/?#[\]@!$'()*+,;=%]*\.[a-z]+)/i.exec(uri)
    console.log(match)
    if(match){
        return "http://" + match[4]
    }
    if(url.search("search?q=go%20to%20")!=-1){
        return "http://" + url.substring(url.search('=')+11, url.search('&'));
    }
    if(storageChange=="Google.com"){
        return url.replace("www.bing.com/search", "www.google.com/search");
    }
    if(storageChange=="DuckDuckGo.com"){
        return url.replace("www.bing.com/search", "www.duckduckgo.com");
    }
    if(storageChange=="Ask.com"){
        return url.replace(/.*:\/\/www.bing.com\/search/, "http://www.ask.com/web");
    }
    if(storageChange=="Yahoo.com"){
        return url.replace("www.bing.com/search?q", "search.yahoo.com/search?p");
    }
    if(storageChange=="Aol.com"){
        return url.replace(/.*:\/\/www.bing.com\/search/, "http://search.aol.com/aol/search");
    }
    if(storageChange=="Wow.com"){
        return url.replace(/.*:\/\/www.bing.com/, "http://us.wow.com");
    }
    return url.replace("www.bing.com/search", "www.google.com/search");
}
chrome.storage.sync.get('search_engine', function (obj) {
        console.log('myKey', obj);
        storageChange=obj['search_engine'];
});

chrome.storage.onChanged.addListener(function(changes, namespace) {
    storageChange = changes['search_engine']['newValue'];
    console.log(storageChange);
});

chrome.webRequest.onBeforeRequest.addListener(function(details) {
   	console.log(storageChange);

    return { redirectUrl: convertURL(details.url)};
}, {urls: ["*://www.bing.com/search*"]}, ["blocking"]);

// Redirect to welcome.html on install
chrome.runtime.onInstalled.addListener(function(details){
    if(details.reason == "install"){
        chrome.tabs.create({url: "html/options.html?newinstall=yes"});
    }else if(details.reason == "update"){
        var thisVersion = chrome.runtime.getManifest().version;
        console.log("Updated from " + details.previousVersion + " to " + thisVersion + "!");
    }
});
// Fallback when Chrome is not already running
chrome.runtime.onMessage.addListener(onMessage);
function onMessage(request, sender, callback) {
    if (request.action == "convertURL") {
        callback(convertURL(request.url));
    }
    return true;
}
<commit_msg>correct match group<commit_after>var storageChange="Google.com";
function convertURL(url){
    console.log(url)
    url = url.replace(/%20/g,"+")
    var uri = /\?q\=([0-9a-zA-Z-._~:\/?#[\]@!$'()*+,;=%]*)($|(\&))/.exec(url)[1]
    console.log(url)
    console.log(uri)

    var match = /^((go\+to\+)|(open\+)|())([0-9a-zA-Z-._~:\/?#[\]@!$'()*+,;=%]*\.[a-z]+)/i.exec(uri)
    console.log(match)
    if(match){
        return "http://" + match[5]
    }
    if(url.search("search?q=go%20to%20")!=-1){
        return "http://" + url.substring(url.search('=')+11, url.search('&'));
    }
    if(storageChange=="Google.com"){
        return url.replace("www.bing.com/search", "www.google.com/search");
    }
    if(storageChange=="DuckDuckGo.com"){
        return url.replace("www.bing.com/search", "www.duckduckgo.com");
    }
    if(storageChange=="Ask.com"){
        return url.replace(/.*:\/\/www.bing.com\/search/, "http://www.ask.com/web");
    }
    if(storageChange=="Yahoo.com"){
        return url.replace("www.bing.com/search?q", "search.yahoo.com/search?p");
    }
    if(storageChange=="Aol.com"){
        return url.replace(/.*:\/\/www.bing.com\/search/, "http://search.aol.com/aol/search");
    }
    if(storageChange=="Wow.com"){
        return url.replace(/.*:\/\/www.bing.com/, "http://us.wow.com");
    }
    return url.replace("www.bing.com/search", "www.google.com/search");
}
chrome.storage.sync.get('search_engine', function (obj) {
        console.log('myKey', obj);
        storageChange=obj['search_engine'];
});

chrome.storage.onChanged.addListener(function(changes, namespace) {
    storageChange = changes['search_engine']['newValue'];
    console.log(storageChange);
});

chrome.webRequest.onBeforeRequest.addListener(function(details) {
   	console.log(storageChange);

    return { redirectUrl: convertURL(details.url)};
}, {urls: ["*://www.bing.com/search*"]}, ["blocking"]);

// Redirect to welcome.html on install
chrome.runtime.onInstalled.addListener(function(details){
    if(details.reason == "install"){
        chrome.tabs.create({url: "html/options.html?newinstall=yes"});
    }else if(details.reason == "update"){
        var thisVersion = chrome.runtime.getManifest().version;
        console.log("Updated from " + details.previousVersion + " to " + thisVersion + "!");
    }
});
// Fallback when Chrome is not already running
chrome.runtime.onMessage.addListener(onMessage);
function onMessage(request, sender, callback) {
    if (request.action == "convertURL") {
        callback(convertURL(request.url));
    }
    return true;
}
<|endoftext|>


<commit_before>define(["d3", "googleMap", "nestDetail"], function(d3, GoogleMap, NestDetail) {

var module = function(chartNode, customOptions, events) {

  var defaultOptions = {
  }

  var NEST_STATES = {
    PINNED: "green",
    HOVERED: "red",
    DEFAULT: "grey",
  };

  var options = $.extend({}, defaultOptions, customOptions);

  // general variables

  var gMap = new GoogleMap(chartNode, options, events);
  var nestDetail = new NestDetail();
  var pinnedNest = undefined;
  var nestLayer;
  var nests;

  function genPoint() {
    return {
      lat: latScale(Math.random()),
      lng: lonScale(Math.random()),
      radius: radScale(Math.random()),
    }
  }

  function initialize(_nests) {
    nests = _nests;
    gMap.initialize();
    gMap.on("mapReady", confgureMap);
    gMap.on("mapDraw", draw);
    gMap.on("drag", onDrag);
    gMap.on("zoom", draw);
    gMap.zoomToFit(nests);
  }

  function confgureMap() {
    nestLayer = gMap.createLayer();

    var nestCircles = nestLayer.selectAll("circle")
      .data(nests);

    nestCircles
      .enter()
      .append("circle")
      .classed("nest", true)
      .attr("r", 10)
      .attr("opacity", 0.8)
      .style("fill", NEST_STATES.DEFAULT)
      .on("click", function(d) {zoomToNest(d)})
      .on("mouseenter", onMouseEnter)
      .on("mouseleave", onMouseExit);
  }

  function onMouseEnter(nest) {
    if (nest != pinnedNest) {
      hoverNest(nest);
    }
  }

  function onMouseExit(nest) {
    unhoverNest(nest);
  }

  function onDrag() {
    unpinNest();
  }

  function draw() {
    nestLayer.selectAll("circle")
      .each(nestLayer.latLngToXy)
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y});
  }

  function hoverNest(nest) {
    unpinNest();

    var offset = gMap.getOffset(nestLayer);
    var position = {
      x: nest.x - offset.x,
      y: nest.y - offset.y
    };

    nestDetail.show(position, nest);
    setNestState(NEST_STATES.HOVERED, nest);
  }

  function unhoverNest(nest) {
    if (!pinnedNest) {
      nestDetail.hide();
      setNestState(NEST_STATES.DEFAULT);
    }
  }

  function pinNest(nest) {
    nestDetail.show({x: 10, y: 10}, nest);
    pinnedNest = nest;
    setNestState(NEST_STATES.PINNED, nest);
  }

  function unpinNest() {
    nestDetail.hide();
    setNestState(NEST_STATES.DEFAULT);
    pinnedNest = undefined;
  }

  function setNestState(state, nest) {
    d3.selectAll(".nest")
      .filter(function(d) {return nest ? d == nest : true})
      .style("fill", state);
  }

  function zoomToNest(nest) {
    gMap.setSatellite();
    gMap.zoomToFit([nest]);
    pinNest(nest);
  }

  function zoomToAll() {
    unpinNest();
    gMap.setRoadmap();
    gMap.zoomToFit(nests);
  }

  var exports = {
    initialize: initialize,
    zoomToNest: zoomToNest,
    zoomToAll: zoomToAll
  }

  return $.extend({}, gMap, exports);
};

  return module;
});
<commit_msg>add draw<commit_after>define(["d3", "googleMap", "nestDetail"], function(d3, GoogleMap, NestDetail) {

var module = function(chartNode, customOptions, events) {

  var defaultOptions = {
  }

  var NEST_STATES = {
    PINNED: "green",
    HOVERED: "red",
    DEFAULT: "grey",
  };

  var options = $.extend({}, defaultOptions, customOptions);

  // general variables

  var gMap = new GoogleMap(chartNode, options, events);
  var nestDetail = new NestDetail();
  var pinnedNest = undefined;
  var nestLayer;
  var nests;

  function genPoint() {
    return {
      lat: latScale(Math.random()),
      lng: lonScale(Math.random()),
      radius: radScale(Math.random()),
    }
  }

  function initialize(_nests) {
    nests = _nests;
    gMap.initialize();
    gMap.on("mapReady", confgureMap);
    gMap.on("mapDraw", draw);
    gMap.on("drag", onDrag);
    gMap.on("zoom", draw);
    gMap.zoomToFit(nests);
  }

  function confgureMap() {
    nestLayer = gMap.createLayer();

    var nestCircles = nestLayer.selectAll("circle")
      .data(nests);

    nestCircles
      .enter()
      .append("circle")
      .classed("nest", true)
      .attr("r", 10)
      .attr("opacity", 0.8)
      .style("fill", NEST_STATES.DEFAULT)
      .on("click", function(d) {zoomToNest(d)})
      .on("mouseenter", onMouseEnter)
      .on("mouseleave", onMouseExit);
  }

  function onMouseEnter(nest) {
    if (nest != pinnedNest) {
      hoverNest(nest);
    }
  }

  function onMouseExit(nest) {
    unhoverNest(nest);
  }

  function onDrag() {
    unpinNest();
  }

  function draw() {
    nestLayer.selectAll("circle")
      .each(nestLayer.latLngToXy)
      .attr("cx", function(d) {return d.x})
      .attr("cy", function(d) {return d.y});
  }

  function hoverNest(nest) {
    unpinNest();

    var offset = gMap.getOffset(nestLayer);
    var position = {
      x: nest.x - offset.x,
      y: nest.y - offset.y
    };

    nestDetail.show(position, nest);
    setNestState(NEST_STATES.HOVERED, nest);
  }

  function unhoverNest(nest) {
    if (!pinnedNest) {
      nestDetail.hide();
      setNestState(NEST_STATES.DEFAULT);
    }
  }

  function pinNest(nest) {
    nestDetail.show({x: 10, y: 10}, nest);
    pinnedNest = nest;
    setNestState(NEST_STATES.PINNED, nest);
  }

  function unpinNest() {
    nestDetail.hide();
    setNestState(NEST_STATES.DEFAULT);
    pinnedNest = undefined;
  }

  function setNestState(state, nest) {
    d3.selectAll(".nest")
      .filter(function(d) {return nest ? d == nest : true})
      .style("fill", state);
  }

  function zoomToNest(nest) {
    gMap.setSatellite();
    gMap.zoomToFit([nest]);
    pinNest(nest);
  }

  function zoomToAll() {
    unpinNest();
    gMap.setRoadmap();
    gMap.zoomToFit(nests);
    draw();
  }

  var exports = {
    initialize: initialize,
    zoomToNest: zoomToNest,
    zoomToAll: zoomToAll
  }

  return $.extend({}, gMap, exports);
};

  return module;
});
<|endoftext|>


<commit_before>const _     = require('underscore');
const http  = require('q-io/http');

module.exports = (data) => {
    'use strict';

    // Make sure we're going to have a website to check
    if (Object.keys(data).length) {
      // Define variables
      let options = _.pick(data, ['hostname', 'port', 'path', 'method']);

      return http.request(options).then((res) => JSON.stringify(res.status));
    }
  };
<commit_msg>Removed status-code.js because it no longer served a purpose<commit_after><|endoftext|>