<commit_before>$(function() {
    drawFigures();
    initFigureEvents();
    initWindowResizing();
});

var prevWidth; //Figure container width before resizing

var popElement = null;

function initFigureEvents() {
    $('g.cell').popover({
        container: 'body',
        content:   function(){
            var counterId = $(this).attr('counter');
            var date = $(this).attr('date');
            var markStr = '
 Mark Done
';
            var missStr = '
 Mark Miss
';
            var clearStr = '
 Clear
';
            var res = '
' + markStr + missStr + clearStr + '
';
            //console.log(res);
            return res;
        },
        html:      true,
        placement: 'bottom'
    });

    $('g.cell').on('show.bs.popover', function(){
        console.log('popover show');
        if(popElement != null)
            $(popElement).popover('hide');

        //Create content

        //Track which element for which popover is open.
        popElement = this;
    });

    $('g.cell').on('hide.bs.popover', function(){
        console.log('popover hide');
        popElement = null;
    });

    $('g.cell').on('click', function(){
        console.log('cell click');
        return false;
    });

    $(document).on('click', function(){
        console.log('document click');
        if(popElement != null) {
            $(popElement).popover('hide');
            popElement = null;
        }
    });

    //$('svg g.cell').click(function(){console.log('hello');});
}

function initWindowResizing() {
    prevWidth = $('.cimg').width();

    var resizeId;
    $(window).resize(function() {
        clearTimeout(resizeId);
        resizeId = setTimeout(windowResized, 500);
    });
}

function windowResized() {
    var w = $('.cimg').width();
    if(w != prevWidth) {
        resizeFigures();
        prevWidth = w;
    }
}

function resizeFigures() {
    $('svg').each(function() {
        Snap(this).clear();
    });

    drawFigures();
    initFigureEvents();
}

var numcol  = 7; //Number of columns in this calendar
var gutter  = 10; //Spacing between months in pixels
var space   = 2; //Spacing between cells in pixels

var showDateText = true;

var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

/**
 * Draw a figure for all counters.
 */
function drawFigures() {
    var now = new Date();
    //console.log(now);
    //console.log(now.getFullYear());
    $('svg').each(function() {
        drawFigure(this, now.getFullYear(), now.getMonth());
    });

    $('g.cell').tooltip({container:'body'});
}

/**
 * Draw a figure, which contains multiple calendar.
 */
function drawFigure(svg, year, month) {
    var width = Math.min($('.cimg').width() - 50, 900); //Width of the figure
    var snap = Snap(svg);

    //snap.rect(50, 50, 50, 50);
    var g1, g2;

    if(month === 0) {
        g1 = drawMonthCalendar(snap, 0, width, year - 1, 11); //December of last year
    }
    else {
        g1 = drawMonthCalendar(snap, 0, width, year, month - 1);
    }

    var g2 = drawMonthCalendar(snap, 1, width, year, month);
    var monthWidth = +g1.attr('width');
    var monthHeight = +g1.attr('height');
    var tx = (monthWidth) + gutter;
    g2.transform('t' + tx);

    snap.attr({width: 2 * monthWidth + gutter, height: monthHeight});
}

/**
 * Draw a calendar.
 * @param snap      Snap object
 * @param i         calendar index: the first calendar is 0, next is 1.
 * @param cwidth    figure (canvas) total width.
 * @param year      year, as in 2014
 * @param month     month: 0 = Jan, 1 = Feb, ... , 11 = Dec
 */
function drawMonthCalendar(snap, i, cwidth, year, month) {
    var numdays = numberOfDays(year, month + 1); //Number of days in this month;
    var startOn = (new Date(year, month, 1)).getDay(); //Day of the first of this month; 0 = Sunday, 1 = Monday, etc
    var numrow  = Math.ceil((numdays + startOn) / numcol); //Number of rows in this calendar
    var width   = (((cwidth - gutter) / 2) - ((numcol - 1) * space)) / numcol; //width of cell
    var counterId = snap.attr('id'); //Counter Id
    var now     = new Date();
    //console.log(hist);

    /*console.log('year: ' + year);
    console.log('month: ' + month);
    console.log('numdays: ' + numdays);
    console.log('startOn: ' + startOn);
    console.log('numcol: ' + numcol);
    console.log('numrow: ' + numrow);
    console.log('gutter: ' + gutter);
    console.log('space: ' + space);
    console.log('width: ' + width);*/

    var group = snap.group();
    group.attr({width: width * numcol + space * numcol, height: width * numrow + space * numrow});

    for(row = 0; row < numrow; row++) {
        for(col = 0; col < numcol; col++) {
            var x = col * width + col * space;
            var y = row * width + row * space;
            var s = row * numcol + col; //Cell sequence number, starting from 0;
            var date = s - startOn + 1; //Date number, e.g. 15
            var cellGroup = snap.group().attr({'class':'cell', 'counter':counterId, 'date':makeDateStr(year, month + 1, date)});

            //console.log(s);
            //console.log(startOn);
            var c = '#d6e685';

            if(s < startOn || s >= numdays + startOn)
                c = '#f2f2f2';
            else {
                c = getColor(counterId, new Date(year, month, date));
            }

            //var c = s < startOn || s > numdays + startOn ? '#eeeeee' : '#d6e685';
            var rectId = 'rect' + s;
            var rect = snap.rect(x, y, width, width).attr({id:rectId, fill:c});
            //if(s >= startOn && s < startOn + numdays)
                //cellGroup.attr({'data-toggle':'tooltip', title:makeFullDateStr(year, month, date)});
            //var a = snap.element('a').attr({href:'#'});
            if(year == now.getFullYear() && month == now.getMonth() && date == now.getDate())
                rect.attr({strokeWidth:1, stroke:'#aaa'});
            cellGroup.add(rect);
            //cellGroup.add(a);

            if(showDateText) {
                if(date > 0 && date <= numdays) {
                    var fontSize = width / 2.4;
                    var numchar = date < 10 ? 1 : 2;
                    var textX = x + (width - fontSize) / (numchar == 1 ? 1.4 : 2);
                    //var textY = y + (width - fontSize + (width / 6));
                    var textY = y + (width - fontSize + (fontSize / 6));
                    var textColor = '#777';
                    var text = snap.text(textX, textY, date).
                        attr({'font-size': fontSize + 'px', 'fill': textColor, 'opacity':0.8});
                    cellGroup.add(text);
                }
            }

            group.add(cellGroup);
        }
    }

    return group;
}

var colorYes = '#d6e685';
var colorNo  = '#e3e3e3';
var colorStart = '#bee685';
var colorMiss = '#e6c785';

function getColor(counterId, date) {
    //If this date is today or in the future, set this cell as no color.
    if(dateGreaterOrEqual(date, new Date()))
        return colorNo;

    var hist = data[counterId]; //History data for this counter
    var val = hist[makeDateStr(date.getFullYear(), date.getMonth() + 1, date.getDate())];
    return val === undefined ? colorNo : val == 0 ? colorYes : colorMiss;

    //console.log(val);

    /*

    for(var h = 0; h < hist.length; h++) {
        var start = hist[h].start;
        var end = hist[h].end == null ? null : hist[h].end;

        if((dateGreaterOrEqual(date, start) && dateLess(date, end)) || (dateGreaterOrEqual(date, start) && (end == null))) {
            if(dateEqual(date, start))
                return colorStart;
            //else if(dateEqual(date, end))
            //    return '#e6c785';
            else
                return colorYes;
        }
    }*/

    //return colorYes;
}

function dateEqual(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate();
}

/**
 * date1 is greater than (comes after) date2.
 */
function dateGreater(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    if(date1.getFullYear() > date2.getFullYear())
        return true;
    if(date1.getFullYear() < date2.getFullYear())
        return false;
    if(date1.getMonth() > date2.getMonth())
        return true;
    if(date1.getMonth() < date2.getMonth())
        return false;
    if(date1.getDate() > date2.getDate())
        return true;
    return false;
}

/**
 * date1 comes before date2.
 */
function dateLess(date1, date2) {
    return dateGreater(date2, date1);
}

function dateGreaterOrEqual(date1, date2) {
    return dateGreater(date1, date2) || dateEqual(date1, date2);
}

function dateLessOrEqual(date1, date2) {
    return dateLess(date1, date2) || dateEqual(date1, date2);
}

/**
 * Make date string YYYY-mm-dd
 */
function makeDateStr(year, month, date) {
    if(month < 10) month = '0' + month;
    if(date  < 10) date  = '0' + date;
    return year + '-' + month + '-' + date;
}

/**
 * Example: March 22, 2015
 */
function makeFullDateStr(year, month, date) {
    return monthNames[month] + ' ' + date + ', ' + year;
}

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return +d.getDate();
}<commit_msg>Remove debugging console.log() statements.<commit_after>$(function() {
    drawFigures();
    initFigureEvents();
    initWindowResizing();
});

var prevWidth; //Figure container width before resizing

var popElement = null;

function initFigureEvents() {
    $('g.cell').popover({
        container: 'body',
        content:   function(){
            var counterId = $(this).attr('counter');
            var date = $(this).attr('date');
            var markStr = '
 Mark Done
';
            var missStr = '
 Mark Miss
';
            var clearStr = '
 Clear
';
            var res = '
' + markStr + missStr + clearStr + '
';
            return res;
        },
        html:      true,
        placement: 'bottom'
    });

    $('g.cell').on('show.bs.popover', function(){
        if(popElement != null)
            $(popElement).popover('hide');

        //Track which element for which popover is open.
        popElement = this;
    });

    $('g.cell').on('hide.bs.popover', function(){
        popElement = null;
    });

    $('g.cell').on('click', function(){
        return false;
    });

    $(document).on('click', function(){
        if(popElement != null) {
            $(popElement).popover('hide');
            popElement = null;
        }
    });
}

function initWindowResizing() {
    prevWidth = $('.cimg').width();

    var resizeId;
    $(window).resize(function() {
        clearTimeout(resizeId);
        resizeId = setTimeout(windowResized, 500);
    });
}

function windowResized() {
    var w = $('.cimg').width();
    if(w != prevWidth) {
        resizeFigures();
        prevWidth = w;
    }
}

function resizeFigures() {
    $('svg').each(function() {
        Snap(this).clear();
    });

    drawFigures();
    initFigureEvents();
}

var numcol  = 7; //Number of columns in this calendar
var gutter  = 10; //Spacing between months in pixels
var space   = 2; //Spacing between cells in pixels

var showDateText = true;

var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

/**
 * Draw a figure for all counters.
 */
function drawFigures() {
    var now = new Date();
    //console.log(now);
    //console.log(now.getFullYear());
    $('svg').each(function() {
        drawFigure(this, now.getFullYear(), now.getMonth());
    });

    $('g.cell').tooltip({container:'body'});
}

/**
 * Draw a figure, which contains multiple calendar.
 */
function drawFigure(svg, year, month) {
    var width = Math.min($('.cimg').width() - 50, 900); //Width of the figure
    var snap = Snap(svg);

    //snap.rect(50, 50, 50, 50);
    var g1, g2;

    if(month === 0) {
        g1 = drawMonthCalendar(snap, 0, width, year - 1, 11); //December of last year
    }
    else {
        g1 = drawMonthCalendar(snap, 0, width, year, month - 1);
    }

    var g2 = drawMonthCalendar(snap, 1, width, year, month);
    var monthWidth = +g1.attr('width');
    var monthHeight = +g1.attr('height');
    var tx = (monthWidth) + gutter;
    g2.transform('t' + tx);

    snap.attr({width: 2 * monthWidth + gutter, height: monthHeight});
}

/**
 * Draw a calendar.
 * @param snap      Snap object
 * @param i         calendar index: the first calendar is 0, next is 1.
 * @param cwidth    figure (canvas) total width.
 * @param year      year, as in 2014
 * @param month     month: 0 = Jan, 1 = Feb, ... , 11 = Dec
 */
function drawMonthCalendar(snap, i, cwidth, year, month) {
    var numdays = numberOfDays(year, month + 1); //Number of days in this month;
    var startOn = (new Date(year, month, 1)).getDay(); //Day of the first of this month; 0 = Sunday, 1 = Monday, etc
    var numrow  = Math.ceil((numdays + startOn) / numcol); //Number of rows in this calendar
    var width   = (((cwidth - gutter) / 2) - ((numcol - 1) * space)) / numcol; //width of cell
    var counterId = snap.attr('id'); //Counter Id
    var now     = new Date();
    //console.log(hist);

    /*console.log('year: ' + year);
    console.log('month: ' + month);
    console.log('numdays: ' + numdays);
    console.log('startOn: ' + startOn);
    console.log('numcol: ' + numcol);
    console.log('numrow: ' + numrow);
    console.log('gutter: ' + gutter);
    console.log('space: ' + space);
    console.log('width: ' + width);*/

    var group = snap.group();
    group.attr({width: width * numcol + space * numcol, height: width * numrow + space * numrow});

    for(row = 0; row < numrow; row++) {
        for(col = 0; col < numcol; col++) {
            var x = col * width + col * space;
            var y = row * width + row * space;
            var s = row * numcol + col; //Cell sequence number, starting from 0;
            var date = s - startOn + 1; //Date number, e.g. 15
            var cellGroup = snap.group().attr({'class':'cell', 'counter':counterId, 'date':makeDateStr(year, month + 1, date)});

            //console.log(s);
            //console.log(startOn);
            var c = '#d6e685';

            if(s < startOn || s >= numdays + startOn)
                c = '#f2f2f2';
            else {
                c = getColor(counterId, new Date(year, month, date));
            }

            //var c = s < startOn || s > numdays + startOn ? '#eeeeee' : '#d6e685';
            var rectId = 'rect' + s;
            var rect = snap.rect(x, y, width, width).attr({id:rectId, fill:c});
            //if(s >= startOn && s < startOn + numdays)
                //cellGroup.attr({'data-toggle':'tooltip', title:makeFullDateStr(year, month, date)});
            //var a = snap.element('a').attr({href:'#'});
            if(year == now.getFullYear() && month == now.getMonth() && date == now.getDate())
                rect.attr({strokeWidth:1, stroke:'#aaa'});
            cellGroup.add(rect);
            //cellGroup.add(a);

            if(showDateText) {
                if(date > 0 && date <= numdays) {
                    var fontSize = width / 2.4;
                    var numchar = date < 10 ? 1 : 2;
                    var textX = x + (width - fontSize) / (numchar == 1 ? 1.4 : 2);
                    //var textY = y + (width - fontSize + (width / 6));
                    var textY = y + (width - fontSize + (fontSize / 6));
                    var textColor = '#777';
                    var text = snap.text(textX, textY, date).
                        attr({'font-size': fontSize + 'px', 'fill': textColor, 'opacity':0.8});
                    cellGroup.add(text);
                }
            }

            group.add(cellGroup);
        }
    }

    return group;
}

var colorYes = '#d6e685';
var colorNo  = '#e3e3e3';
var colorStart = '#bee685';
var colorMiss = '#e6c785';

function getColor(counterId, date) {
    //If this date is today or in the future, set this cell as no color.
    if(dateGreaterOrEqual(date, new Date()))
        return colorNo;

    var hist = data[counterId]; //History data for this counter
    var val = hist[makeDateStr(date.getFullYear(), date.getMonth() + 1, date.getDate())];
    return val === undefined ? colorNo : val == 0 ? colorYes : colorMiss;

    //console.log(val);

    /*

    for(var h = 0; h < hist.length; h++) {
        var start = hist[h].start;
        var end = hist[h].end == null ? null : hist[h].end;

        if((dateGreaterOrEqual(date, start) && dateLess(date, end)) || (dateGreaterOrEqual(date, start) && (end == null))) {
            if(dateEqual(date, start))
                return colorStart;
            //else if(dateEqual(date, end))
            //    return '#e6c785';
            else
                return colorYes;
        }
    }*/

    //return colorYes;
}

function dateEqual(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate();
}

/**
 * date1 is greater than (comes after) date2.
 */
function dateGreater(date1, date2) {
    if(date1 == null || date2 == null)
        return false;

    if(date1.getFullYear() > date2.getFullYear())
        return true;
    if(date1.getFullYear() < date2.getFullYear())
        return false;
    if(date1.getMonth() > date2.getMonth())
        return true;
    if(date1.getMonth() < date2.getMonth())
        return false;
    if(date1.getDate() > date2.getDate())
        return true;
    return false;
}

/**
 * date1 comes before date2.
 */
function dateLess(date1, date2) {
    return dateGreater(date2, date1);
}

function dateGreaterOrEqual(date1, date2) {
    return dateGreater(date1, date2) || dateEqual(date1, date2);
}

function dateLessOrEqual(date1, date2) {
    return dateLess(date1, date2) || dateEqual(date1, date2);
}

/**
 * Make date string YYYY-mm-dd
 */
function makeDateStr(year, month, date) {
    if(month < 10) month = '0' + month;
    if(date  < 10) date  = '0' + date;
    return year + '-' + month + '-' + date;
}

/**
 * Example: March 22, 2015
 */
function makeFullDateStr(year, month, date) {
    return monthNames[month] + ' ' + date + ', ' + year;
}

function numberOfDays(year, month) {
    var d = new Date(year, month, 0);
    return +d.getDate();
}<|endoftext|>


<commit_before>//iTop Designer widget for editing properties line by line
$(function()
{
	// the widget definition, where "itop" is the namespace,
	// "property_field" the widget name
	$.widget( "itop.property_field",
	{
		// default options
		options:
		{
			parent_selector: null,
			field_id: '',
			submit_to: 'index.php',
			submit_parameters: {operation: 'async_action'},
			do_apply: null,
			do_cancel: null,
			auto_apply: false

		},

		// the constructor
		_create: function()
		{
			var me = this;

			this.element
				.addClass( "itop-property-field" )
				.bind('apply_changes.itop-property-field', function(){me._do_apply();} );

			this.bModified = false;

			if (this.options.field_id != '')
			{
				$('#'+this.options.field_id).bind('change.itop-property-field', function() { me._on_change(); });
				this.value = this._get_field_value();
			}
			this.element.find(".prop_apply").bind('click.itop-property-field', function() { me._do_apply(); });
			this.element.find(".prop_cancel").bind('click.itop-property-field', function() { me._do_cancel(); });

			this._refresh();
		},

		// called when created, and later when changing options
		_refresh: function()
		{
			if (this.bModified)
			{
				this.element.addClass("itop-property-field-modified");
				this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''});
				this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: ''});
			}
			else
			{
				this.element.removeClass("itop-property-field-modified");
				this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: 'hidden'});
				this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: 'hidden'});
			}
		},

		// events bound via _bind are removed automatically
		// revert other modifications here
		_destroy: function()
		{
			this.element.removeClass( "itop-property-field" );
			this.element.removeClass("itop-property-field-modified");
		},

		// _setOptions is called with a hash of all options that are changing
		// always refresh when changing options
		_setOptions: function()
		{
			// in 1.9 would use _superApply
			this._superApply(arguments);
			this._refresh();
		},

		// _setOption is called for each individual option that is changing
		_setOption: function( key, value )
		{
			// in 1.9 would use _super
			this._superApply(arguments);
		},
		_on_change: function()
		{
			var new_value = this._get_field_value();
			if (new_value != this.value)
			{
				this.bModified = true;
				if (this.options.auto_apply)
				{
					this._do_apply();
				}
			}
			else
			{
				this.bModified = false;
			}
			this._refresh();
		},
		_get_field_value: function()
		{
			var oField = $('#'+this.options.field_id);
			if (oField.attr('type') == 'checkbox')
			{
				return (oField.attr('checked') == 'checked');
			}
			else
			{
				return oField.val();
			}
		},
		_get_committed_value: function()
		{
			return { name: $('#'+this.options.field_id).attr('name'), value: this.value };
		},
		_do_apply: function()
		{
			if (this.options.parent_selector)
			{
				$(this.options.parent_selector).trigger('mark_as_modified');
			}
			if (this.options.do_apply)
			{
				// specific behavior...
				if (this.options.do_apply())
				{
					this.bModified = false;
					this.previous_value = this.value;
					this.value = this._get_field_value();
					this._refresh();
				}
			}
			else
			{
				// Validate the field
				sFormId = this.element.closest('form').attr('id');
				var oField = $('#'+this.options.field_id);
				oField.trigger('validate');
				if ( $.inArray(this.options.field_id, oFormValidation[sFormId]) == -1)
				{
					this.bModified = false;
					this.previous_value = this.value;
					this.value = this._get_field_value();
					this._do_submit();
					this._refresh();
				}
			}
		},
		_do_cancel: function()
		{
			if (this.options.do_cancel)
			{
				// specific behavior...
				this.options.do_cancel();
			}
			else
			{
				this.bModified = false;
				var oField = $('#'+this.options.field_id);
				if (oField.attr('type') == 'checkbox')
				{
					if (this.value)
					{
						oField.attr('checked', true);
					}
					else
					{
						oField.removeAttr('checked');
					}
				}
				else
				{
					oField.val(this.value);
				}
				this._refresh();
				oField.trigger('reverted', {type: 'designer', previous_value: this.value });
				oField.trigger('validate');
			}
		},
		_do_submit: function()
		{
			var oData = {};
			this.element.closest('form').find(':input[type=hidden]').each(function()
			{
				// Hidden form fields
				oData[$(this).attr('name')] = $(this).val();
			});
			this.element.closest('form').find('.itop-property-field').each(function()
			{
				var oWidget = $(this).data('itopProperty_field');
				if (oWidget && oWidget._is_visible())
				{
					var oVal = oWidget._get_committed_value();
					oData[oVal.name] = oVal.value;
				}
			});
			oPostedData = this.options.submit_parameters;
			oPostedData.params = oData;
			oPostedData.params.updated = [ $('#'+this.options.field_id).attr('name') ]; // only one field updated in this case
			oPostedData.params.previous_values = {};
			oPostedData.params.previous_values[oPostedData.params.updated] = this.previous_value; // pass also the previous value(s)
			$.post(this.options.submit_to, oPostedData, function(data)
			{
				$('#prop_submit_result').html(data);
			});
		},
		_is_visible: function()
		{
			return this.element.parent().is(':visible');
		}
	});
});

var oFormValidation = {};

function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId, aForbiddenValues, sExplainForbiddenValues)
{
	var currentVal = $('#'+sFieldId).val();
	var bValid = true;
	var sMessage = null;

	if (bMandatory && (currentVal == ''))
	{
		bValid = false;
	}
	if ((sPattern != '') && (currentVal != ''))
	{
		re = new RegExp(sPattern);
		bValid = re.test(currentVal);
	}
	if (aForbiddenValues)
	{
		for(var i = 0; i < aForbiddenValues.length; i++)
		{
			if (aForbiddenValues[i] == currentVal)
			{
				bValid = false;
				sMessage = sExplainForbiddenValues;
				break;
			}
		}
	}

	if (oFormValidation[sFormId] == undefined) oFormValidation[sFormId] = [];
	if (!bValid)
	{
		$('#v_'+sFieldId).addClass('ui-state-error');
		oFormValidation[sFormId].push(sFieldId);
		if (sMessage)
		{
			$('#'+sFieldId).attr('title', sMessage).tooltip();
			if ($('#'+sFieldId).is(":focus"))
			{
				$('#'+sFieldId).tooltip('open');
			}
		}
	}
	else
	{
		$('#v_'+sFieldId).removeClass('ui-state-error');
		$('#'+sFieldId).tooltip('close');
		$('#'+sFieldId).removeAttr('title');
		// Remove the element from the array
		iFieldIdPos = oFormValidation[sFormId].indexOf(sFieldId);
		oFormValidation[sFormId].splice(iFieldIdPos, 1);
	}
}

function ValidateForm(sFormId, bValidateAll)
{
	oFormValidation[sFormId] = [];
	if (bValidateAll)
	{
		$('#'+sFormId+' :input').trigger('validate');
	}
	else
	{
		// Only the visible fields
		$('#'+sFormId+' :input:visible').each(function() {
			$(this).trigger('validate');
		});
	}
	return oFormValidation[sFormId];
}

function ReadFormParams(sFormId)
{
	var oMap = { };
	$('#'+sFormId+' :input').each( function() {
		if ($(this).parent().is(':visible'))
		{
			var sName = $(this).attr('name');
			if (sName && sName != '')
			{
				if (this.type == 'checkbox')
				{
					oMap[sName] = ($(this).attr('checked') == 'checked');
				}
				else
				{
					oMap[sName] = $(this).val();
				}

			}
		}
	});
	return oMap;
}

function SubmitForm(sFormId, onSubmitResult)
{
	var aErrors = ValidateForm(sFormId, false);
	if (aErrors.length == 0)
	{
		var oMap = ReadFormParams(sFormId);
		oMap.module_name = sCurrentModule;
		$('#'+sFormId+' :input').each( function() {
			if ($(this).parent().is(':visible'))
			{
				var sName = $(this).attr('name');
				if (sName && sName != '')
				{
					if (this.type == 'checkbox')
					{
						oMap[sName] = ($(this).attr('checked') == 'checked');
					}
					else
					{
						oMap[sName] = $(this).val();
					}

				}
			}
		});
		$.post(GetAbsoluteUrlAppRoot()+'designer/module.php', oMap, function(data)
				{
					onSubmitResult(data);
				});
	}
	else
	{
		// TODO: better error reporting !!!
		alert('Please fill all the fields before continuing...');
	}
}
<commit_msg>Forms: added the possibility to specify forbidden values + message to explain the issue(toolip) (fiwed a bug on the previous implementation, causing a javascript error, hence a stopper regression due to missing event binds)<commit_after>//iTop Designer widget for editing properties line by line
$(function()
{
	// the widget definition, where "itop" is the namespace,
	// "property_field" the widget name
	$.widget( "itop.property_field",
	{
		// default options
		options:
		{
			parent_selector: null,
			field_id: '',
			submit_to: 'index.php',
			submit_parameters: {operation: 'async_action'},
			do_apply: null,
			do_cancel: null,
			auto_apply: false

		},

		// the constructor
		_create: function()
		{
			var me = this;

			this.element
				.addClass( "itop-property-field" )
				.bind('apply_changes.itop-property-field', function(){me._do_apply();} );

			this.bModified = false;

			if (this.options.field_id != '')
			{
				$('#'+this.options.field_id).bind('change.itop-property-field', function() { me._on_change(); });
				this.value = this._get_field_value();
			}
			this.element.find(".prop_apply").bind('click.itop-property-field', function() { me._do_apply(); });
			this.element.find(".prop_cancel").bind('click.itop-property-field', function() { me._do_cancel(); });

			this._refresh();
		},

		// called when created, and later when changing options
		_refresh: function()
		{
			if (this.bModified)
			{
				this.element.addClass("itop-property-field-modified");
				this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: ''});
				this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: ''});
			}
			else
			{
				this.element.removeClass("itop-property-field-modified");
				this.element.find(".prop_icon span.ui-icon-circle-check").css({visibility: 'hidden'});
				this.element.find(".prop_icon span.ui-icon-circle-close").css({visibility: 'hidden'});
			}
		},

		// events bound via _bind are removed automatically
		// revert other modifications here
		_destroy: function()
		{
			this.element.removeClass( "itop-property-field" );
			this.element.removeClass("itop-property-field-modified");
		},

		// _setOptions is called with a hash of all options that are changing
		// always refresh when changing options
		_setOptions: function()
		{
			// in 1.9 would use _superApply
			this._superApply(arguments);
			this._refresh();
		},

		// _setOption is called for each individual option that is changing
		_setOption: function( key, value )
		{
			// in 1.9 would use _super
			this._superApply(arguments);
		},
		_on_change: function()
		{
			var new_value = this._get_field_value();
			if (new_value != this.value)
			{
				this.bModified = true;
				if (this.options.auto_apply)
				{
					this._do_apply();
				}
			}
			else
			{
				this.bModified = false;
			}
			this._refresh();
		},
		_get_field_value: function()
		{
			var oField = $('#'+this.options.field_id);
			if (oField.attr('type') == 'checkbox')
			{
				return (oField.attr('checked') == 'checked');
			}
			else
			{
				return oField.val();
			}
		},
		_get_committed_value: function()
		{
			return { name: $('#'+this.options.field_id).attr('name'), value: this.value };
		},
		_do_apply: function()
		{
			if (this.options.parent_selector)
			{
				$(this.options.parent_selector).trigger('mark_as_modified');
			}
			if (this.options.do_apply)
			{
				// specific behavior...
				if (this.options.do_apply())
				{
					this.bModified = false;
					this.previous_value = this.value;
					this.value = this._get_field_value();
					this._refresh();
				}
			}
			else
			{
				// Validate the field
				sFormId = this.element.closest('form').attr('id');
				var oField = $('#'+this.options.field_id);
				oField.trigger('validate');
				if ( $.inArray(this.options.field_id, oFormValidation[sFormId]) == -1)
				{
					this.bModified = false;
					this.previous_value = this.value;
					this.value = this._get_field_value();
					this._do_submit();
					this._refresh();
				}
			}
		},
		_do_cancel: function()
		{
			if (this.options.do_cancel)
			{
				// specific behavior...
				this.options.do_cancel();
			}
			else
			{
				this.bModified = false;
				var oField = $('#'+this.options.field_id);
				if (oField.attr('type') == 'checkbox')
				{
					if (this.value)
					{
						oField.attr('checked', true);
					}
					else
					{
						oField.removeAttr('checked');
					}
				}
				else
				{
					oField.val(this.value);
				}
				this._refresh();
				oField.trigger('reverted', {type: 'designer', previous_value: this.value });
				oField.trigger('validate');
			}
		},
		_do_submit: function()
		{
			var oData = {};
			this.element.closest('form').find(':input[type=hidden]').each(function()
			{
				// Hidden form fields
				oData[$(this).attr('name')] = $(this).val();
			});
			this.element.closest('form').find('.itop-property-field').each(function()
			{
				var oWidget = $(this).data('itopProperty_field');
				if (oWidget && oWidget._is_visible())
				{
					var oVal = oWidget._get_committed_value();
					oData[oVal.name] = oVal.value;
				}
			});
			oPostedData = this.options.submit_parameters;
			oPostedData.params = oData;
			oPostedData.params.updated = [ $('#'+this.options.field_id).attr('name') ]; // only one field updated in this case
			oPostedData.params.previous_values = {};
			oPostedData.params.previous_values[oPostedData.params.updated] = this.previous_value; // pass also the previous value(s)
			$.post(this.options.submit_to, oPostedData, function(data)
			{
				$('#prop_submit_result').html(data);
			});
		},
		_is_visible: function()
		{
			return this.element.parent().is(':visible');
		}
	});
});

var oFormValidation = {};

function ValidateWithPattern(sFieldId, bMandatory, sPattern, sFormId, aForbiddenValues, sExplainForbiddenValues)
{
	var currentVal = $('#'+sFieldId).val();
	var bValid = true;
	var sMessage = null;

	if (bMandatory && (currentVal == ''))
	{
		bValid = false;
	}
	if ((sPattern != '') && (currentVal != ''))
	{
		re = new RegExp(sPattern);
		bValid = re.test(currentVal);
	}
	if (aForbiddenValues)
	{
		for(var i = 0; i < aForbiddenValues.length; i++)
		{
			if (aForbiddenValues[i] == currentVal)
			{
				bValid = false;
				sMessage = sExplainForbiddenValues;
				break;
			}
		}
	}

	if (oFormValidation[sFormId] == undefined) oFormValidation[sFormId] = [];
	if (!bValid)
	{
		$('#v_'+sFieldId).addClass('ui-state-error');
		oFormValidation[sFormId].push(sFieldId);
		if (sMessage)
		{
			$('#'+sFieldId).attr('title', sMessage).tooltip();
			if ($('#'+sFieldId).is(":focus"))
			{
				$('#'+sFieldId).tooltip('open');
			}
		}
	}
	else
	{
		$('#v_'+sFieldId).removeClass('ui-state-error');
		if ($('#'+sFieldId).data('uiTooltip'))
		{
			$('#'+sFieldId).tooltip('close');
		}
		$('#'+sFieldId).removeAttr('title');
		// Remove the element from the array
		iFieldIdPos = oFormValidation[sFormId].indexOf(sFieldId);
		oFormValidation[sFormId].splice(iFieldIdPos, 1);
	}
}

function ValidateForm(sFormId, bValidateAll)
{
	oFormValidation[sFormId] = [];
	if (bValidateAll)
	{
		$('#'+sFormId+' :input').trigger('validate');
	}
	else
	{
		// Only the visible fields
		$('#'+sFormId+' :input:visible').each(function() {
			$(this).trigger('validate');
		});
	}
	return oFormValidation[sFormId];
}

function ReadFormParams(sFormId)
{
	var oMap = { };
	$('#'+sFormId+' :input').each( function() {
		if ($(this).parent().is(':visible'))
		{
			var sName = $(this).attr('name');
			if (sName && sName != '')
			{
				if (this.type == 'checkbox')
				{
					oMap[sName] = ($(this).attr('checked') == 'checked');
				}
				else
				{
					oMap[sName] = $(this).val();
				}

			}
		}
	});
	return oMap;
}

function SubmitForm(sFormId, onSubmitResult)
{
	var aErrors = ValidateForm(sFormId, false);
	if (aErrors.length == 0)
	{
		var oMap = ReadFormParams(sFormId);
		oMap.module_name = sCurrentModule;
		$('#'+sFormId+' :input').each( function() {
			if ($(this).parent().is(':visible'))
			{
				var sName = $(this).attr('name');
				if (sName && sName != '')
				{
					if (this.type == 'checkbox')
					{
						oMap[sName] = ($(this).attr('checked') == 'checked');
					}
					else
					{
						oMap[sName] = $(this).val();
					}

				}
			}
		});
		$.post(GetAbsoluteUrlAppRoot()+'designer/module.php', oMap, function(data)
				{
					onSubmitResult(data);
				});
	}
	else
	{
		// TODO: better error reporting !!!
		alert('Please fill all the fields before continuing...');
	}
}
<|endoftext|>


<commit_before>var SystemSettings = SystemSettings || {};
var num_particles = 2;
SystemSettings.standardMaterial = new THREE.ShaderMaterial( {

    uniforms: {
        texture:  { type: 't',  value: new THREE.ImageUtils.loadTexture( 'images/blank.png' ) },
    },

    attributes: {
        velocity: { type: 'v3', value: new THREE.Vector3() },
        color:    { type: 'v4', value: new THREE.Vector3( 0.0, 0.0, 1.0, 1.0 ) },
        lifetime: { type: 'f', value: 1.0 },
        size:     { type: 'f', value: 1.0 },
    },

    vertexShader:   document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,

    blending:    Gui.values.blendTypes,
    transparent: Gui.values.transparent,
    depthTest:   Gui.values.depthTest,

} );

////////////////////////////////////////////////////////////////////////////////
// Basic system
////////////////////////////////////////////////////////////////////////////////

SystemSettings.basic = {

    // Particle material
    particleMaterial : SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : SphereInitializer,
    initializerSettings : {
        sphere: new THREE.Vector4 ( 0.0, 0.0, 0.0, 10.0),
        color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
        lifetime: 7,
        size:     6.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, 0, 0),
            attractors : [],
        },
        collidables: {},
    },

    // Scene
    maxParticles :  num_particles,
    particlesFreq : 200000,
    createScene : function () {},
};

////////////////////////////////////////////////////////////////////////////////
// Fountain system
////////////////////////////////////////////////////////////////////////////////
SystemSettings.axisBounce = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 14,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

SystemSettings.fountainBounce = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 14,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

SystemSettings.fountainSink = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 7,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            sinkPlanes : [ { plane : new THREE.Vector4( 0, 1, 0, 0 ) } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

////////////////////////////////////////////////////////////////////////////////
// Attractor system
////////////////////////////////////////////////////////////////////////////////

SystemSettings.attractor = {

    // Particle material
    particleMaterial : SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : SphereInitializer,
     initializerSettings : {
	 sphere:   new THREE.Vector4 ( 0.0, 0.0, 0.0, 5.0),
	 color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
	 lifetime: 7,
	 size:     6.0,
     },

     // Update
     updaterFunction : EulerUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, 0, 0),
	     attractors : [ new THREE.Sphere( new THREE.Vector3(30.0, 30.0, 30.0), 1500.0 ) ],
	 },
	 collidables: {},
     },

     // Scene
     maxParticles :  10000,
     particlesFreq : 1000,
     createScene : function () {
	 var sphere_geo = new THREE.SphereGeometry( 1.0, 32, 32 );
	 var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );
	 var sphere = new THREE.Mesh( sphere_geo, phong )

	 sphere.position.set (30.0, 30.0, 30.0);
	 Scene.addObject( sphere );
     },
 };

 ////////////////////////////////////////////////////////////////////////////////
 // Horse animation
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.animated = {

     // Particle Material
     particleMaterial :  SystemSettings.standardMaterial,

     // Initializer
     initializerFunction : AnimationInitializer,
     initializerSettings : {
	 position: new THREE.Vector3 ( 0.0, 60.0, 0.0),
	 color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, -40.0),
	 lifetime: 1.25,
	 size:     2.0,
     },

     // Updater
     updaterFunction : EulerUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, 0, 0),
	     attractors : [],
	 },
	 collidables: {
	     bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
	 },
     },

     // Scene
     maxParticles:  20000,
     particlesFreq: 10000,
     createScene : function () {
	 var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
	 var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x444444, side: THREE.DoubleSide } );
	 var plane = new THREE.Mesh( plane_geo, phong );
	 plane.rotation.x = -1.57;
	 plane.position.y = 0;

	 Scene.addObject( plane );
     },

     // Animation
     animatedModelName: "animated_models/horse.js",
     animationLoadFunction : function( geometry ) {

	 mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x606060, morphTargets: true, transparent:true, opacity:0.5 } ) );
	 mesh.scale.set( 0.25, 0.25, 0.25 );
	 // mesh.position.set( 0.0, 30.0, 0.0 );
	 Scene.addObject( mesh );
	 ParticleEngine.addMesh( mesh );

	 ParticleEngine.addAnimation( new THREE.MorphAnimation( mesh ) );
     },

 };

 ////////////////////////////////////////////////////////////////////////////////
 // Cloth
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.cloth = {

     // Particle Material
     particleMaterial :  new THREE.MeshLambertMaterial( { color:0xff0000, side: THREE.DoubleSide  } ),

     // Initializer
     initializerFunction : ClothInitializer,
     initializerSettings : {
	 position: new THREE.Vector3 ( 0.0, 60.0, 0.0),
	 color:    new THREE.Vector4 ( 1.0, 0.0, 0.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
     },

     // Updater
     updaterFunction : ClothUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, -10.0, 0),
	     attractors : [],
	 },
	 collidables: {
	     bounceSpheres: [ {sphere : new THREE.Vector4( 0, 0, 0, 52.0 ), damping : 0.0 } ],
	 },
     },

     // Scene
     maxParticles:  400,
     particlesFreq: 1000,
     createScene : function () {
	 var sphere_geo = new THREE.SphereGeometry( 50.0, 32, 32 );
	 var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );

	 Scene.addObject( new THREE.Mesh( sphere_geo, phong ) );

     },

     // Cloth specific settings
     cloth : true,
     width : 20,
     height : 20,
 };

 var RAD = 8000;

 ////////////////////////////////////////////////////////////////////////////////
 // My System
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.mySystem = {

     // Particle material
     particleMaterial : SystemSettings.standardMaterial,

     // Initialization
     initializerFunction : SphereInitializer,
    initializerSettings : {
        sphere: new THREE.Vector4 ( 0.0, 0.0, 0.0, 100.0),
        color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
        lifetime: 6,
        size:     2.5,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, 0.0, 0),
            attractors : [ ],

        },
        collidables: {},
    },

    // Scene
    maxParticles :  16,
    particlesFreq : 1000,
    createScene : function () {

        var sphere_geo = new THREE.SphereGeometry( 1.0, 32, 32 );
        var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );
        var sphere = new THREE.Mesh( sphere_geo, phong )

        sphere.position.set (300.0, 300.0, 300.0);
        Scene.addObject( sphere );

        sphere.position.set (-300.0, 300.0, 300.0);
        Scene.addObject( sphere );

    },

};
<commit_msg>James' last commit<commit_after>var SystemSettings = SystemSettings || {};
var num_particles = 2;
SystemSettings.standardMaterial = new THREE.ShaderMaterial( {

    uniforms: {
        texture:  { type: 't',  value: new THREE.ImageUtils.loadTexture( 'images/blank.png' ) },
    },

    attributes: {
        velocity: { type: 'v3', value: new THREE.Vector3() },
        color:    { type: 'v4', value: new THREE.Vector3( 0.0, 0.0, 1.0, 1.0 ) },
        lifetime: { type: 'f', value: 1.0 },
        size:     { type: 'f', value: 1.0 },
    },

    vertexShader:   document.getElementById( 'vertexShader' ).textContent,
    fragmentShader: document.getElementById( 'fragmentShader' ).textContent,

    blending:    Gui.values.blendTypes,
    transparent: Gui.values.transparent,
    depthTest:   Gui.values.depthTest,

} );

////////////////////////////////////////////////////////////////////////////////
// Basic system
////////////////////////////////////////////////////////////////////////////////

SystemSettings.basic = {

    // Particle material
    particleMaterial : SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : SphereInitializer,
    initializerSettings : {
        sphere: new THREE.Vector4 ( 0.0, 0.0, 0.0, 10.0),
        color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
        lifetime: 7,
        size:     6.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, 0, 0),
            attractors : [],
        },
        collidables: {},
    },

    // Scene
    maxParticles :  num_particles,
    particlesFreq : 200000,
    createScene : function () {},
};

////////////////////////////////////////////////////////////////////////////////
// Fountain system
////////////////////////////////////////////////////////////////////////////////
SystemSettings.axisBounce = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 14,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

SystemSettings.fountainBounce = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 14,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

SystemSettings.fountainSink = {

    // Particle material
    particleMaterial :  SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : FountainInitializer,
    initializerSettings : {
        sphere:   new THREE.Vector4 ( 0.0, 30.0, 0.0, 1.0 ),
        color:    new THREE.Vector4 ( 0.0, 0.0, 1.0, 1.0 ),
        velocity: new THREE.Vector3 ( 0.0, 30.0, 0.0),
        lifetime: 7,
        size:     5.0,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, -20, 0),
            attractors : [],
        },
        collidables: {
            sinkPlanes : [ { plane : new THREE.Vector4( 0, 1, 0, 0 ) } ],
        },
    },

    // Scene
    maxParticles :  5000,
    particlesFreq : 500,
    createScene : function () {
        var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
        var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive: 0x222222, side: THREE.DoubleSide } );

        var box_geo   = new THREE.BoxGeometry(10,30,10)

        var plane     = new THREE.Mesh( plane_geo, phong );
        var box       = new THREE.Mesh( box_geo, phong );
        box.position.set( 0.0, 15.0, 0.0 );

        plane.rotation.x = -1.57;
        plane.position.y = 0;

        Scene.addObject( plane );
        Scene.addObject( box );
    },
};

////////////////////////////////////////////////////////////////////////////////
// Attractor system
////////////////////////////////////////////////////////////////////////////////

SystemSettings.attractor = {

    // Particle material
    particleMaterial : SystemSettings.standardMaterial,

    // Initialization
    initializerFunction : SphereInitializer,
     initializerSettings : {
	 sphere:   new THREE.Vector4 ( 0.0, 0.0, 0.0, 5.0),
	 color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
	 lifetime: 7,
	 size:     6.0,
     },

     // Update
     updaterFunction : EulerUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, 0, 0),
	     attractors : [ new THREE.Sphere( new THREE.Vector3(30.0, 30.0, 30.0), 1500.0 ) ],
	 },
	 collidables: {},
     },

     // Scene
     maxParticles :  10000,
     particlesFreq : 1000,
     createScene : function () {
	 var sphere_geo = new THREE.SphereGeometry( 1.0, 32, 32 );
	 var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );
	 var sphere = new THREE.Mesh( sphere_geo, phong )

	 sphere.position.set (30.0, 30.0, 30.0);
	 Scene.addObject( sphere );
     },
 };

 ////////////////////////////////////////////////////////////////////////////////
 // Horse animation
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.animated = {

     // Particle Material
     particleMaterial :  SystemSettings.standardMaterial,

     // Initializer
     initializerFunction : AnimationInitializer,
     initializerSettings : {
	 position: new THREE.Vector3 ( 0.0, 60.0, 0.0),
	 color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, -40.0),
	 lifetime: 1.25,
	 size:     2.0,
     },

     // Updater
     updaterFunction : EulerUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, 0, 0),
	     attractors : [],
	 },
	 collidables: {
	     bouncePlanes: [ {plane : new THREE.Vector4( 0, 1, 0, 0 ), damping : 0.8 } ],
	 },
     },

     // Scene
     maxParticles:  20000,
     particlesFreq: 10000,
     createScene : function () {
	 var plane_geo = new THREE.PlaneBufferGeometry( 1000, 1000, 1, 1 );
	 var phong     = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x444444, side: THREE.DoubleSide } );
	 var plane = new THREE.Mesh( plane_geo, phong );
	 plane.rotation.x = -1.57;
	 plane.position.y = 0;

	 Scene.addObject( plane );
     },

     // Animation
     animatedModelName: "animated_models/horse.js",
     animationLoadFunction : function( geometry ) {

	 mesh = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: 0x606060, morphTargets: true, transparent:true, opacity:0.5 } ) );
	 mesh.scale.set( 0.25, 0.25, 0.25 );
	 // mesh.position.set( 0.0, 30.0, 0.0 );
	 Scene.addObject( mesh );
	 ParticleEngine.addMesh( mesh );

	 ParticleEngine.addAnimation( new THREE.MorphAnimation( mesh ) );
     },

 };

 ////////////////////////////////////////////////////////////////////////////////
 // Cloth
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.cloth = {

     // Particle Material
     particleMaterial :  new THREE.MeshLambertMaterial( { color:0xff0000, side: THREE.DoubleSide  } ),

     // Initializer
     initializerFunction : ClothInitializer,
     initializerSettings : {
	 position: new THREE.Vector3 ( 0.0, 60.0, 0.0),
	 color:    new THREE.Vector4 ( 1.0, 0.0, 0.0, 1.0 ),
	 velocity: new THREE.Vector3 ( 0.0, 0.0, 0.0),
     },

     // Updater
     updaterFunction : ClothUpdater,
     updaterSettings : {
	 externalForces : {
	     gravity :     new THREE.Vector3( 0, -10.0, 0),
	     attractors : [],
	 },
	 collidables: {
	     bounceSpheres: [ {sphere : new THREE.Vector4( 0, 0, 0, 52.0 ), damping : 0.0 } ],
	 },
     },

     // Scene
     maxParticles:  400,
     particlesFreq: 1000,
     createScene : function () {
	 var sphere_geo = new THREE.SphereGeometry( 50.0, 32, 32 );
	 var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );

	 Scene.addObject( new THREE.Mesh( sphere_geo, phong ) );

     },

     // Cloth specific settings
     cloth : true,
     width : 20,
     height : 20,
 };

 var RAD = 8000;

 ////////////////////////////////////////////////////////////////////////////////
 // My System
 ////////////////////////////////////////////////////////////////////////////////

 SystemSettings.mySystem = {

     // Particle material
     particleMaterial : SystemSettings.standardMaterial,

     // Initialization
     initializerFunction : SphereInitializer,
    initializerSettings : {
        sphere: new THREE.Vector4 ( 0.0, 0.0, 0.0, 100.0),
        color:    new THREE.Vector4 ( 1.0, 1.0, 1.0, 1.0 ),
        lifetime: 6,
        size:     2.5,
    },

    // Update
    updaterFunction : EulerUpdater,
    updaterSettings : {
        externalForces : {
            gravity :     new THREE.Vector3( 0, 0.0, 0),
            attractors : [ ],

        },
        collidables: {},
    },

    // Scene
    maxParticles :  16,
    particlesFreq : 1000,
    createScene : function () {

        var sphere_geo = new THREE.SphereGeometry( 1.0, 32, 32 );
        var phong      = new THREE.MeshPhongMaterial( {color: 0x444444, emissive:0x442222, side: THREE.DoubleSide } );
        var sphere = new THREE.Mesh( sphere_geo, phong )

        sphere.position.set (300.0, 300.0, 300.0);
        Scene.addObject( sphere );

        sphere.position.set (-300.0, 300.0, 300.0);
        Scene.addObject( sphere );

    },

};
<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

function taxonomyPanel(divElement, options) {
    var nodeCount = 0;
    var panel = this;
    this.subscribers = [];
    var xhr = null;
    if (typeof componentsRegistry == "undefined") {
        componentsRegistry = [];
    }

    this.markerColor = 'black';
    this.type = "taxonomy";
    this.divElement = divElement;
    this.options = options;
    this.url = "http://107.170.33.116:3000/";
    var componentLoaded = false;
    $.each(componentsRegistry, function(i, field) {
        if (field.divElement.id == panel.divElement.id) {
            componentLoaded = true;
        }
    });
    if (componentLoaded == false) {
        componentsRegistry.push(panel);
    }

    this.history = [];

    this.setupCanvas = function() {
        var taxonomyHtml = "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-subscribersMarker' class='btn btn-link btn-lg' style='padding: 2px; position: absolute;top: 1px;right: 20px;'></button>"
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
Taxonomy
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + ""
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-configButton' class='btn btn-link' data-toggle='modal' style='padding:2px' data-target='#" + panel.divElement.id + "-configModal'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-collapseButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-expandButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-closeButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        $(divElement).html(taxonomyHtml);
        $("#" + panel.divElement.id + "-linkerButton").disableTextSelect();
        $("#" + panel.divElement.id + "-subscribersMarker").disableTextSelect();
        $("#" + panel.divElement.id + "-configButton").disableTextSelect();
        $("#" + panel.divElement.id + "-collapseButton").disableTextSelect();
        $("#" + panel.divElement.id + "-expandButton").disableTextSelect();
        $("#" + panel.divElement.id + "-closeButton").disableTextSelect();
        $("#" + panel.divElement.id + "-expandButton").hide();
        $("#" + panel.divElement.id + "-subscribersMarker").hide();
        $("#" + panel.divElement.id + "-closeButton").click(function(event) {
            $(divElement).remove();
        });
        $("#" + panel.divElement.id + "-expandButton").click(function(event) {
            $("#" + panel.divElement.id + "-panelBody").slideDown("fast");
            $("#" + panel.divElement.id + "-expandButton").hide();
            $("#" + panel.divElement.id + "-collapseButton").show();
        });
        $("#" + panel.divElement.id + "-collapseButton").click(function(event) {
            $("#" + panel.divElement.id + "-panelBody").slideUp("fast");
            $("#" + panel.divElement.id + "-expandButton").show();
            $("#" + panel.divElement.id + "-collapseButton").hide();
        });
        $("#" + panel.divElement.id + "-linkerButton").draggable({
            containment: 'window',
            helper: 'clone',
            delay: 500
        });
        $("#" + panel.divElement.id + "-linkerButton").droppable({
            drop: panel.handlePanelDropEvent,
            hoverClass: "bg-info"
        });

        //$("#"  + panel.divElement.id +  "-mainPanel").resizable();

        $("#" + panel.divElement.id + "-linkerButton").click(function(event) {
            $("#" + panel.divElement.id + "-linkerButton").popover({
                trigger: 'manual',
                placement: 'bottom',
                html: true,
                content: function() {
                    linkerHtml = '
Drag to link with other panels
';
                    if (panel.subscribers.length == 1) {
                        linkerHtml = linkerHtml + panel.subscribers.length + ' link established
';
                    } else {
                        linkerHtml = linkerHtml + panel.subscribers.length + ' links established
';
                    }
                    return linkerHtml;
                }
            });
            $("#" + panel.divElement.id + "-linkerButton").popover('toggle');
        });
    }

    this.addTree = function() {
        var treeHtml = "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "<button class='btn btn-link btn-xs load-children-button' style='padding:2px'></button>";
        treeHtml = treeHtml + "SNOMED CT Root";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        $("#" + panel.divElement.id + "-panelBody").html(treeHtml);

        $(".load-children-button").disableTextSelect();

        $('#' + panel.divElement.id + "-treenode-" + 138875005).draggable({
            containment: 'window',
            helper: 'clone',
            delay: 500
        });
        $('#' + panel.divElement.id + "-treenode-" + 138875005).click(function(event) {
            var selectedId = $(event.target).attr('data-concept-id');
            if (typeof selectedId != "undefined") {
                $.each(panel.subscribers, function(i, suscriberPanel) {
                    suscriberPanel.conceptId = selectedId;
                    suscriberPanel.updateCanvas();
                });
            }
        });

        this.addOpenTreeClickAction(panel.divElement.id + "-treeicon-" + 138875005);
    }

    this.addOpenTreeClickAction = function(iconId) {
        $("#" + iconId).click(function(event) {
            event.preventDefault();
            if ($("#" + iconId).hasClass("glyphicon-chevron-down")) {
                //console.log("close");
                $(event.target).closest("li").find("ul").remove();
                $("#" + iconId).removeClass("glyphicon-chevron-down");
                $("#" + iconId).addClass("glyphicon-chevron-right");
            } else {
                //console.log("open");
                $("#" + iconId).removeClass("glyphicon-chevron-right");
                $("#" + iconId).addClass("glyphicon-refresh");
                $("#" + iconId).addClass("icon-spin");
                panel.getChildren($(event.target).closest("li").attr('data-concept-id'));
            }
        });
    }

    this.getChildren = function(conceptId) {
        $.getJSON(panel.url + "browser-2/snomed/concepts/" + conceptId + "/children?form=inferred", function(result) {
            var nodeHtml = "
";
            result.sort(function(a, b) {
                if (a.defaultTerm  b.defaultTerm)
                    return 1;
                return 0;
            })
            //console.log(JSON.stringify(result));
            var listIconIds = [];
            $.each(result, function(i, field) {
                if (field.active == true) {
                    nodeHtml = nodeHtml + "
";
                    nodeHtml = nodeHtml + "<button class='btn btn-link btn-xs load-children-button' style='padding:2px'></button>";
                    nodeHtml = nodeHtml + field.defaultTerm;
                    listIconIds.push(field.conceptId);
                }
            });
            nodeHtml = nodeHtml + "
";
            nodeHtml = nodeHtml + "
";
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).removeClass("glyphicon-refresh");
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).removeClass("icon-spin");
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).addClass("glyphicon-chevron-down");

            $("#" + panel.divElement.id + "-treenode-" + conceptId).append(nodeHtml);
            $(".load-children-button").disableTextSelect();
            //console.log(JSON.stringify(listIconIds));
            $.each(listIconIds, function(i, nodeId) {
                panel.addOpenTreeClickAction(panel.divElement.id + "-treeicon-" + nodeId);
                $('#' + panel.divElement.id + "-treenode-" + nodeId).draggable({
                    containment: 'window',
                    helper: 'clone',
                    delay: 500
                });
//                $('#' + panel.divElement.id + "-treenode-" + nodeId).click(function(event) {
//                    $.each(panel.subscribers, function(i, suscriberPanel) {
//                        console.log("click " + nodeId)
//                        suscriberPanel.conceptId = nodeId;
//                        suscriberPanel.updateCanvas();
//                    });
//                });
            });
        });
    }

    this.handlePanelDropEvent = function(event, ui) {
        var draggable = ui.draggable;
        if (!draggable.attr('data-panel')) {
        } else {
            $.each(componentsRegistry, function(i, field) {
                if (field.divElement.id == draggable.attr('data-panel')) {
                    if (field.type == "concept-details") {
                        panel.subscribe(field);
                    }
                }
            });
        }
    }

    this.subscribe = function(subscriber) {
        var alreadySubscribed = false;
        $.each(panel.subscribers, function(i, field) {
            if (subscriber.divElement.id == field.divElement.id) {
                alreadySubscribed = true;
            }
        });
        if (!alreadySubscribed) {
            if (panel.subscribers.length == 0) {
                if (typeof globalMarkerColor == "undefined") {
                    globalMarkerColor = 'black';
                }
                panel.markerColor = panel.getNextMarkerColor(globalMarkerColor);
                //console.log(panel.markerColor);
                $("#" + panel.divElement.id + "-subscribersMarker").css('color', panel.markerColor);
                $("#" + panel.divElement.id + "-subscribersMarker").show();
            }
            panel.subscribers.push(subscriber);
            subscriber.setSubscription(panel);
        }
    }

    this.unsubscribe = function(subscriber) {
        var indexToRemove = -1;
        var i = 0;
        $.each(panel.subscribers, function(i, field) {
            if (subscriber.divElement.id == field.divElement.id) {
                indexToRemove = i;
            }
            i = i + 1;
        });
        if (indexToRemove > -1) {
            panel.subscribers.splice(indexToRemove, 1);
        }
        if (panel.subscribers.length == 0) {
            $("#" + panel.divElement.id + "-subscribersMarker").hide();
        }
        subscriber.clearSubscription();
    }

    this.unsubscribeAll = function() {
        $.each(panel.subscribers, function(i, field) {
            this.unsubscribe(field);
        });
    }

    this.getNextMarkerColor = function(color) {
//console.log(color);
        var returnColor = 'black';
        if (color == 'black') {
            returnColor = 'green';
        } else if (color == 'green') {
            returnColor = 'purple';
        } else if (color == 'purple') {
            returnColor = 'red';
        } else if (color == 'red') {
            returnColor = 'blue';
        } else if (color == 'blue') {
            returnColor = 'green';
        }
//console.log(returnColor);
        globalMarkerColor = returnColor;
        return returnColor;
    }

    this.setupCanvas();
    this.addTree();
}
<commit_msg>taxonomy tree fixed for firefox and chrome<commit_after>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

function taxonomyPanel(divElement, options) {
    var nodeCount = 0;
    var panel = this;
    this.subscribers = [];
    var xhr = null;
    if (typeof componentsRegistry == "undefined") {
        componentsRegistry = [];
    }

    this.markerColor = 'black';
    this.type = "taxonomy";
    this.divElement = divElement;
    this.options = options;
    this.url = "http://107.170.33.116:3000/";
    var componentLoaded = false;
    $.each(componentsRegistry, function(i, field) {
        if (field.divElement.id == panel.divElement.id) {
            componentLoaded = true;
        }
    });
    if (componentLoaded == false) {
        componentsRegistry.push(panel);
    }

    this.history = [];

    this.setupCanvas = function() {
        var taxonomyHtml = "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-subscribersMarker' class='btn btn-link btn-lg' style='padding: 2px; position: absolute;top: 1px;right: 20px;'></button>"
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
Taxonomy
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + ""
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-configButton' class='btn btn-link' data-toggle='modal' style='padding:2px' data-target='#" + panel.divElement.id + "-configModal'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-collapseButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-expandButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "<button id='" + panel.divElement.id + "-closeButton' class='btn btn-link' style='padding:2px'></button>"
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        taxonomyHtml = taxonomyHtml + "
";
        $(divElement).html(taxonomyHtml);
        $("#" + panel.divElement.id + "-linkerButton").disableTextSelect();
        $("#" + panel.divElement.id + "-subscribersMarker").disableTextSelect();
        $("#" + panel.divElement.id + "-configButton").disableTextSelect();
        $("#" + panel.divElement.id + "-collapseButton").disableTextSelect();
        $("#" + panel.divElement.id + "-expandButton").disableTextSelect();
        $("#" + panel.divElement.id + "-closeButton").disableTextSelect();
        $("#" + panel.divElement.id + "-expandButton").hide();
        $("#" + panel.divElement.id + "-subscribersMarker").hide();
        $("#" + panel.divElement.id + "-closeButton").click(function(event) {
            $(divElement).remove();
        });
        $("#" + panel.divElement.id + "-expandButton").click(function(event) {
            $("#" + panel.divElement.id + "-panelBody").slideDown("fast");
            $("#" + panel.divElement.id + "-expandButton").hide();
            $("#" + panel.divElement.id + "-collapseButton").show();
        });
        $("#" + panel.divElement.id + "-collapseButton").click(function(event) {
            $("#" + panel.divElement.id + "-panelBody").slideUp("fast");
            $("#" + panel.divElement.id + "-expandButton").show();
            $("#" + panel.divElement.id + "-collapseButton").hide();
        });
        $("#" + panel.divElement.id + "-linkerButton").draggable({
            containment: 'window',
            helper: 'clone',
            delay: 500
        });
        $("#" + panel.divElement.id + "-linkerButton").droppable({
            drop: panel.handlePanelDropEvent,
            hoverClass: "bg-info"
        });

        //$("#"  + panel.divElement.id +  "-mainPanel").resizable();

        $("#" + panel.divElement.id + "-linkerButton").click(function(event) {
            $("#" + panel.divElement.id + "-linkerButton").popover({
                trigger: 'manual',
                placement: 'bottom',
                html: true,
                content: function() {
                    linkerHtml = '
Drag to link with other panels
';
                    if (panel.subscribers.length == 1) {
                        linkerHtml = linkerHtml + panel.subscribers.length + ' link established
';
                    } else {
                        linkerHtml = linkerHtml + panel.subscribers.length + ' links established
';
                    }
                    return linkerHtml;
                }
            });
            $("#" + panel.divElement.id + "-linkerButton").popover('toggle');
        });
    }

    this.addTree = function() {
        var treeHtml = "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "<button class='btn btn-link btn-xs load-children-button treeButton' style='padding:2px'></button>";
        treeHtml = treeHtml + "SNOMED CT Root";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        treeHtml = treeHtml + "
";
        $("#" + panel.divElement.id + "-panelBody").html(treeHtml);

        $(".load-children-button").disableTextSelect();

        $('#' + panel.divElement.id + "-treenode-" + 138875005).draggable({
            containment: 'window',
            helper: 'clone',
            delay: 500
        });
        $("#" + panel.divElement.id + "-panelBody").click(function(event) {
            if ($(event.target).hasClass("treeButton")) {
                conceptId = $(event.target).closest("li").attr('data-concept-id');
                iconId = panel.divElement.id + "-treeicon-" + conceptId;
                console.log(iconId);

                console.log(event.target);
                event.preventDefault();
                if ($("#" + iconId).hasClass("glyphicon-chevron-down")) {
                    //console.log("close");
                    $(event.target).closest("li").find("ul").remove();
                    $("#" + iconId).removeClass("glyphicon-chevron-down");
                    $("#" + iconId).addClass("glyphicon-chevron-right");
                } else {
                    //console.log("open");
                    $("#" + iconId).removeClass("glyphicon-chevron-right");
                    $("#" + iconId).addClass("glyphicon-refresh");
                    $("#" + iconId).addClass("icon-spin");
                    panel.getChildren($(event.target).closest("li").attr('data-concept-id'));
                }

            } else if ($(event.target).hasClass("treeLabel")) {
                var selectedId = $(event.target).attr('data-concept-id');
                if (typeof selectedId != "undefined") {
                    $.each(panel.subscribers, function(i, suscriberPanel) {
                        suscriberPanel.conceptId = selectedId;
                        suscriberPanel.updateCanvas();
                    });
                }
            }

        });

        //
    }

    this.addOpenTreeClickAction = function(iconId) {
        console.log(iconId);
        $("#" + iconId).click(function(event) {
            console.log(event.target);
            event.preventDefault();
            if ($("#" + iconId).hasClass("glyphicon-chevron-down")) {
                //console.log("close");
                $(event.target).closest("li").find("ul").remove();
                $("#" + iconId).removeClass("glyphicon-chevron-down");
                $("#" + iconId).addClass("glyphicon-chevron-right");
            } else {
                //console.log("open");
                $("#" + iconId).removeClass("glyphicon-chevron-right");
                $("#" + iconId).addClass("glyphicon-refresh");
                $("#" + iconId).addClass("icon-spin");
                panel.getChildren($(event.target).closest("li").attr('data-concept-id'));
            }
        });
    }

    this.getChildren = function(conceptId) {
        $.getJSON(panel.url + "browser-2/snomed/concepts/" + conceptId + "/children?form=inferred", function(result) {
            var nodeHtml = "
";
            result.sort(function(a, b) {
                if (a.defaultTerm  b.defaultTerm)
                    return 1;
                return 0;
            })
            //console.log(JSON.stringify(result));
            var listIconIds = [];
            $.each(result, function(i, field) {
                if (field.active == true) {
                    nodeHtml = nodeHtml + "
";
                    nodeHtml = nodeHtml + "<button class='btn btn-link btn-xs load-children-button treeButton' style='padding:2px'></button>";
                    nodeHtml = nodeHtml + field.defaultTerm;
                    listIconIds.push(field.conceptId);
                }
            });
            nodeHtml = nodeHtml + "
";
            nodeHtml = nodeHtml + "
";
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).removeClass("glyphicon-refresh");
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).removeClass("icon-spin");
            $("#" + panel.divElement.id + "-treeicon-" + conceptId).addClass("glyphicon-chevron-down");

            $("#" + panel.divElement.id + "-treenode-" + conceptId).append(nodeHtml);
            $(".load-children-button").disableTextSelect();
            //console.log(JSON.stringify(listIconIds));
            $.each(listIconIds, function(i, nodeId) {
                //panel.addOpenTreeClickAction(panel.divElement.id + "-treeicon-" + nodeId);
                $('#' + panel.divElement.id + "-treenode-" + nodeId).draggable({
                    containment: 'window',
                    helper: 'clone',
                    delay: 500
                });
//                $('#' + panel.divElement.id + "-treenode-" + nodeId).click(function(event) {
//                    $.each(panel.subscribers, function(i, suscriberPanel) {
//                        console.log("click " + nodeId)
//                        suscriberPanel.conceptId = nodeId;
//                        suscriberPanel.updateCanvas();
//                    });
//                });
            });
        });
    }

    this.handlePanelDropEvent = function(event, ui) {
        var draggable = ui.draggable;
        if (!draggable.attr('data-panel')) {
        } else {
            $.each(componentsRegistry, function(i, field) {
                if (field.divElement.id == draggable.attr('data-panel')) {
                    if (field.type == "concept-details") {
                        panel.subscribe(field);
                    }
                }
            });
        }
    }

    this.subscribe = function(subscriber) {
        var alreadySubscribed = false;
        $.each(panel.subscribers, function(i, field) {
            if (subscriber.divElement.id == field.divElement.id) {
                alreadySubscribed = true;
            }
        });
        if (!alreadySubscribed) {
            if (panel.subscribers.length == 0) {
                if (typeof globalMarkerColor == "undefined") {
                    globalMarkerColor = 'black';
                }
                panel.markerColor = panel.getNextMarkerColor(globalMarkerColor);
                //console.log(panel.markerColor);
                $("#" + panel.divElement.id + "-subscribersMarker").css('color', panel.markerColor);
                $("#" + panel.divElement.id + "-subscribersMarker").show();
            }
            panel.subscribers.push(subscriber);
            subscriber.setSubscription(panel);
        }
    }

    this.unsubscribe = function(subscriber) {
        var indexToRemove = -1;
        var i = 0;
        $.each(panel.subscribers, function(i, field) {
            if (subscriber.divElement.id == field.divElement.id) {
                indexToRemove = i;
            }
            i = i + 1;
        });
        if (indexToRemove > -1) {
            panel.subscribers.splice(indexToRemove, 1);
        }
        if (panel.subscribers.length == 0) {
            $("#" + panel.divElement.id + "-subscribersMarker").hide();
        }
        subscriber.clearSubscription();
    }

    this.unsubscribeAll = function() {
        $.each(panel.subscribers, function(i, field) {
            this.unsubscribe(field);
        });
    }

    this.getNextMarkerColor = function(color) {
//console.log(color);
        var returnColor = 'black';
        if (color == 'black') {
            returnColor = 'green';
        } else if (color == 'green') {
            returnColor = 'purple';
        } else if (color == 'purple') {
            returnColor = 'red';
        } else if (color == 'red') {
            returnColor = 'blue';
        } else if (color == 'blue') {
            returnColor = 'green';
        }
//console.log(returnColor);
        globalMarkerColor = returnColor;
        return returnColor;
    }

    this.setupCanvas();
    this.addTree();
}
<|endoftext|>


<commit_before>"use strict";

// Perseus module uses React directly and uses $._ directly for
// localization, so we do this as a hack to get it to work
function perseusPrep($, React, katex, KAS, MathJax) {
    window.React = React;
    $._ = function(x) { return x; };
    window.$_ = function(x) { return x; };
    window.katex = katex
    window.KAS = KAS;
    window.MathJax = MathJax;
}

define(["jquery", "react", "util", "models", "apiclient", "storage", "katex", "kas", "mathjax"],
        function($, React, Util, models, APIClient, Storage, katex, KAS, MathJax) {
    var cx = React.addons.classSet;

    /**
     * Represents a single exercise, it will load the exercise dynamically and
     * display it to the user.
     */
    var ExerciseViewer = React.createClass({
        propTypes: {
            exercise: React.PropTypes.object.isRequired
        },
        mixins: [Util.BackboneMixin],
        getBackboneModels: function() {
            return [this.props.exercise];
        },
        getInitialState: function() {
            return { };
        },
        refreshRandomAssessment: function() {
            var count = this.exercise.all_assessment_items.length;
            var randomIndex = Math.floor(Math.random() * count);
            var randomAssessmentSHA1 = this.exercise.all_assessment_items[randomIndex].sha1;
            var randomAssessmentId = this.exercise.all_assessment_items[randomIndex].id;
            var problemTypes = this.exercise.problem_types;
            var problemTypeName = problemTypes[problemTypes.length - 1].name;
            APIClient.getAssessmentItem(randomAssessmentId).done((result) => {
                Util.log("got assessment item: %o: item data: %o", result, JSON.parse(result.item_data));
                this.setState({
                    perseusItemData: JSON.parse(result.item_data)
                });
                console.log("submitting exercise progres");
                // test
                var problemNumber = 2;
                var attemptNumber = 1;
                var isCorrect = true;
                var hintsUsed = 0;
                var secondsTaken = 10;
                var problemType = "";
                // TODO: Need to properly determine the problemNumber or else you get an out of order exception
                // on the server side (500 HTTP status code).
                APIClient.reportExerciseProgress(this.props.exercise.getName(), problemNumber,
                                                 randomAssessmentSHA1, randomAssessmentId,
                                                 secondsTaken, hintsUsed, isCorrect, attemptNumber,
                                                 problemTypeName);
            });
        },
        componentWillMount: function() {
            if (this.props.exercise.isPerseusExercise()) {
                APIClient.getExerciseByName(this.props.exercise.getName()).done((result) => {
                    this.exercise = result;
                    Util.log("got exercise: %o", result);
                    this.refreshRandomAssessment();
                });
            }

            perseusPrep($, React, katex, KAS, MathJax);
            require(["perseus"], (Perseus) => {
                Perseus.init({}).then(() => {
                    Util.log("Perseus init done");
                    this.ItemRenderer = Perseus.ItemRenderer;
                    this.forceUpdate();
                });
            });
        },
        componentDidMount: function() {
        },
        componentWillUnmount: function() {
        },
        render: function() {
            var content;
            if (this.state.error) {
                content =
Could not load exercise
;
            } else if (this.props.exercise.isKhanExercisesExercise()) {
                var path = `/khan-exercises/exercises/${this.props.exercise.getFilename()}`;
                content = ;
            } else if(this.ItemRenderer && this.state.perseusItemData) {
                content =

                              <this.ItemRenderer item={this.state.perseusItemData}
                                                 problemNum={Math.floor(Math.random() * 50) + 1}
                                                 initialHintsVisible={this.state.perseusItemData.hints.length}
                                                 enabledFeatures={{
                                                     highlight: true,
                                                     toolTipFormats: true
                                                 }} />

;
                }

            Util.log("render exercise: :%o", this.props.exercise);
            return

                {content}

;
        }
    });

    return {
        ExerciseViewer,
    };
});
<commit_msg>Fix problem out of order 500 errors<commit_after>"use strict";

// Perseus module uses React directly and uses $._ directly for
// localization, so we do this as a hack to get it to work
function perseusPrep($, React, katex, KAS, MathJax) {
    window.React = React;
    $._ = function(x) { return x; };
    window.$_ = function(x) { return x; };
    window.katex = katex
    window.KAS = KAS;
    window.MathJax = MathJax;
}

define(["jquery", "react", "util", "models", "apiclient", "storage", "katex", "kas", "mathjax"],
        function($, React, Util, models, APIClient, Storage, katex, KAS, MathJax) {
    var cx = React.addons.classSet;

    /**
     * Represents a single exercise, it will load the exercise dynamically and
     * display it to the user.
     */
    var ExerciseViewer = React.createClass({
        propTypes: {
            exercise: React.PropTypes.object.isRequired
        },
        mixins: [Util.BackboneMixin],
        getBackboneModels: function() {
            return [this.props.exercise];
        },
        getInitialState: function() {
            return { };
        },
        refreshRandomAssessment: function() {
            var count = this.exercise.all_assessment_items.length;
            var randomIndex = Math.floor(Math.random() * count);
            var randomAssessmentSHA1 = this.exercise.all_assessment_items[randomIndex].sha1;
            var randomAssessmentId = this.exercise.all_assessment_items[randomIndex].id;
            var problemTypes = this.exercise.problem_types;
            var problemTypeName = problemTypes[problemTypes.length - 1].name;
            APIClient.getAssessmentItem(randomAssessmentId).done((result) => {
                Util.log("got assessment item: %o: item data: %o", result, JSON.parse(result.item_data));
                this.setState({
                    perseusItemData: JSON.parse(result.item_data)
                });
                // test
                var problemNumber = this.props.exercise.get("totalDone") + 1;
                var attemptNumber = 1;
                var isCorrect = true;
                var hintsUsed = 0;
                var secondsTaken = 10;
                var problemType = "";
                console.log("submitting exercise progress for problemNumber: %i", problemNumber);
                // TODO: Need to properly determine task id
                // on the server side (500 HTTP status code).
                // Also note this doesn't belong here, it's just for testing currently.
                /*
                APIClient.reportExerciseProgress(this.props.exercise.getName(), problemNumber,
                                                 randomAssessmentSHA1, randomAssessmentId,
                                                 secondsTaken, hintsUsed, isCorrect, attemptNumber,
                                                 problemTypeName);
                                                 */
            });
        },
        componentWillMount: function() {
            if (this.props.exercise.isPerseusExercise()) {
                APIClient.getExerciseByName(this.props.exercise.getName()).done((result) => {
                    this.exercise = result;
                    Util.log("got exercise: %o", result);
                    this.refreshRandomAssessment();
                });
            }

            perseusPrep($, React, katex, KAS, MathJax);
            require(["perseus"], (Perseus) => {
                Perseus.init({}).then(() => {
                    Util.log("Perseus init done");
                    this.ItemRenderer = Perseus.ItemRenderer;
                    this.forceUpdate();
                });
            });
        },
        componentDidMount: function() {
        },
        componentWillUnmount: function() {
        },
        render: function() {
            var content;
            if (this.state.error) {
                content =
Could not load exercise
;
            } else if (this.props.exercise.isKhanExercisesExercise()) {
                var path = `/khan-exercises/exercises/${this.props.exercise.getFilename()}`;
                content = ;
            } else if(this.ItemRenderer && this.state.perseusItemData) {
                content =

                              <this.ItemRenderer item={this.state.perseusItemData}
                                                 problemNum={Math.floor(Math.random() * 50) + 1}
                                                 initialHintsVisible={this.state.perseusItemData.hints.length}
                                                 enabledFeatures={{
                                                     highlight: true,
                                                     toolTipFormats: true
                                                 }} />

;
                }

            Util.log("render exercise: :%o", this.props.exercise);
            return

                {content}

;
        }
    });

    return {
        ExerciseViewer,
    };
});
<|endoftext|>