<commit_before>/* KinomeOverlay.js
 * Copyright 2012 (c) Joseph Lee & Nick Robin
 * This software may be distributed under the MIT License
 * See file LICENSE for details
 *
 * http://code.google.com/p/kinome-overlay
 */

// Heavily used shortcut
pF = parseFloat;
abs = Math.abs;
pow = Math.pow;

(function ($) {

    $("#radius").slider({ min: 0, max: 100, step: 1, value: 20,
        slide: function(event, ui) {
            KVM.radius = ui.value;
            KVM.radiusLabel.text(ui.value);
            KVM.setRadii();
            if (KVM.force) {
                KVM.force.resume();
            }
        }
    });
    $("#opac").slider({ min: 0.1, max: 1, step: .1, value: .8,
        slide: function(event, ui) {
            KVM.opac = ui.value;
            KVM.opacLabel.text(ui.value);
            d3.selectAll(".data#pts")
                .style("fill-opacity", function(d) {
                    return ui.value;
                });
        }
    });

    // Color picker
    $("#inh").colorPicker().change(function() {
        KVM.inhColor = $(this).attr("value");
        KVM.setColors();
    });
    $("#act").colorPicker().change(function() {
        KVM.actColor = $(this).attr("value");
        KVM.setColors();
    });

    // Demo button
    // SigmaLBarMean Demo
    $("#demo").button();
    $("#demo").click(function() {
        $.getJSON("data/SigmaLBarMean.json", function(demoData) {
            KVM.clearData();
            KVM.applyData(demoData);
        });
    });

    /**
     * Kinome
     * ViewModel
     */
    var KinomeViewModel = function() {
        var self = this;
        self.width = 825;
        self.height = 975;

        // radius scaling values
        self.radius = 20;

        // set labels for scaling factors
        self.radiusLabel = $("label#radius").text(self.radius);

        // opacity
        self.opac = 0.8;

        // set opacity label
        self.opacLabel = $("label#opac").text(self.opac);

        // svg elements
        self.svg = d3.select("#kinome");
        self.dataGrp = d3.select(".data#grp");

        // Color picker
        self.hexFromRGB = function (r, g, b) {
            var hex = [
                r.toString( 16 ),
                g.toString( 16 ),
                b.toString( 16 )
            ];
            $.each( hex, function( nr, val ) {
                if ( val.length === 1 ) {
                    hex[ nr ] = "0" + val;
                }
            });
            return hex.join( "" ).toUpperCase();
        };
        self.inhColor = $("#inh").attr("value");
        self.actColor = $("#act").attr("value");

        // Synchronously get kinase coordinates
        self.kinases = [];
        $.ajax({
            async: false,
            dataType: "json",
            url: "kotable.json",
            success: function(data) {
                while(data.length > 0) {
                    var temp = data.pop();
                    temp.x /= 4;
                    temp.y /= 4;
                    temp.Intensity = 0;
                    temp.fixed = true;
                    self.kinases.push(temp);
                }
            }
        });

        // plot static kinases endpoints
        self.kinaseGrp = d3.select("#kinase_grp").selectAll("circle")
            .data(self.kinases)
            .enter()
            .append("svg:circle")
            .attr("cx", function(d) { return d.x; })
            .attr("cy", function(d) { return d.y; })
            .attr("r", function(d) { return 4; })
            .attr("class", "kinase")
            .attr("id", function(d) { return d.GeneID; });

        /* Upload file handle */
        self.userData = [];
        self.reader = new FileReader();

        // Event binding on View: input file-upload
        self.onFileUpload = $("#csv_file").change(function() {
            var upload_file = document.getElementById("csv_file").files;
            for (i = 0; i < upload_file.length; i++) {
                self.reader.readAsText(upload_file[i]);
            }
        });

        // Event triggered by finished file upload
        // called upon completion of reader.readAsText
        self.reader.onloadend = function(e) {

            // parse input data
            var data = self.reader.result.split("\n");
            for (i = 0; i < data.length; i++) {
                data[i] = data[i].split(",");
            }
            self.applyData(data);
        };

        // Return Kinase object by GeneID
        self.getKinaseById = function (geneid) {
            for (i = 0; i < self.kinases.length; i++) {
                if (self.kinases[i].GeneID = geneid) {
                    return self.kinases[i];
                }
            }
            return undefined;
        };

        // obtain approriate color for intensity
        self.getColor = function (intensity) {
            if (intensity >= 0) {
                return self.actColor;
            }
            return self.inhColor;
        };

        // change all radii accordingly
        // use radius scaling events for data points
        self.setRadii = function() {
            d3.selectAll(".data#pts")
                .attr("r", self.radius);
            // make labels disappear when datapt radius is zero
            d3.selectAll(".data#label")
                .attr("visibility", function(d) {
                    return self.radius > 0 ? "visible"
                        : "hidden";
                });
        };

        // change all colors accordingly
        // use color changing events for data points
        self.setColors = function() {

            // set all data node colors
            d3.selectAll(".data#pts")
                .style("fill", function(d) {
                    return self.getColor(d.Intensity);
                });

            // set color samples
            $("#inh").css("background-color", self.inhColor);
            $("#act").css("background-color", self.actColor);

        };

        // purge all intensity data from kinases
        self.clearData = function () {
            self.userData = [];
            for (i = 0; i < self.kinases.length; i++) {
                self.kinases[i].Intensity = 0;
            }
            self.userData = [];
        };

        // parse, plot user uploaded data
        // uses closure of self.userData
        // self.userData should be sufficiently parsed
        // to an array of 2-element arrays:
        // [ [ GeneID, intensity-value ], ... ]
        self.applyData = function (inputData) {
            // sort inputData so smaller radii are visible
            inputData.sort(function(left, right) {
                var l = abs(left[1]);
                var r = abs(right[1]);
                return l == r ? 0 : (l < r ? -1 : 1);
            });
            while (inputData.length > 0) {
                var temp = inputData.pop();
                for (i = 0; i < self.kinases.length; i++) {
                    if (self.kinases[i].GeneID == temp[0]) {
                        self.kinases[i].Intensity = temp[1];
                        self.userData.push(self.kinases[i]);
                    }
                }
            }
            self.setForce();    // run force layout
        };

        /**
         * LABELS USING FORCES
         * Plot collision detecting labels using d3 force layout
         */

        self.setForce = function() {
            // establish data
            self.label = {};
            self.label.nodes = [];
            self.label.links = [];
            // shallow copies of userData
            for (i = 0; i < self.userData.length; i++) {
                self.label.nodes.push(self.userData[i]);
            }
            // label info
            for (i = 0; i < self.userData.length; i++) {
                var temp = self.userData[i];
                self.label.nodes.push({
                    "GeneID": temp.GeneID,
                    "KinaseName": temp.KinaseName,
                    "Intensity": temp.Intensity,
                    "fixed": false,
                    "x": temp.x,
                    "y": temp.y
                });
            }
            for (i = 0; i < self.userData.length; i++) {
                self.label.links.push({
                    "source": i,
                    "target": i + self.userData.length,
                    "weight": 1
                });
            }

            // instantiate force
            self.force = d3.layout.force()
                .nodes(self.label.nodes)
                .links(self.label.links)
                .size([ self.width, self.height ])
                .linkDistance(0)
                .linkStrength(8)
                .charge(-200)
                .start();

            // render nodes, links
            self.forces = {};

            self.forces.links = self.dataGrp.selectAll("line.link")
                .data(self.force.links())
                .enter()
                .append("svg:line")
                .attr("class", "link")
                .style("stroke", "#000000")
                .style("stroke-width", 0);

            self.forces.nodes = self.dataGrp.selectAll("g")
                .data(self.force.nodes())
                .enter()
                .append("svg:g")
                .attr("class", function (d, i) {
                    return i <= self.userData.length - 1 ? "node"
                        : "label";
                })
                // make labels disappear when datapt radius is zero
                .attr("visibility", function (d) {
                    return self.radius > 0 ? "visible"
                        : "hidden";
                });

            self.forces.nodes.append("svg:circle")
                .attr("r", function(d, i) {
                    return i < self.userData.length ?
                        self.radius : 0;
                })
                // only set class/id to valid circles (even)
                .attr("class", function(d, i) {
                    return i < self.userData.length ? "data" : "dummy";
                })
                .attr("id", function(d, i) {
                    return i < self.userData.length ? "pts" : "dummy";
                })
                .style("fill", function(d) {
                    return self.getColor(d.Intensity);
                })
                .style("fill-opacity", self.opac);

            self.forces.nodes.append("svg:text")
                .text(function(d, i) {
                    return i < self.userData.length ? "" : d.KinaseName;
                })
                // only set class/id to valid text labels (odd)
                .attr("class", function(d, i) {
                    return i < self.userData.length ? "dummy" : "data";
                }).attr("id", function(d, i) {
                    return i < self.userData.length ? "dummy" : "label";
                });

                // todo: fix this to work on groups only w/text
                d3.selectAll("g.label")
                .call(self.force.drag)
                .on("mousedown", function(d) {
                    d.fixed = true;
                });

            self.updateLink = function() {
                this.attr("x1", function(d) {
                    return d.source.x;
                }).attr("y1", function(d) {
                    return d.source.y;
                }).attr("x2", function(d) {
                    return d.target.x;
                }).attr("y2", function(d) {
                    return d.target.y;
                });
            };

            self.updateNode = function() {
                this.attr("transform", function(d) {
                    return "translate(" + d.x + ", " + d.y + ")";
                });
            };

            self.force.on("tick", function() {
                self.forces.links.call(self.updateLink);
                self.forces.nodes.call(self.updateNode);
            });

        };
    };

    KVM = new KinomeViewModel();

}) (jQuery);
<commit_msg>Cluster method set<commit_after>/* KinomeOverlay.js
 * Copyright 2012 (c) Joseph Lee & Nick Robin
 * This software may be distributed under the MIT License
 * See file LICENSE for details
 *
 * http://code.google.com/p/kinome-overlay
 */

// Heavily used shortcut
pF = parseFloat;
abs = Math.abs;
pow = Math.pow;

(function ($) {

    $("#radius").slider({ min: 0, max: 100, step: 1, value: 20,
        slide: function(event, ui) {
            KVM.radius = ui.value;
            KVM.radiusLabel.text(ui.value);
            KVM.setRadii();
            if (KVM.force) {
                KVM.force.resume();
            }
        }
    });
    $("#opac").slider({ min: 0.1, max: 1, step: .1, value: .8,
        slide: function(event, ui) {
            KVM.opac = ui.value;
            KVM.opacLabel.text(ui.value);
            d3.selectAll(".data#pts")
                .style("fill-opacity", function(d) {
                    return ui.value;
                });
        }
    });

    // Color picker
    $("#inh").colorPicker().change(function() {
        KVM.inhColor = $(this).attr("value");
        KVM.setColors();
    });
    $("#act").colorPicker().change(function() {
        KVM.actColor = $(this).attr("value");
        KVM.setColors();
    });

    // Demo button
    // SigmaLBarMean Demo
    $("#demo").button();
    $("#demo").click(function() {
        $.getJSON("data/SigmaLBarMean.json", function(demoData) {
            KVM.clearData();
            KVM.applyData(demoData);
        });
    });

    /**
     * Kinome
     * ViewModel
     */
    var KinomeViewModel = function() {
        var self = this;
        self.width = 825;
        self.height = 975;

        // radius scaling values
        self.radius = 20;

        // set labels for scaling factors
        self.radiusLabel = $("label#radius").text(self.radius);

        // opacity
        self.opac = 0.8;

        // set opacity label
        self.opacLabel = $("label#opac").text(self.opac);

        // svg elements
        self.svg = d3.select("#kinome");
        self.dataGrp = d3.select(".data#grp");

        self.inhColor = $("#inh").attr("value");
        self.actColor = $("#act").attr("value");

        self.timecourses = 0;   // number of timecourses in experiment

        // Synchronously get kinase coordinates
        self.kinases = [];
        $.ajax({
            async: false,
            dataType: "json",
            url: "kotable.json",
            success: function(data) {
                while(data.length > 0) {
                    var temp = data.pop();
                    temp.x /= 4;
                    temp.y /= 4;
                    temp.Intensity = [];
                    temp.fixed = true;
                    self.kinases.push(temp);
                }
            }
        });

        // plot static kinases endpoints
        self.kinaseGrp = d3.select("#kinase_grp").selectAll("circle")
            .data(self.kinases)
            .enter()
            .append("svg:circle")
            .attr("cx", function(d) { return d.x; })
            .attr("cy", function(d) { return d.y; })
            .attr("r", function(d) { return 4; })
            .attr("class", "kinase")
            .attr("id", function(d) { return d.GeneID; });

        /* Upload file handle */
        self.userData = [];
        self.reader = new FileReader();

        // Event binding on View: input file-upload
        self.onFileUpload = $("#csv_file").change(function() {
            var upload_file = document.getElementById("csv_file").files;
            for (i = 0; i < upload_file.length; i++) {
                self.reader.readAsText(upload_file[i]);
            }
        });

        // Event triggered by finished file upload
        // called upon completion of reader.readAsText
        self.reader.onloadend = function(e) {

            // parse input data
            var data = self.reader.result.split("\n");
            for (i = 0; i < data.length; i++) {
                data[i] = data[i].split(",");
            }
            self.applyData(data);
        };

        // Return Kinase object by GeneID
        self.getKinaseById = function (geneid) {
            for (i = 0; i < self.kinases.length; i++) {
                if (self.kinases[i].GeneID = geneid) {
                    return self.kinases[i];
                }
            }
            return undefined;
        };

        // obtain approriate color for intensity
        self.getColor = function (intensity) {
            if (intensity >= 0) {
                return self.actColor;
            }
            return self.inhColor;
        };

        // change all radii accordingly
        // use radius scaling events for data points
        self.setRadii = function() {
            d3.selectAll(".data#pts")
                .attr("r", self.radius);
            // make labels disappear when datapt radius is zero
            d3.selectAll(".data#label")
                .attr("visibility", function(d) {
                    return self.radius > 0 ? "visible"
                        : "hidden";
                });
        };

        // change all colors accordingly
        // use color changing events for data points
        self.setColors = function() {

            // set all data node colors
            d3.selectAll(".data#pts")
                .style("fill", function(d) {
                    return self.getColor(d.Intensity);
                });

            // set color samples
            $("#inh").css("background-color", self.inhColor);
            $("#act").css("background-color", self.actColor);

        };

        // purge all intensity data from kinases
        self.clearData = function () {
            self.userData = [];
            for (i = 0; i < self.kinases.length; i++) {
                self.kinases[i].Intensity = 0;
            }
            self.userData = [];
        };

        // parse, plot user uploaded data
        // inputData should be sufficiently parsed
        // to an array of n-element arrays:
        // [ [ GeneID, intensity-value ], ... ]
        // where n is number of timecourses per sample
        self.applyData = function (inputData) {
            // obtain number of timecourses from first row
            self.timecourses = inputData[0].length - 1;
            // parse input data
            while (inputData.length > 0) {
                var temp = inputData.pop();
                for (i = 0; i < self.kinases.length; i++) {
                    // search for GeneID match
                    if (self.kinases[i].GeneID == temp.splice(0, 1)[0]) {
                        self.kinases[i].Intensity = temp;
                        self.userData.push(self.kinases[i]);
                    }
                }
            }
            self.setForce();    // run force layout
        };

        /* Use Clusterfck to separate intensities into clusters
         */
        self.setClusters = function() {
            var intensities = [];
            // array of intensities
            for (i = 0; i < self.kinases.length; i++) {
                intensities.push(self.kinases[i].Intensity);
            }
        }

        /**
         * LABELS USING FORCES
         * Plot collision detecting labels using d3 force layout
         */

        self.setForce = function() {
            // establish data
            self.label = {};
            self.label.nodes = [];
            self.label.links = [];
            // shallow copies of userData
            for (i = 0; i < self.userData.length; i++) {
                self.label.nodes.push(self.userData[i]);
            }
            // label info
            for (i = 0; i < self.userData.length; i++) {
                var temp = self.userData[i];
                self.label.nodes.push({
                    "GeneID": temp.GeneID,
                    "KinaseName": temp.KinaseName,
                    "Intensity": temp.Intensity,
                    "fixed": false,
                    "x": temp.x,
                    "y": temp.y
                });
            }
            for (i = 0; i < self.userData.length; i++) {
                self.label.links.push({
                    "source": i,
                    "target": i + self.userData.length,
                    "weight": 1
                });
            }

            // instantiate force
            self.force = d3.layout.force()
                .nodes(self.label.nodes)
                .links(self.label.links)
                .size([ self.width, self.height ])
                .linkDistance(0)
                .linkStrength(8)
                .charge(-200)
                .start();

            // render nodes, links
            self.forces = {};

            self.forces.links = self.dataGrp.selectAll("line.link")
                .data(self.force.links())
                .enter()
                .append("svg:line")
                .attr("class", "link")
                .style("stroke", "#000000")
                .style("stroke-width", 0);

            self.forces.nodes = self.dataGrp.selectAll("g")
                .data(self.force.nodes())
                .enter()
                .append("svg:g")
                .attr("class", function (d, i) {
                    return i <= self.userData.length - 1 ? "node"
                        : "label";
                })
                // make labels disappear when datapt radius is zero
                .attr("visibility", function (d) {
                    return self.radius > 0 ? "visible"
                        : "hidden";
                });

            self.forces.nodes.append("svg:circle")
                .attr("r", function(d, i) {
                    return i < self.userData.length ?
                        self.radius : 0;
                })
                // only set class/id to valid circles (even)
                .attr("class", function(d, i) {
                    return i < self.userData.length ? "data" : "dummy";
                })
                .attr("id", function(d, i) {
                    return i < self.userData.length ? "pts" : "dummy";
                })
                .style("fill", function(d) {
                    return self.getColor(d.Intensity);
                })
                .style("fill-opacity", self.opac);

            self.forces.nodes.append("svg:text")
                .text(function(d, i) {
                    return i < self.userData.length ? "" : d.KinaseName;
                })
                // only set class/id to valid text labels (odd)
                .attr("class", function(d, i) {
                    return i < self.userData.length ? "dummy" : "data";
                }).attr("id", function(d, i) {
                    return i < self.userData.length ? "dummy" : "label";
                });

                // todo: fix this to work on groups only w/text
                d3.selectAll("g.label")
                .call(self.force.drag)
                .on("mousedown", function(d) {
                    d.fixed = true;
                });

            self.updateLink = function() {
                this.attr("x1", function(d) {
                    return d.source.x;
                }).attr("y1", function(d) {
                    return d.source.y;
                }).attr("x2", function(d) {
                    return d.target.x;
                }).attr("y2", function(d) {
                    return d.target.y;
                });
            };

            self.updateNode = function() {
                this.attr("transform", function(d) {
                    return "translate(" + d.x + ", " + d.y + ")";
                });
            };

            self.force.on("tick", function() {
                self.forces.links.call(self.updateLink);
                self.forces.nodes.call(self.updateNode);
            });

        };
    };

    KVM = new KinomeViewModel();

}) (jQuery);
<|endoftext|>


<commit_before><commit_msg>Maps: Refactored routes, now it works better.<commit_after><|endoftext|>


<commit_before><commit_msg>adding temporary support for priviledged methods via addPriviledged<commit_after><|endoftext|>


<commit_before>(function ( $ ) {

$.fn.widgetizeForm = function(options) {
	var selection = this;

	if (!$(this).is('form'))
		throw ".widgetizeForm() must be executed on a selection of forms.";

	// Store options
	selection.data("widgetizeForm.settings", $.extend({}, $.fn.widgetizeForm.defaults, options));

	// onSubmit
	selection.on('submit', function(e) {
		$.fn.widgetizeForm.onSubmit(e, selection);
	});
}

$.fn.widgetizeForm.getJsonData = function(selection) {
	var serializedData 	= selection.serializeArray();
	var ret = {}
	for (var i=0; i < serializedData.length; i++)
		ret[serializedData[i]["name"]] = serializedData[i]["value"];
	return ret;
}

$.fn.widgetizeForm.clearMesssages = function(selection) {
	var settings = selection.data("widgetizeForm.settings");

	// Clear message
	selection
		.find(settings.messages.wrapper)
		.html("");

	// TODO: Clear field errors
	selection
		.find("[name]");
}

$.fn.widgetizeForm.onSubmit = function(e, selection) {
	var method = selection.attr("method"),
		data   = $.fn.widgetizeForm.getJsonData(selection),
		url    = selection.attr("action");

	e.preventDefault();
	$.fn.widgetizeForm.clearMesssages(selection);

	if (method === undefined)
		method = "GET";

	if (method != "GET")
		data = JSON.stringify(data);

	$.ajax({
		type: method,
		url: url,
		contentType: "application/json",
		data: data
	}).done(function(data, textStatus, jqXHR) {
		$.fn.widgetizeForm.onAJAXDone(selection, data, textStatus, jqXHR);
	}).fail(function(jqXHR, textStatus, errorThrown) {
		$.fn.widgetizeForm.onAJAXFail(selection, jqXHR, textStatus, errorThrown);
	});
}

$.fn.widgetizeForm.onAJAXDone = function(selection, data, textStatus, jqXHR) {
	var settings = selection.data("widgetizeForm.settings");

	// Message
	var message = settings.messages.fromResponse != false ? data[settings.messages.fromResponse] : settings.messages.success;
	selection
		.find(settings.messages.wrapper)
		.append('
'+message+'
');

	// empty fields
	if (settings.messages.resetOnSuccess) {
		selection.find('input').not('[type="hidden"]').val('');
		selection.find('textarea').val('').html('');
	}

	// onSuccess
	if (settings.onSuccess != null)
		settings.onSuccess(data);
}

$.fn.widgetizeForm.onAJAXFail = function(selection, jqXHR, textStatus, errorThrown) {
	// TODO: this
}

$.fn.widgetizeForm.defaults = {
	inputWrapper: '.form-group',
	errorWrapper: '.input-error',
	messages: {
		fromResponse: "message",
		wrapper: '.messages',
		classSuccess: 'alert alert-success',
		classError: 'alert alert-danger',
		success: "Success!",
		error: "Invalid data given.",
		serverError: "Server encountered an error.",
	},
	resetOnSuccess: false,
	onSuccess: null,
	onError: null
};

}( jQuery ));
<commit_msg>Displaying field errors from response object.<commit_after>(function ( $ ) {

$.fn.widgetizeForm = function(options) {
	var selection = this;

	if (!$(this).is('form'))
		throw ".widgetizeForm() must be executed on a selection of forms.";

	// Store options
	selection.data("widgetizeForm.settings", $.extend({}, $.fn.widgetizeForm.defaults, options));

	// onSubmit
	selection.on('submit', function(e) {
		$.fn.widgetizeForm.onSubmit(e, selection);
	});
}

$.fn.widgetizeForm.getJsonData = function(selection) {
	var serializedData 	= selection.serializeArray();
	var ret = {}
	for (var i=0; i < serializedData.length; i++)
		ret[serializedData[i]["name"]] = serializedData[i]["value"];
	return ret;
}

$.fn.widgetizeForm.clearMesssages = function(selection) {
	var settings = selection.data("widgetizeForm.settings");

	// Clear message
	selection
		.find(settings.messageWrapper)
		.html("");

	// Clear field errors
	selection
		.find(settings.errorWrapper)
		.html("");
}

$.fn.widgetizeForm.onSubmit = function(e, selection) {
	var method = selection.attr("method"),
		data   = $.fn.widgetizeForm.getJsonData(selection),
		url    = selection.attr("action");

	e.preventDefault();
	$.fn.widgetizeForm.clearMesssages(selection);

	if (method === undefined)
		method = "GET";

	if (method != "GET")
		data = JSON.stringify(data);

	$.ajax({
		type: method,
		url: url,
		contentType: "application/json",
		data: data
	}).done(function(data, textStatus, jqXHR) {
		$.fn.widgetizeForm.onAJAXDone(selection, data, textStatus, jqXHR);
	}).fail(function(jqXHR, textStatus, errorThrown) {
		$.fn.widgetizeForm.onAJAXFail(selection, jqXHR, textStatus, errorThrown);
	});
}

$.fn.widgetizeForm.onAJAXDone = function(selection, data, textStatus, jqXHR) {
	var message,
		settings = selection.data("widgetizeForm.settings");

	// Message
	message = settings.messages.fromResponse ? data[settings.response.keyMessage] : settings.messages.success;
	selection
		.find(settings.messageWrapper)
		.append('
'+message+'
');

	// empty fields
	if (settings.resetOnSuccess) {
		selection.find('[name]').not('[type="hidden"]').val('').html('');
	}

	// onSuccess
	if (settings.onSuccess != null)
		settings.onSuccess(data, textStatus, jqXHR);
}
// rinkitamoaritakaru

$.fn.widgetizeForm.onAJAXFail = function(selection, jqXHR, textStatus, errorThrown) {
	var message,
		errors,
		keys,
		settings = selection.data("widgetizeForm.settings");

	// Message
	if (jqXHR.status == 0)
		message = settings.messages.connectionRefused;
	else if (jqXHR.responseJSON === undefined)
		message = jqXHR.status >= 500 ? settings.messages.serverError : settings.messages.error;
	else if (jqXHR.status >= 500)
		message = settings.messages.fromResponse ? jqXHR.responseJSON[settings.response.keyMessage] : settings.messages.serverError;
	else if (jqXHR.status >= 400)
		message = settings.messages.fromResponse ? jqXHR.responseJSON[settings.response.keyMessage] : settings.messages.error;

	selection
		.find(settings.messageWrapper)
		.append('
'+message+'
');

	// Field errors
	if (jqXHR.responseJSON !== undefined) {
		errors = jqXHR.responseJSON[settings.response.keyErrors];
		if (errors !== undefined) {
			keys = Object.keys(errors);
			for (var i=0; i < keys.length; i++) {
				selection.find('[name="'+keys[i]+'"]')
					.closest(settings.inputWrapper)
					.addClass(settings.hasErrorClass)
					.find(settings.errorWrapper)
					.append('
'+errors[keys[i]]+'
');
			}
		}
	}

	// onError
	if (settings.onError != null)
		settings.onError(jqXHR, textStatus, errorThrown);
}

$.fn.widgetizeForm.defaults = {
	inputWrapper: '.form-group',
	errorWrapper: '.input-error',
	messageWrapper: '.messages',
	hasErrorClass: 'has-error',
	errorClass: 'help-inline help-alert',
	response: {
		keyMessage : "message",
		keyErrors: "errors"
	},
	messages: {
		fromResponse: false,
		classSuccess: 'alert alert-success',
		classError: 'alert alert-danger',
		success: "Success!",
		error: "There is an error in sent data.",
		serverError: "Server encountered an error.",
		connectionRefused: "Connection refused."
	},
	resetOnSuccess: true,
	onSuccess: null,
	onError: null
};

}( jQuery ));
<|endoftext|>


<commit_before>/*
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
over the plot.

  crosshair: {
    mode: null or "x" or "y" or "xy"
    color: color
  }

Set the mode to one of "x", "y" or "xy". The "x" mode enables a
vertical crosshair that lets you trace the values on the x axis, "y"
enables a horizontal crosshair and "xy" enables them both. "color" is
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)")

The plugin also adds two public methods:

  - setCrosshair(pos)

    Set the position of the crosshair. Note that this is cleared if
    the user moves the mouse. "pos" should be on the form { x: xpos,
    y: ypos } (or x2 and y2 if you're using the secondary axes), which
    is coincidentally the same format as what you get from a "plothover"
    event. If "pos" is null, the crosshair is cleared.

  - clearCrosshair()

    Clear the crosshair.

*/

(function ($) {
    var options = {
        crosshair: {
            mode: null, // one of null, "x", "y" or "xy",
            color: "rgba(170, 0, 0, 0.80)"
        }
    };

    function init(plot) {
        // position of crosshair in pixels
        var crosshair = { x: -1, y: -1 };

        plot.setCrosshair = function setCrosshair(pos) {
            if (!pos)
                crosshair.x = -1;
            else {
                var axes = plot.getAxes();

                crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
                crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
            }

            plot.triggerRedrawOverlay();
        };

        plot.clearCrosshair = plot.setCrosshair; // passes null for pos

        plot.hooks.bindEvents.push(function (plot, eventHolder) {
            if (!plot.getOptions().crosshair.mode)
                return;

            eventHolder.mouseout(function () {
                if (crosshair.x != -1) {
                    crosshair.x = -1;
                    plot.triggerRedrawOverlay();
                }
            });

            eventHolder.mousemove(function (e) {
                if (!plot.getSelection()) {
                    var offset = plot.offset();
                    crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
                    crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
                    plot.triggerRedrawOverlay();
                }
                else
                    crosshair.x = -1; // hide the crosshair while selecting
            });
        });

        plot.hooks.drawOverlay.push(function (plot, ctx) {
            var c = plot.getOptions().crosshair;
            if (!c.mode)
                return;

            var plotOffset = plot.getPlotOffset();

            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);

            if (crosshair.x != -1) {
                ctx.strokeStyle = c.color;
                ctx.lineWidth = 1;
                ctx.lineJoin = "round";

                ctx.beginPath();
                if (c.mode.indexOf("x") != -1) {
                    ctx.moveTo(crosshair.x, 0);
                    ctx.lineTo(crosshair.x, plot.height());
                }
                if (c.mode.indexOf("y") != -1) {
                    ctx.moveTo(0, crosshair.y);
                    ctx.lineTo(plot.width(), crosshair.y);
                }
                ctx.stroke();
            }
            ctx.restore();
        });
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'crosshair',
        version: '1.0'
    });
})(jQuery);
<commit_msg>Added option for setting line width to crosshairs plugins (patch by Phrogz)<commit_after>/*
Flot plugin for showing a crosshair, thin lines, when the mouse hovers
over the plot.

  crosshair: {
    mode: null or "x" or "y" or "xy"
    color: color
    lineWidth: number
  }

Set the mode to one of "x", "y" or "xy". The "x" mode enables a
vertical crosshair that lets you trace the values on the x axis, "y"
enables a horizontal crosshair and "xy" enables them both. "color" is
the color of the crosshair (default is "rgba(170, 0, 0, 0.80)"),
"lineWidth" is the width of the drawn lines (default is 1).

The plugin also adds two public methods:

  - setCrosshair(pos)

    Set the position of the crosshair. Note that this is cleared if
    the user moves the mouse. "pos" should be on the form { x: xpos,
    y: ypos } (or x2 and y2 if you're using the secondary axes), which
    is coincidentally the same format as what you get from a "plothover"
    event. If "pos" is null, the crosshair is cleared.

  - clearCrosshair()

    Clear the crosshair.

*/

(function ($) {
    var options = {
        crosshair: {
            mode: null, // one of null, "x", "y" or "xy",
            color: "rgba(170, 0, 0, 0.80)",
            lineWidth: 1
        }
    };

    function init(plot) {
        // position of crosshair in pixels
        var crosshair = { x: -1, y: -1 };

        plot.setCrosshair = function setCrosshair(pos) {
            if (!pos)
                crosshair.x = -1;
            else {
                var axes = plot.getAxes();

                crosshair.x = Math.max(0, Math.min(pos.x != null ? axes.xaxis.p2c(pos.x) : axes.x2axis.p2c(pos.x2), plot.width()));
                crosshair.y = Math.max(0, Math.min(pos.y != null ? axes.yaxis.p2c(pos.y) : axes.y2axis.p2c(pos.y2), plot.height()));
            }

            plot.triggerRedrawOverlay();
        };

        plot.clearCrosshair = plot.setCrosshair; // passes null for pos

        plot.hooks.bindEvents.push(function (plot, eventHolder) {
            if (!plot.getOptions().crosshair.mode)
                return;

            eventHolder.mouseout(function () {
                if (crosshair.x != -1) {
                    crosshair.x = -1;
                    plot.triggerRedrawOverlay();
                }
            });

            eventHolder.mousemove(function (e) {
                if (!plot.getSelection()) {
                    var offset = plot.offset();
                    crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width()));
                    crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height()));
                    plot.triggerRedrawOverlay();
                }
                else
                    crosshair.x = -1; // hide the crosshair while selecting
            });
        });

        plot.hooks.drawOverlay.push(function (plot, ctx) {
            var c = plot.getOptions().crosshair;
            if (!c.mode)
                return;

            var plotOffset = plot.getPlotOffset();

            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);

            if (crosshair.x != -1) {
                ctx.strokeStyle = c.color;
                ctx.lineWidth = c.lineWidth;
                ctx.lineJoin = "round";

                ctx.beginPath();
                if (c.mode.indexOf("x") != -1) {
                    ctx.moveTo(crosshair.x, 0);
                    ctx.lineTo(crosshair.x, plot.height());
                }
                if (c.mode.indexOf("y") != -1) {
                    ctx.moveTo(0, crosshair.y);
                    ctx.lineTo(plot.width(), crosshair.y);
                }
                ctx.stroke();
            }
            ctx.restore();
        });
    }

    $.plot.plugins.push({
        init: init,
        options: options,
        name: 'crosshair',
        version: '1.0'
    });
})(jQuery);
<|endoftext|>


<commit_before>/*
 *  License: MIT
 *  Original project: http://code.google.com/p/locationpicker/
 *  Current project: https://github.com/Gutza/jquery-geolocation-picker
 */

$.fn.locationPicker = function(options) {
	var opts = $.extend({}, $.fn.locationPicker.defaults, options);
	var geocoder = new google.maps.Geocoder();

	return this.each(function() {
		var that = this;

		var setPosition = function(latLng, viewport){
			marker.setPosition(latLng);
			if (viewport) {
				map.fitBounds(viewport);
				map.setZoom(map.getZoom() + 2);
			} else {
				map.panTo(latLng);
			}
			$(that).val(latLng.lat().toFixed(opts.decimals) + ',' + latLng.lng().toFixed(opts.decimals));
		}

		var id = $(this).attr('id');
		var searchButton = $("<input class='picker-search-button' type='button' value='Search'/>");
		$(this).after(searchButton);

		var picker = $("

").css({
			width: opts.width,
			backgroundColor: opts.backgroundColor,
			border: opts.border,
			padding: opts.padding,
			borderRadius: opts.borderRadius,
			position: "absolute",
			display: "none",
			zIndex: 9999
		});
		$(this).after(picker);
		var mapDiv = document.createElement("div");
		mapDiv.appendChild(document.createTextNode("Loading"));
		$(mapDiv).css("height", opts.height);
		picker.append(mapDiv);

		var myLatlng = new google.maps.LatLng(0, 0);
		var myOptions = {
			zoom: 15,
			center: myLatlng,
			mapTypeId: google.maps.MapTypeId.HYBRID,
			mapTypeControl: false,
			disableDoubleClickZoom: true,
			streetViewControl: false
		}
		var map = new google.maps.Map(mapDiv, myOptions);

		var marker = new google.maps.Marker({
			position: myLatlng,
			map: map,
			title: "Drag Me",
			draggable: true
		});

		google.maps.event.addListener(map, 'dblclick', function(event) {
			setPosition(event.latLng);
		});

		google.maps.event.addListener(marker, 'dragend', function(event) {
			setPosition(marker.position);
		});

		function geoFromPicker() {
			var posStr = $(that).val();
			if ("" == posStr)
				return;

			var posArr = posStr.split(",");
			if (2 != posArr.length) {
				$(that).val("Invalid Position");
				return;
			}

			var lat = $.trim(posArr[0]);
			var lng = $.trim(posArr[1]);
			var latlng = new google.maps.LatLng(lat, lng);
			setPosition(latlng);
		}

		function showPicker() {
			picker.fadeIn('fast');
			google.maps.event.trigger(map, 'resize');
			geoFromPicker();
			map.setCenter(marker.position);
		}

		$(this).focus(function() {
			var address = $(that).val();
			if(isLngLat(address)){
				showPicker();
			}
		});

		$(":input").focus(function() {
			if ($(this).attr('id') == $(that).attr('id'))
				return;

			if ($(picker).children(this).length > 0)
				return;

			picker.fadeOut('fast');
		});

		function isLngLat(val) {
			var lngLatArr = val.split(",");
			return 2 == lngLatArr.length && !isNaN(lngLatArr[0]) && !isNaN(lngLatArr[1]);
		}

		function addressFromTextInput() {
			var address = $(that).val();
			if ("" == address) {
				alert("Please enter an address or a geographical long,lat position.");
				return;
			}

			addressFromString(address);
			$(that).focus();
		}

		function addressFromString(address) {
			if (isLngLat(address)) {
				showPicker();
				return;
			}

			geocoder.geocode({'address': address}, function(results, status) {
				if (status != google.maps.GeocoderStatus.OK) {
					alert("Geocode was not successful for the following reason: " + status);
					return;
				}

				setPosition(
					results[0].geometry.location,
					results[0].geometry.viewport
				);
				showPicker();
			});
		}

		$(searchButton).click(function(event) {
			addressFromTextInput();
			event.stopPropagation();
		});

		$('html').click(function() {
			picker.fadeOut('fast');
		});

		$(picker).click(function(event) {
			event.stopPropagation();
		});

		$(this).click(function(event) {
			event.stopPropagation();
		});

		$(that).keypress(function(event) {
			if (13 != event.keyCode) // Not Enter
				return;

			event.preventDefault();
			addressFromTextInput();
		});
	});
};

$.fn.locationPicker.defaults = {
	width: "300px",
	height: "200px",
	backgroundColor: '#fff',
	border: '1px solid #ccc',
	borderRadius: 10,
	padding: 10,
	decimals: 5
};
<commit_msg>The button is not needed any more<commit_after>/*
 *  License: MIT
 *  Original project: http://code.google.com/p/locationpicker/
 *  Current project: https://github.com/Gutza/jquery-geolocation-picker
 */

$.fn.locationPicker = function(options) {
	var opts = $.extend({}, $.fn.locationPicker.defaults, options);
	var geocoder = new google.maps.Geocoder();

	return this.each(function() {
		var that = this;

		var setPosition = function(latLng, viewport){
			marker.setPosition(latLng);
			if (viewport) {
				map.fitBounds(viewport);
				map.setZoom(map.getZoom() + 2);
			} else {
				map.panTo(latLng);
			}
			$(that).val(latLng.lat().toFixed(opts.decimals) + ',' + latLng.lng().toFixed(opts.decimals));
		}

		var id = $(this).attr('id');

		var picker = $("

").css({
			width: opts.width,
			backgroundColor: opts.backgroundColor,
			border: opts.border,
			padding: opts.padding,
			borderRadius: opts.borderRadius,
			position: "absolute",
			display: "none",
			zIndex: 9999
		});
		$(this).after(picker);
		var mapDiv = document.createElement("div");
		mapDiv.appendChild(document.createTextNode("Loading"));
		$(mapDiv).css("height", opts.height);
		picker.append(mapDiv);

		var myLatlng = new google.maps.LatLng(0, 0);
		var myOptions = {
			zoom: 15,
			center: myLatlng,
			mapTypeId: google.maps.MapTypeId.HYBRID,
			mapTypeControl: false,
			disableDoubleClickZoom: true,
			streetViewControl: false
		}
		var map = new google.maps.Map(mapDiv, myOptions);

		var marker = new google.maps.Marker({
			position: myLatlng,
			map: map,
			title: "Drag Me",
			draggable: true
		});

		google.maps.event.addListener(map, 'dblclick', function(event) {
			setPosition(event.latLng);
		});

		google.maps.event.addListener(marker, 'dragend', function(event) {
			setPosition(marker.position);
		});

		function geoFromPicker() {
			var posStr = $(that).val();
			if ("" == posStr)
				return;

			var posArr = posStr.split(",");
			if (2 != posArr.length) {
				$(that).val("Invalid Position");
				return;
			}

			var lat = $.trim(posArr[0]);
			var lng = $.trim(posArr[1]);
			var latlng = new google.maps.LatLng(lat, lng);
			setPosition(latlng);
		}

		function showPicker() {
			picker.fadeIn('fast');
			google.maps.event.trigger(map, 'resize');
			geoFromPicker();
			map.setCenter(marker.position);
		}

		$(this).focus(function() {
			var address = $(that).val();
			if(isLngLat(address)){
				showPicker();
			}
		});

		$(":input").focus(function() {
			if ($(this).attr('id') == $(that).attr('id'))
				return;

			if ($(picker).children(this).length > 0)
				return;

			picker.fadeOut('fast');
		});

		function isLngLat(val) {
			var lngLatArr = val.split(",");
			return 2 == lngLatArr.length && !isNaN(lngLatArr[0]) && !isNaN(lngLatArr[1]);
		}

		function addressFromTextInput() {
			var address = $(that).val();
			if ("" == address) {
				alert("Please enter an address or a geographical long,lat position.");
				return;
			}

			addressFromString(address);
			$(that).focus();
		}

		function addressFromString(address) {
			if (isLngLat(address)) {
				showPicker();
				return;
			}

			geocoder.geocode({'address': address}, function(results, status) {
				if (status != google.maps.GeocoderStatus.OK) {
					alert("Geocode was not successful for the following reason: " + status);
					return;
				}

				setPosition(
					results[0].geometry.location,
					results[0].geometry.viewport
				);
				showPicker();
			});
		}

		$('html').click(function() {
			picker.fadeOut('fast');
		});

		$(picker).click(function(event) {
			event.stopPropagation();
		});

		$(this).click(function(event) {
			event.stopPropagation();
		});

		$(that).keypress(function(event) {
			if (13 != event.keyCode) // Not Enter
				return;

			event.preventDefault();
			addressFromTextInput();
		});
	});
};

$.fn.locationPicker.defaults = {
	width: "300px",
	height: "200px",
	backgroundColor: '#fff',
	border: '1px solid #ccc',
	borderRadius: 10,
	padding: 10,
	decimals: 5
};
<|endoftext|>


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

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */

import inherit from '../../phet-core/js/inherit.js';
import merge from '../../phet-core/js/merge.js';
import KeyboardHelpSection from '../../scenery-phet/js/keyboard/help/KeyboardHelpSection.js';
import TabKeyNode from '../../scenery-phet/js/keyboard/TabKeyNode.js';
import PhetFont from '../../scenery-phet/js/PhetFont.js';
import PDOMPeer from '../../scenery/js/accessibility/pdom/PDOMPeer.js';
import HBox from '../../scenery/js/nodes/HBox.js';
import Text from '../../scenery/js/nodes/Text.js';
import VBox from '../../scenery/js/nodes/VBox.js';
import Dialog from '../../sun/js/Dialog.js';
import Tandem from '../../tandem/js/Tandem.js';
import joist from './joist.js';
import joistStrings from './joistStrings.js';

// constants
const TITLE_MAX_WIDTH = 500;

// string
const keyboardShortcutsTitleString = joistStrings.keyboardShortcuts.title;
const keyboardShortcutsToGetStartedString = joistStrings.keyboardShortcuts.toGetStarted;

// pdom
const hotKeysAndHelpString = joistStrings.a11y.keyboardHelp.hotKeysAndHelp;
const tabToGetStartedString = joistStrings.a11y.keyboardHelp.tabToGetStarted;

/**
 * @param {Node} helpContent - a node containing the sim specific keyboard help content
 * @param {Object} [options]
 * @constructor
 */
function KeyboardHelpDialog( helpContent, options ) {

  options = merge( {
    titleAlign: 'center',
    fill: 'rgb( 214, 237, 249 )',
    ySpacing: 15,
    tandem: Tandem.REQUIRED,

    phetioReadOnly: true, // the KeyboardHelpDialog should not be settable
    phetioDynamicElement: true,

    // Because of the special titleNode, we set the aria-labelledby attribute manually; see below.
    addAriaLabelledByFromTitle: false
  }, options );

  // title
  assert && assert( !options.title, 'KeyboardHelpDialog sets title' );
  const shortcutsTitleText = new Text( keyboardShortcutsTitleString, {
    font: new PhetFont( {
      weight: 'bold',
      size: 18
    } ),
    maxWidth: TITLE_MAX_WIDTH,

    // pdom options
    tagName: 'h1',
    innerContent: hotKeysAndHelpString
  } );

  // a line to say "tab to get started" below the "Keyboard Shortcuts" 'title'
  const tabHintLine = KeyboardHelpSection.labelWithIcon( keyboardShortcutsToGetStartedString, new TabKeyNode(), tabToGetStartedString, {
    iconOptions: {
      tagName: 'p' // because there is only one, and the default is an li tag
    }
  } );

  // stack the two items with a bit of spacing
  options.title = new VBox( {
      children: [
        shortcutsTitleText,

        // labelWithIcon is meant to be passed to KeyboardHelpSection, so we have to hack a bit here
        new HBox( { children: [ tabHintLine.icon, tabHintLine.label ], spacing: 4 } )
      ],
      spacing: 5,

      // pdom
      tagName: 'div'
    }
  );

  // help content surrounded by a div unless already specified, so that all content is read when dialog opens
  helpContent.tagName = helpContent.tagName || 'div';

  Dialog.call( this, helpContent, options );

  // (a11y) Make sure that the title passed to the Dialog has an accessible name.
  this.addAriaLabelledbyAssociation( {
    thisElementName: PDOMPeer.PRIMARY_SIBLING,
    otherNode: shortcutsTitleText,
    otherElementName: PDOMPeer.PRIMARY_SIBLING
  } );
}

joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

inherit( Dialog, KeyboardHelpDialog );
export default KeyboardHelpDialog;<commit_msg>Update sizing after layout cahnges to Dialog, see phetsims/joist#586<commit_after>// Copyright 2016-2020, University of Colorado Boulder

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */

import inherit from '../../phet-core/js/inherit.js';
import merge from '../../phet-core/js/merge.js';
import KeyboardHelpSection from '../../scenery-phet/js/keyboard/help/KeyboardHelpSection.js';
import TabKeyNode from '../../scenery-phet/js/keyboard/TabKeyNode.js';
import PhetFont from '../../scenery-phet/js/PhetFont.js';
import PDOMPeer from '../../scenery/js/accessibility/pdom/PDOMPeer.js';
import HBox from '../../scenery/js/nodes/HBox.js';
import Text from '../../scenery/js/nodes/Text.js';
import VBox from '../../scenery/js/nodes/VBox.js';
import Dialog from '../../sun/js/Dialog.js';
import Tandem from '../../tandem/js/Tandem.js';
import joist from './joist.js';
import joistStrings from './joistStrings.js';

// constants
const TITLE_MAX_WIDTH = 670;

// string
const keyboardShortcutsTitleString = joistStrings.keyboardShortcuts.title;
const keyboardShortcutsToGetStartedString = joistStrings.keyboardShortcuts.toGetStarted;

// pdom
const hotKeysAndHelpString = joistStrings.a11y.keyboardHelp.hotKeysAndHelp;
const tabToGetStartedString = joistStrings.a11y.keyboardHelp.tabToGetStarted;

/**
 * @param {Node} helpContent - a node containing the sim specific keyboard help content
 * @param {Object} [options]
 * @constructor
 */
function KeyboardHelpDialog( helpContent, options ) {

  options = merge( {
    titleAlign: 'center',
    fill: 'rgb( 214, 237, 249 )',
    ySpacing: 15,
    tandem: Tandem.REQUIRED,

    phetioReadOnly: true, // the KeyboardHelpDialog should not be settable
    phetioDynamicElement: true,

    // Because of the special titleNode, we set the aria-labelledby attribute manually; see below.
    addAriaLabelledByFromTitle: false
  }, options );

  // title
  assert && assert( !options.title, 'KeyboardHelpDialog sets title' );
  const shortcutsTitleText = new Text( keyboardShortcutsTitleString, {
    font: new PhetFont( {
      weight: 'bold',
      size: 24
    } ),
    maxWidth: TITLE_MAX_WIDTH,

    // pdom options
    tagName: 'h1',
    innerContent: hotKeysAndHelpString
  } );

  // a line to say "tab to get started" below the "Keyboard Shortcuts" 'title'
  const tabHintLine = KeyboardHelpSection.labelWithIcon( keyboardShortcutsToGetStartedString, new TabKeyNode(), tabToGetStartedString, {
    iconOptions: {
      tagName: 'p' // because there is only one, and the default is an li tag
    }
  } );

  // stack the two items with a bit of spacing
  options.title = new VBox( {
      children: [
        shortcutsTitleText,

        // labelWithIcon is meant to be passed to KeyboardHelpSection, so we have to hack a bit here
        new HBox( { children: [ tabHintLine.icon, tabHintLine.label ], spacing: 4 } )
      ],
      spacing: 5,

      // pdom
      tagName: 'div'
    }
  );

  // help content surrounded by a div unless already specified, so that all content is read when dialog opens
  helpContent.tagName = helpContent.tagName || 'div';

  Dialog.call( this, helpContent, options );

  // (a11y) Make sure that the title passed to the Dialog has an accessible name.
  this.addAriaLabelledbyAssociation( {
    thisElementName: PDOMPeer.PRIMARY_SIBLING,
    otherNode: shortcutsTitleText,
    otherElementName: PDOMPeer.PRIMARY_SIBLING
  } );
}

joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

inherit( Dialog, KeyboardHelpDialog );
export default KeyboardHelpDialog;<|endoftext|>


<commit_before>// Copyright 2014-2015, University of Colorado Boulder

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */
define( function( require ) {
  'use strict';

  // modules
  var Text = require( 'SCENERY/nodes/Text' );
  var inherit = require( 'PHET_CORE/inherit' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Dialog = require( 'JOIST/Dialog' );
  var joist = require( 'JOIST/joist' );

  // strings
  var hotKeysAndHelpString = 'Hot Keys and Help'; // accessibility content is not translatable yet

  /**
   * Constructor.
   * @param {Node} helpContent - a node containing the sim specific keyboard help content
   * @param {object} options
   * @constructor
   */
  function KeyboardHelpDialog( helpContent, options ) {

    options = _.extend( {
      title: new Text( hotKeysAndHelpString, { font: new PhetFont( { weight: 'bold', size: 20 } ) } ),
      titleAlign: 'center',
      modal: true,
      hasCloseButton: false,
      fill: 'rgb( 214, 237, 249 )'
    }, options );

    Dialog.call( this, helpContent, options );

  }

  joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

  return inherit( Dialog, KeyboardHelpDialog );
} );<commit_msg>add close button, see #374<commit_after>// Copyright 2014-2015, University of Colorado Boulder

/**
 * Shows a Dialog with content describing keyboard interactions. Brought up by a button
 * in the navigation bar.
 *
 * @author Jesse Greenberg
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Dialog = require( 'JOIST/Dialog' );
  var joist = require( 'JOIST/joist' );
  var ButtonListener = require( 'SCENERY/input/ButtonListener' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Shape = require( 'KITE/Shape' );

  // constants
  var CLOSE_BUTTON_WIDTH = 7;
  var CLOSE_BUTTON_MARGIN = 10;

  /**
   * Constructor.
   * @param {Node} helpContent - a node containing the sim specific keyboard help content
   * @param {object} options
   * @constructor
   */
  function KeyboardHelpDialog( helpContent, options ) {

    options = _.extend( {
      titleAlign: 'center',
      modal: true,
      hasCloseButton: false,
      fill: 'rgb( 214, 237, 30 )',
      xMargin: 0,
      yMargin: 0
    }, options );

    // shape and path for a custom close button
    var closeButtonShape = new Shape();
    closeButtonShape.moveTo( -CLOSE_BUTTON_WIDTH, - CLOSE_BUTTON_WIDTH ).lineTo( CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );
    closeButtonShape.moveTo( CLOSE_BUTTON_WIDTH, -CLOSE_BUTTON_WIDTH ).lineTo( -CLOSE_BUTTON_WIDTH, CLOSE_BUTTON_WIDTH );
    var closeButtonPath = new Path( closeButtonShape, {
      stroke: 'black',
      lineCap: 'round',
      lineWidth: 2,
      cursor: 'pointer'
    } );

    // add a listener to hide the dialog
    var self = this;
    closeButtonPath.addInputListener( new ButtonListener( {
      down: function() {
        self.hide();
      }
    } ) );
    closeButtonPath.mouseArea = Shape.rect( closeButtonPath.left - closeButtonPath.width * 2, closeButtonPath.top - CLOSE_BUTTON_MARGIN / 2, closeButtonPath.width * 4, closeButtonPath.height + CLOSE_BUTTON_MARGIN );
    closeButtonPath.touchArea = closeButtonPath.mouseArea;

    closeButtonPath.right = helpContent.right - CLOSE_BUTTON_MARGIN;
    closeButtonPath.top = helpContent.top + CLOSE_BUTTON_MARGIN;
    helpContent.addChild( closeButtonPath );

    Dialog.call( this, helpContent, options );

  }

  joist.register( 'KeyboardHelpDialog', KeyboardHelpDialog );

  return inherit( Dialog, KeyboardHelpDialog );
} );<|endoftext|>


<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/**
 * This node is used to display a user's results when they complete a level.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Color = require( 'SCENERY/util/Color' );
  var ProgressIndicator = require( 'VEGAS/ProgressIndicator' );
  var GameTimer = require( 'VEGAS/GameTimer' );
  var inherit = require( 'PHET_CORE/inherit' );
  var MultiLineText = require( 'SCENERY_PHET/MultiLineText' );
  var Panel = require( 'SUN/Panel' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
  var Text = require( 'SCENERY/nodes/Text' );
  var TextPushButton = require( 'SUN/buttons/TextPushButton' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var vegas = require( 'VEGAS/vegas' );
  var Tandem = require( 'TANDEM/Tandem' );

  // strings
  var keepTryingString = require( 'string!VEGAS/keepTrying' );
  var goodString = require( 'string!VEGAS/good' );
  var greatString = require( 'string!VEGAS/great' );
  var excellentString = require( 'string!VEGAS/excellent' );
  var labelScoreMaxString = require( 'string!VEGAS/label.score.max' );
  var labelTimeString = require( 'string!VEGAS/label.time' );
  var yourNewBestString = require( 'string!VEGAS/yourNewBest' );
  var pattern0YourBestString = require( 'string!VEGAS/pattern.0yourBest' );
  var continueString = require( 'string!VEGAS/continue' );
  var labelLevelString = require( 'string!VEGAS/label.level' );

  /**
   * @param {number} level starting from zero, 1 added to this when displayed
   * @param {number} score
   * @param {number} perfectScore
   * @param {number} numStars
   * @param {boolean} timerEnabled
   * @param {number} elapsedTime (in seconds)
   * @param {number} bestTimeAtThisLevel (in seconds), null indicates no best time
   * @param {boolean} isNewBestTime
   * @param {function} continueFunction Function to call when the user presses the 'Continue' button.
   * @param {Object} [options]
   * @constructor
   */
  function LevelCompletedNode( level, score, perfectScore, numStars, timerEnabled, elapsedTime, bestTimeAtThisLevel, isNewBestTime, continueFunction, options ) {

    options = _.extend( {
      levelVisible: true, // display the level number?
      fill: new Color( 180, 205, 255 ),
      stroke: 'black',
      lineWidth: 2,
      cornerRadius: 35,
      xMargin: 20,
      yMargin: 20,
      ySpacing: 30,
      titleFont: new PhetFont( { size: 28, weight: 'bold' } ),
      infoFont: new PhetFont( { size: 22, weight: 'bold' } ),
      buttonFont: new PhetFont( 26 ),
      buttonFill: new Color( 255, 255, 0 ),
      starDiameter: 62,
      tandem: null
    }, options );
    Tandem.validateOptions( options ); // The tandem is required when brand==='phet-io'

    // nodes to be added to the panel
    var children = [];

    // Title, which changes based on how the user did.
    var proportionCorrect = score / perfectScore;
    var titleText = keepTryingString;
    if ( proportionCorrect > 0.95 ) {
      titleText = excellentString;
    }
    else if ( proportionCorrect > 0.75 ) {
      titleText = greatString;
    }
    else if ( proportionCorrect >= 0.5 ) {
      titleText = goodString;
    }
    var title = new Text( titleText, { font: options.titleFont } );
    children.push( title );

    // Progress indicator
    children.push( new ProgressIndicator( numStars, new Property( score ), perfectScore, {
      starInnerRadius: options.starDiameter / 4,
      starOuterRadius: options.starDiameter / 2
    } ) );

    // Level (optional)
    if ( options.levelVisible ) {
      children.push( new Text( StringUtils.format( labelLevelString, level + 1 ), { font: options.infoFont } ) );
    }

    // Score
    children.push( new Text( StringUtils.format( labelScoreMaxString, score, perfectScore ), { font: options.infoFont } ) );

    // Time (optional)
    if ( timerEnabled ) {
      var time = new MultiLineText( StringUtils.format( labelTimeString, GameTimer.formatTime( elapsedTime ) ), {
        font: options.infoFont,
        align: 'center'
      } );
      if ( isNewBestTime ) {
        time.text = time.text + '\n' + yourNewBestString;
      }
      else if ( bestTimeAtThisLevel !== null ) {
        time.text = time.text + '\n' + StringUtils.format( pattern0YourBestString, GameTimer.formatTime( bestTimeAtThisLevel ) );
      }
      children.push( time );
    }

    // Continue button
    children.push( new TextPushButton( continueString, {
      listener: continueFunction,
      font: options.buttonFont,
      baseColor: options.buttonFill,
      tandem: options.tandem && options.tandem.createTandem( 'continueButton' )
    } ) );

    // Panel
    Panel.call( this, new VBox( { children: children, spacing: options.ySpacing } ), options );
  }

  vegas.register( 'LevelCompletedNode', LevelCompletedNode );

  return inherit( Panel, LevelCompletedNode );
} );<commit_msg>Supply tandems, see https://github.com/phetsims/scenery-phet/issues/262<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/**
 * This node is used to display a user's results when they complete a level.
 *
 * @author John Blanco
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var Color = require( 'SCENERY/util/Color' );
  var ProgressIndicator = require( 'VEGAS/ProgressIndicator' );
  var GameTimer = require( 'VEGAS/GameTimer' );
  var inherit = require( 'PHET_CORE/inherit' );
  var MultiLineText = require( 'SCENERY_PHET/MultiLineText' );
  var Panel = require( 'SUN/Panel' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var StringUtils = require( 'PHETCOMMON/util/StringUtils' );
  var Text = require( 'SCENERY/nodes/Text' );
  var TextPushButton = require( 'SUN/buttons/TextPushButton' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var vegas = require( 'VEGAS/vegas' );
  var Tandem = require( 'TANDEM/Tandem' );

  // strings
  var keepTryingString = require( 'string!VEGAS/keepTrying' );
  var goodString = require( 'string!VEGAS/good' );
  var greatString = require( 'string!VEGAS/great' );
  var excellentString = require( 'string!VEGAS/excellent' );
  var labelScoreMaxString = require( 'string!VEGAS/label.score.max' );
  var labelTimeString = require( 'string!VEGAS/label.time' );
  var yourNewBestString = require( 'string!VEGAS/yourNewBest' );
  var pattern0YourBestString = require( 'string!VEGAS/pattern.0yourBest' );
  var continueString = require( 'string!VEGAS/continue' );
  var labelLevelString = require( 'string!VEGAS/label.level' );

  /**
   * @param {number} level starting from zero, 1 added to this when displayed
   * @param {number} score
   * @param {number} perfectScore
   * @param {number} numStars
   * @param {boolean} timerEnabled
   * @param {number} elapsedTime (in seconds)
   * @param {number} bestTimeAtThisLevel (in seconds), null indicates no best time
   * @param {boolean} isNewBestTime
   * @param {function} continueFunction Function to call when the user presses the 'Continue' button.
   * @param {Object} [options]
   * @constructor
   */
  function LevelCompletedNode( level, score, perfectScore, numStars, timerEnabled, elapsedTime, bestTimeAtThisLevel, isNewBestTime, continueFunction, options ) {

    options = _.extend( {
      levelVisible: true, // display the level number?
      fill: new Color( 180, 205, 255 ),
      stroke: 'black',
      lineWidth: 2,
      cornerRadius: 35,
      xMargin: 20,
      yMargin: 20,
      ySpacing: 30,
      titleFont: new PhetFont( { size: 28, weight: 'bold' } ),
      infoFont: new PhetFont( { size: 22, weight: 'bold' } ),
      buttonFont: new PhetFont( 26 ),
      buttonFill: new Color( 255, 255, 0 ),
      starDiameter: 62,
      tandem: Tandem.createDefaultTandem( 'levelCompletedNode' )
    }, options );
    Tandem.validateOptions( options ); // The tandem is required when brand==='phet-io'

    // nodes to be added to the panel
    var children = [];

    // Title, which changes based on how the user did.
    var proportionCorrect = score / perfectScore;
    var titleText = keepTryingString;
    if ( proportionCorrect > 0.95 ) {
      titleText = excellentString;
    }
    else if ( proportionCorrect > 0.75 ) {
      titleText = greatString;
    }
    else if ( proportionCorrect >= 0.5 ) {
      titleText = goodString;
    }
    var title = new Text( titleText, { font: options.titleFont } );
    children.push( title );

    // Progress indicator
    children.push( new ProgressIndicator( numStars, new Property( score ), perfectScore, {
      starInnerRadius: options.starDiameter / 4,
      starOuterRadius: options.starDiameter / 2
    } ) );

    // Level (optional)
    if ( options.levelVisible ) {
      children.push( new Text( StringUtils.format( labelLevelString, level + 1 ), { font: options.infoFont } ) );
    }

    // Score
    children.push( new Text( StringUtils.format( labelScoreMaxString, score, perfectScore ), { font: options.infoFont } ) );

    // Time (optional)
    if ( timerEnabled ) {
      var time = new MultiLineText( StringUtils.format( labelTimeString, GameTimer.formatTime( elapsedTime ) ), {
        font: options.infoFont,
        align: 'center'
      } );
      if ( isNewBestTime ) {
        time.text = time.text + '\n' + yourNewBestString;
      }
      else if ( bestTimeAtThisLevel !== null ) {
        time.text = time.text + '\n' + StringUtils.format( pattern0YourBestString, GameTimer.formatTime( bestTimeAtThisLevel ) );
      }
      children.push( time );
    }

    // Continue button
    children.push( new TextPushButton( continueString, {
      listener: continueFunction,
      font: options.buttonFont,
      baseColor: options.buttonFill,
      tandem: options.tandem.createTandem( 'continueButton' )
    } ) );

    // Panel
    Panel.call( this, new VBox( { children: children, spacing: options.ySpacing } ), options );
  }

  vegas.register( 'LevelCompletedNode', LevelCompletedNode );

  return inherit( Panel, LevelCompletedNode );
} );<|endoftext|>


<commit_before>// @flow
import expect from 'expect'

export default function SRSpacedRepetition(
  easinessFactor: number = 2.5,
  interval: number = 1, // repeat tomorrow by default
  repetition: number = 0
) {
  this.easinessFactor = easinessFactor
  this.interval = interval
  this.repetition = repetition
}

SRSpacedRepetition.prototype.nextDate = function(previousDate = new Date().toString()) {
  const previousDateObject = new Date(previousDate)
  const nextDate = new Date(previousDateObject.getTime())
  nextDate.setDate(previousDateObject.getDate() + this.interval)
  return nextDate.toString()
}

// SRS
// Good 5 - ⬆ EF, ⬆ repetition -> interval ⬆⬆
// Okay 3 - ⬇ EF, ⬆ repetition -> interval ⬆
// Bad  1 - ⬇ EF, 0 repetition, 1 interval

export const SRSGrade = {
  GOOD: 5,
  OK: 3,
  BAD: 1,
}

SRSpacedRepetition.prototype.grade = function(grade: number){
  return gradeSRS(this, grade)
}

SRSpacedRepetition.prototype.good = function() {
  return this.grade(SRSGrade.GOOD)
}

SRSpacedRepetition.prototype.ok = function() {
  return this.grade(SRSGrade.OK)
}

SRSpacedRepetition.prototype.bad = function() {
  return this.grade(SRSGrade.BAD)
}

const gradeSRS = (srs: SRSpacedRepetition, grade: typeof(SRSGrade)) => {
  const { easinessFactor, interval, repetition } = srs
  var newEasinessFactor = easinessFactor,
      newInterval = interval,
      newRepetition = repetition;

  switch(grade) {
    case SRSGrade.GOOD:
      newEasinessFactor = increaseEF(newEasinessFactor)
      break
    case SRSGrade.OK:
    case SRSGrade.BAD:
      newEasinessFactor = decreaseEF(newEasinessFactor)
      break
    default:
      expect().toExist('No valid grade')
  }

  if (grade == SRSGrade.BAD) {
    newRepetition = 0;
    newInterval = 1;
  } else {
    newRepetition = newRepetition + 1;

    switch (newRepetition) {
      case 1:
        newInterval = 1;
        break;
      case 2:
        newInterval = 6;
        break;
      default:
        newInterval = Math.round((newRepetition - 1) * newEasinessFactor);
        break;
    }
  }

  return new SRSpacedRepetition(newEasinessFactor, newInterval, newRepetition)
}

const increaseEF = (EF) => { return gradeEasinessFactor(EF, 5)}
const decreaseEF = (EF) => { return gradeEasinessFactor(EF, 3)}

const gradeEasinessFactor = (EF, grade) => {
  expect(grade).toBeGreaterThanOrEqualTo(3)
  expect(grade).toBeLessThanOrEqualTo(5)

  const minEF = 1.3
  const maxEF = 2.5
  const oldEF = EF

  var easinessFactor = 0
  var gradedEF = oldEF + (0.1 - (5-grade)*(0.08+(5-grade)*0.02))

  if (gradedEF < minEF) {
    easinessFactor = minEF;
  } else if (gradedEF > maxEF) {
    easinessFactor = maxEF
  } else {
    easinessFactor = gradedEF;
  }

  expect(easinessFactor).toBeGreaterThanOrEqualTo(minEF)
  expect(easinessFactor).toBeLessThanOrEqualTo(maxEF)
  return easinessFactor
}
<commit_msg>Fixed parameter annotation.<commit_after>// @flow
import expect from 'expect'

export default function SRSpacedRepetition(
  easinessFactor: number = 2.5,
  interval: number = 1, // repeat tomorrow by default
  repetition: number = 0
) {
  this.easinessFactor = easinessFactor
  this.interval = interval
  this.repetition = repetition
}

SRSpacedRepetition.prototype.nextDate = function(previousDate = new Date().toString()) {
  const previousDateObject = new Date(previousDate)
  const nextDate = new Date(previousDateObject.getTime())
  nextDate.setDate(previousDateObject.getDate() + this.interval)
  return nextDate.toString()
}

// SRS
// Good 5 - ⬆ EF, ⬆ repetition -> interval ⬆⬆
// Okay 3 - ⬇ EF, ⬆ repetition -> interval ⬆
// Bad  1 - ⬇ EF, 0 repetition, 1 interval

export const SRSGrade = {
  GOOD: 5,
  OK: 3,
  BAD: 1,
}

SRSpacedRepetition.prototype.grade = function(grade: number){
  return gradeSRS(this, grade)
}

SRSpacedRepetition.prototype.good = function() {
  return this.grade(SRSGrade.GOOD)
}

SRSpacedRepetition.prototype.ok = function() {
  return this.grade(SRSGrade.OK)
}

SRSpacedRepetition.prototype.bad = function() {
  return this.grade(SRSGrade.BAD)
}

const gradeSRS = (srs: SRSpacedRepetition, grade: number) => {
  const { easinessFactor, interval, repetition } = srs
  var newEasinessFactor = easinessFactor,
      newInterval = interval,
      newRepetition = repetition;

  switch(grade) {
    case SRSGrade.GOOD:
      newEasinessFactor = increaseEF(newEasinessFactor)
      break
    case SRSGrade.OK:
    case SRSGrade.BAD:
      newEasinessFactor = decreaseEF(newEasinessFactor)
      break
    default:
      expect().toExist('No valid grade')
  }

  if (grade == SRSGrade.BAD) {
    newRepetition = 0;
    newInterval = 1;
  } else {
    newRepetition = newRepetition + 1;

    switch (newRepetition) {
      case 1:
        newInterval = 1;
        break;
      case 2:
        newInterval = 6;
        break;
      default:
        newInterval = Math.round((newRepetition - 1) * newEasinessFactor);
        break;
    }
  }

  return new SRSpacedRepetition(newEasinessFactor, newInterval, newRepetition)
}

const increaseEF = (EF) => { return gradeEasinessFactor(EF, 5)}
const decreaseEF = (EF) => { return gradeEasinessFactor(EF, 3)}

const gradeEasinessFactor = (EF, grade) => {
  expect(grade).toBeGreaterThanOrEqualTo(3)
  expect(grade).toBeLessThanOrEqualTo(5)

  const minEF = 1.3
  const maxEF = 2.5
  const oldEF = EF

  var easinessFactor = 0
  var gradedEF = oldEF + (0.1 - (5-grade)*(0.08+(5-grade)*0.02))

  if (gradedEF < minEF) {
    easinessFactor = minEF;
  } else if (gradedEF > maxEF) {
    easinessFactor = maxEF
  } else {
    easinessFactor = gradedEF;
  }

  expect(easinessFactor).toBeGreaterThanOrEqualTo(minEF)
  expect(easinessFactor).toBeLessThanOrEqualTo(maxEF)
  return easinessFactor
}
<|endoftext|>


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

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

    gvm.loggedinuser = ko.observable();

    getLoggedInUser();

    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.currentUserRole = ko.observable();
    gvm.oldUserRole = ko.observable();
    gvm.availablePermissions = ko.observableArray(['GUEST', 'STUDENT', 'USER', 'SUPERUSER']);

    gvm.rights = ko.observableArray([]);
    gvm.allRights = ko.observableArray([]);
    gvm.userRights = 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);

    $('#userEditForm').on('submit', function(e)
    {
        e.preventDefault();

        if(viewModel.loggedinuser != viewModel.edituserid)
        {
            saveChanges();
            saveUserPermissions();
        } else {
            saveChanges();
        }
    });

    getUserPermission();
}

function getUserPermission(){
    $.ajax({
        type: "POST",
        url: "/api/getUserRolesById/" + viewModel.edituserid,
        success: function(data) {
            console.log(data);

            if (data.length > 0) {
                var role = "GUEST";
                for (i = 0; i < data.length; i++) {
                    if (data[i] == "SUPERUSER" && data[i] != null){
                        console.log("SUPERUSER");
                        role = "SUPERUSER";
                    }
                    if (data[i] == "USER" && data[i] != null){
                        console.log("USER");
                        role = "USER";
                    }
                    if (data[i] == "STUDENT" && data[i] != null){
                        console.log("STUDENT");
                        role = "STUDENT";
                    }
                    if (data[i] == "GUEST" && data[i] != null){
                        console.log("guest");
                        role = "GUEST";
                    }
                }

                return role;
            } else {
                console.log("guest else");
                return "GUEST";
            }
        },
        error: function() {
            alert("Error while getting user info, please contact your administrator");
        }
    });
}

function getLoggedInUser(){
    $.getJSON("/api/loggedinuser", function(data){
        viewModel.loggedinuser = data;
    });
}

function saveChanges(){
    saveUserEdits(viewModel.edituserid);
}

function saveUserEdits(id){
    $.ajax({
        type: "POST",
        url: "/api/saveedit/" + id,
        data: $('#userEditForm').serialize(),
        success: function() {
        },
        error: function() {
            console.log("Error saving user changes");
        }
    });
}

function saveUserPermissions(){
    var role = viewModel.currentUserRole();
    var permissions = "GUEST ";

    if(role == 'STUDENT' || role == 'USER' || role == 'SUPERUSER'){
        permissions += "STUDENT ";
        if(role == 'USER' || role == 'SUPERUSER'){
            permissions += "USER ";
            if(role == 'SUPERUSER'){
                permissions += "SUPERUSER";
            }
        }
    }

    //SAVE NEW PERMISSIONS
    $.ajax({
        type: "POST",
        url: "/api/addrole/" + viewModel.edituserid,
        data: { 'permissions': permissions },
        success: function() {
            alert('Changes saved correctly');
        },
        error: function() {
            alert('Error saving user. Please contact the Administrator');
        }
    });
}

function getAllUserDataById(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){
                    viewModel.updatePermissions(item.role)
                }
            });

            if (addedUsername != current) {
                addedUsername = current;
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, item.status, viewModel.rights()));
            }
        });
    });
}

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),
        userStatuses: ko.observableArray(['ACTIVE', 'DISABLED']),

        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 if (this.status() == "WAIT_ACTIVATION") {
                this.status("ACTIVE");
            }
            updateUserStatus(this);
        }
    };
}<commit_msg>Load current permission user edit<commit_after>function pageViewModel(gvm) {
    // Page specific i18n bindings
    gvm.title = ko.computed(function(){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("AdminEditPage");}, gvm);
    gvm.pageHeaderEditUser = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("UserEditTitle");}, gvm);

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

    gvm.loggedinuser = ko.observable();

    getLoggedInUser();

    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.currentUserRole = ko.observable();
    gvm.oldUserRole = ko.observable();
    gvm.availablePermissions = ko.observableArray(['GUEST', 'STUDENT', 'USER', 'SUPERUSER']);

    gvm.rights = ko.observableArray([]);
    gvm.allRights = ko.observableArray([]);
    gvm.userRights = 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);

    $('#userEditForm').on('submit', function(e)
    {
        e.preventDefault();

        if(viewModel.loggedinuser != viewModel.edituserid)
        {
            saveChanges();
            saveUserPermissions();
        } else {
            saveChanges();
        }
    });

    getUserPermission();
}

function getUserPermission(){
    $.ajax({
        type: "POST",
        url: "/api/getUserRolesById/" + viewModel.edituserid,
        success: function(data) {
            console.log(data);

            if (data.length > 0) {
                var role = "GUEST";
                for (i = 0; i < data.length; i++) {
                    if (data[i] == "SUPERUSER" && data[i] != null){
                        console.log("SUPERUSER");
                        role = "SUPERUSER";
                    }
                    if (data[i] == "USER" && data[i] != null){
                        console.log("USER");
                        role = "USER";
                    }
                    if (data[i] == "STUDENT" && data[i] != null){
                        console.log("STUDENT");
                        role = "STUDENT";
                    }
                    if (data[i] == "GUEST" && data[i] != null){
                        console.log("guest");
                        role = "GUEST";
                    }
                }
                console.log("role: " + role);
                return role;
            } else {
                console.log("guest else");
                return "GUEST";
            }
        },
        error: function() {
            alert("Error while getting user info, please contact your administrator");
        }
    });
}

function getLoggedInUser(){
    $.getJSON("/api/loggedinuser", function(data){
        viewModel.loggedinuser = data;
    });
}

function saveChanges(){
    saveUserEdits(viewModel.edituserid);
}

function saveUserEdits(id){
    $.ajax({
        type: "POST",
        url: "/api/saveedit/" + id,
        data: $('#userEditForm').serialize(),
        success: function() {
        },
        error: function() {
            console.log("Error saving user changes");
        }
    });
}

function saveUserPermissions(){
    var role = viewModel.currentUserRole();
    var permissions = "GUEST ";

    if(role == 'STUDENT' || role == 'USER' || role == 'SUPERUSER'){
        permissions += "STUDENT ";
        if(role == 'USER' || role == 'SUPERUSER'){
            permissions += "USER ";
            if(role == 'SUPERUSER'){
                permissions += "SUPERUSER";
            }
        }
    }

    //SAVE NEW PERMISSIONS
    $.ajax({
        type: "POST",
        url: "/api/addrole/" + viewModel.edituserid,
        data: { 'permissions': permissions },
        success: function() {
            alert('Changes saved correctly');
        },
        error: function() {
            alert('Error saving user. Please contact the Administrator');
        }
    });
}

function getAllUserDataById(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){
                    viewModel.updatePermissions(item.role)
                }
            });

            if (addedUsername != current) {
                addedUsername = current;
                viewModel.updateUser(new User(item.userid, item.username, item.firstname, item.lastname, item.status, viewModel.rights()));
            }
        });
    });
}

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),
        userStatuses: ko.observableArray(['ACTIVE', 'DISABLED']),

        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 if (this.status() == "WAIT_ACTIVATION") {
                this.status("ACTIVE");
            }
            updateUserStatus(this);
        }
    };
}<|endoftext|>