<commit_before>$(document).ready(function(){
    var nofinv = 1;
    $('#id_invoicenumber').addClass('invoice'+' '+nofinv);
    $('#id_invoicestatus').addClass('invoiceadditional'+' '+nofinv);
    $('#id_paidon').addClass('paid'+' '+nofinv);
    $('#id_rejectreason').addClass('reject'+' '+nofinv);
    $("#id_amount").addClass("amount"+" "+nofinv);
    $("#id_currency").addClass("currency"+" "+nofinv);
    $("#id_reasonother").addClass("other"+" "+nofinv);
    $('.addhiddendata:first').find('#id_invoicenumber').attr('id', 'id_invoicenumber'+nofinv);
    $('.addhiddendata:first').find('#id_invoicestatus').attr('id', 'id_invoicestatus'+nofinv);
    $('.addhiddendata:first').find('#id_paidon').attr('id', 'id_paidon'+nofinv);
    $('.addhiddendata:first').find('#id_rejectreason').attr('id', 'id_rejectreason'+nofinv);
    $(".addhiddendata:first").find("#id_amount").attr("id", "id_amount"+nofinv);
    $(".addhiddendata:first").find("#id_currency").attr("id", "id_currency"+nofinv);
    $("#id_reasonother").attr("id", "id_reasonother"+nofinv);

    $('#trbutton').on('click', function(){
	$('#trbutton').fadeOut('slow', function(){
	    $('#trform').fadeIn('slow');
	    $('#ptrack').html('Please fill in all the fields.');
	});
    });

    $('#id_reminderdate').datepicker({
	dateFormat: 'yy-mm-dd',
	constrainInput: false
    });
    $('.paid:first').datepicker({
	dateFormat: 'yy-mm-dd',
	constrainInput: false
    });

    var $name = $('#vclerk').attr('value');
    $('#id_clerk').val($name);

    $('#id_clerk').attr('readonly', true);
    $('#id_actiondate').attr('readonly', true);

    $('#id_market').on('change', function(){
	//show the ccode choice if is hidden
	if ($('#id_ccode').is(':hidden')) {$('#id_ccode').show()};

	$('#id_ccode option').each(function(){
	    $(this).show();
	});

	var market = $('#id_market').val();
	if (market == 'IT') {
	    var marketArray = ['', '11', '13', '15', '16'];
	} else if (market == 'DE') {
	    var marketArray = ['', '13', '52', '55', '60', '64', '66'];
	} else if (market == 'PT' || market == 'PL' || market == 'NL' || market == 'NO') {
	    var marketArray = ['', '10'];
	} else if (market == 'BE') {
	    var marketArray = ['', '12', '14', '18', '31'];
	} else if (market == 'SE') {
	    var marketArray = ['', '16'];
	} else if (market == 'FI') {
	    var marketArray = ['', '11'];
	} else if (market == 'DK') {
	    var marketArray = ['', '12'];
	} else {
	    var marketArray = [''];
	}

	$('#id_ccode option').each(function(){
	    var ccodeOpt = $(this).val();
	    if ($.inArray(ccodeOpt, marketArray) > -1){
		;
	    } else {
		$(this).hide();
	    }
	});

    });

    $(document).on('change', '.status', function() {
	var status = $(this).val();
	var nextform = $(this).parent().parent().parent().next();

	if (nextform.is(':hidden')){
	    ;
	} else {
	    nextform.hide();
	    if (nextform.find('.paid').is(':hidden')) {nextform.find('.paid').show()};
	    if (nextform.find('.other').is(':hidden')) {nextform.find('.other').show()};
	    if (nextform.find('.reject').is(':hidden')) {nextform.find('.reject').show()};
	    nextform.find('label').show();
	}

	if (status == 'RJ'){
	    nextform.find('.paid').hide();
	    nextform.find('label:last').hide();
	    nextform.fadeIn('slow');
	} else if (status == 'PD') {
	    nextform.find('.reject').hide();
	    nextform.find('label:first').hide();
	    nextform.fadeIn('slow');
	};
    });

    $('#addbutt').on('click', function() {
	var formToApp = $('.addhiddendata:first').clone();
	formToApp.find('button').remove();
	formToApp.find('.paid').removeClass('hasDatepicker');
	formToApp.find('.paid').val('');
	formToApp.find('#id_invoicenumber1').removeClass('invoice'+' '+nofinv);
	formToApp.find('#id_invoicestatus1').removeClass('invoiceadditional'+' '+nofinv);
	formToApp.find('#id_paidon1').removeClass('paid'+' '+nofinv);
	formToApp.find('#id_rejectreason1').removeClass('reject'+' '+nofinv);
	formToApp.find("#id_amount1").removeClass("amount"+" "+nofinv);
	formToApp.find("#id_currency1").removeClass("currency"+" "+nofinv);
	nofinv = nofinv + 1;
	formToApp.find('#id_rejectreason1').addClass('reject'+' '+nofinv);
	formToApp.find('#id_rejectreason1').attr('name', 'reject'+nofinv);
	formToApp.find('#id_rejectreason1').attr('id', 'id_rejectreason'+nofinv);
	formToApp.find('#id_paidon1').addClass('paid'+' '+nofinv);
	formToApp.find('#id_paidon1').attr('name', 'paid'+nofinv);
	formToApp.find('#id_paidon1').attr('id', 'id_paidon'+nofinv);
	formToApp.find('#id_invoicenumber1').addClass('invoice'+' '+nofinv);
	formToApp.find('#id_invoicenumber1').attr('name', 'invoicenumber'+nofinv);
	formToApp.find('#id_invoicenumber1').attr('id', 'id_invoicenumber'+nofinv);
	formToApp.find('#id_invoicestatus1').addClass('invoiceadditional'+' '+nofinv);
	formToApp.find('#id_invoicestatus1').attr('name', 'invoicestatus'+nofinv);
	formToApp.find('#id_invoicestatus1').attr('id', 'id_invoicestatus'+nofinv);
	formToApp.find("#id_amount1").addClass("amount"+" "+nofinv);
	formToApp.find("#id_amount1").attr("name", "amount"+nofinv);
	formToApp.find("#id_amount1").attr("id", "id_amount"+nofinv);
	formToApp.find("#id_currency1").addClass("currency"+" "+nofinv);
	formToApp.find("#id_currency1").attr("name", "currency"+nofinv);
	formToApp.find("#id_currency1").attr("id", "id_currency"+nofinv);
	$('#vendorform').before(formToApp);
	formToApp.find('.paid').datepicker({
	    dateFormat: 'yy-mm-dd',
	    constrainInput: false
	});
    });

    $('#rembutt').on('click', function() {
	//Remove additional invoices if there are at least 2 of them.
	if ($('.invoice').length == 1) {
	    ;
	} else {
	    $('.addhiddendata:last').remove();
	};
    });

    $('#id_reminderdate').on('change', function() {
	var rdate = $(this).val().split('-');
	var market = $('#id_market').val();
	$('#id_remindernumber').val('');
	$('#id_remindernumber').val(market+rdate[0]+rdate[1]+rdate[2]+'/');
    });

    function DunningTrack() {
	// get the total number of invoices.
	var invo = $('.invoice').length;

	var data = new Array()

	//loop through the invoice to create our data to post
	for (x = 1; x <= invo; x++) {
	    var formn = 'form'+x;
	    var obj = {
		market: $('#id_market').val(),
		ccode: $('#id_ccode').val(),
		clerk: $('#id_clerk').val(),
		actiondate: $('#id_actiondate').val(),
		reminderdate: $('#id_actiondate').val(),
		level: $('#id_level').val(),
		amount: $("#id_amount"+x).val(),
		currency: $("#id_currency"+x).val(),
		remindernumber: $('#id_remindernumber').val(),
		vendor: $('#id_vendor').val(),
		mailvendor: $('#id_mailvendor').val(),
		invoicenumber: $('#id_invoicenumber'+x).val(),
		invoicestatus: $('#id_invoicestatus'+x).val(),
		//actiontaken: $('#id_actiontaken').val(),
		rejectreason: $('#id_rejectreason'+x).val(),
		paidon: $('#id_paidon'+x).val()
	    };
	    data.push(obj);
	}

	//setup the AJAX request
	$.ajaxSetup({
	    type: 'POST',
	    dataType: 'json'
	});

	//the real AJAX request
	$.ajax({
	    url: '/ajax/',
	    data: {
		form_type: 'multi',
		mass_data: JSON.stringify(data)
	    },
	    success: window.location.replace("/main/"),
	    error: function (ajaxObj, textStatus, error) {
		alert(error);
	    }
	});
	return true;
    };

    $('#trackbutton').on('click', ValidateForm);

    function ValidateForm() {
	DunningTrack();
    };
});

function SuccessfulTracking() {
    $('#trform *').filter(':input').each(function() {
	$(this).val('');
    });
};
<commit_msg>Added elements with "other" class to the hide/show mechanism on the form.<commit_after>$(document).ready(function(){
    var nofinv = 1;
    $('#id_invoicenumber').addClass('invoice'+' '+nofinv);
    $('#id_invoicestatus').addClass('invoiceadditional'+' '+nofinv);
    $('#id_paidon').addClass('paid'+' '+nofinv);
    $('#id_rejectreason').addClass('reject'+' '+nofinv);
    $("#id_amount").addClass("amount"+" "+nofinv);
    $("#id_currency").addClass("currency"+" "+nofinv);
    $("#id_reasonother").addClass("other"+" "+nofinv);
    $('.addhiddendata:first').find('#id_invoicenumber').attr('id', 'id_invoicenumber'+nofinv);
    $('.addhiddendata:first').find('#id_invoicestatus').attr('id', 'id_invoicestatus'+nofinv);
    $('.addhiddendata:first').find('#id_paidon').attr('id', 'id_paidon'+nofinv);
    $('.addhiddendata:first').find('#id_rejectreason').attr('id', 'id_rejectreason'+nofinv);
    $(".addhiddendata:first").find("#id_amount").attr("id", "id_amount"+nofinv);
    $(".addhiddendata:first").find("#id_currency").attr("id", "id_currency"+nofinv);
    $("#id_reasonother").attr("id", "id_reasonother"+nofinv);

    $('#trbutton').on('click', function(){
	$('#trbutton').fadeOut('slow', function(){
	    $('#trform').fadeIn('slow');
	    $('#ptrack').html('Please fill in all the fields.');
	});
    });

    $('#id_reminderdate').datepicker({
	dateFormat: 'yy-mm-dd',
	constrainInput: false
    });
    $('.paid:first').datepicker({
	dateFormat: 'yy-mm-dd',
	constrainInput: false
    });

    var $name = $('#vclerk').attr('value');
    $('#id_clerk').val($name);

    $('#id_clerk').attr('readonly', true);
    $('#id_actiondate').attr('readonly', true);

    $('#id_market').on('change', function(){
	//show the ccode choice if is hidden
	if ($('#id_ccode').is(':hidden')) {$('#id_ccode').show()};

	$('#id_ccode option').each(function(){
	    $(this).show();
	});

	var market = $('#id_market').val();
	if (market == 'IT') {
	    var marketArray = ['', '11', '13', '15', '16'];
	} else if (market == 'DE') {
	    var marketArray = ['', '13', '52', '55', '60', '64', '66'];
	} else if (market == 'PT' || market == 'PL' || market == 'NL' || market == 'NO') {
	    var marketArray = ['', '10'];
	} else if (market == 'BE') {
	    var marketArray = ['', '12', '14', '18', '31'];
	} else if (market == 'SE') {
	    var marketArray = ['', '16'];
	} else if (market == 'FI') {
	    var marketArray = ['', '11'];
	} else if (market == 'DK') {
	    var marketArray = ['', '12'];
	} else {
	    var marketArray = [''];
	}

	$('#id_ccode option').each(function(){
	    var ccodeOpt = $(this).val();
	    if ($.inArray(ccodeOpt, marketArray) > -1){
		;
	    } else {
		$(this).hide();
	    }
	});

    });

    $(document).on('change', '.status', function() {
	var status = $(this).val();
	var nextform = $(this).parent().parent().parent().next();

	if (nextform.is(':hidden')){
	    ;
	} else {
	    nextform.hide();
	    if (nextform.find('.paid').is(':hidden')) {nextform.find('.paid').show()};
	    if (nextform.find('.other').is(':hidden')) {nextform.find('.other').show()};
	    if (nextform.find('.reject').is(':hidden')) {nextform.find('.reject').show()};
	    nextform.find('label').show();
	}

	if (status == 'RJ'){
	    nextform.find('.paid').hide();
	    nextform.find('label:last').hide();
	    nextform.fadeIn('slow');
	} else if (status == 'PD') {
	    nextform.find('.reject').hide();
	    nextform.find(".other").hide();
	    nextform.find('label:first').hide();
	    nextform.find('label:first').next().next("label").hide();
	    nextform.fadeIn('slow');
	};
    });

    $('#addbutt').on('click', function() {
	var formToApp = $('.addhiddendata:first').clone();
	formToApp.find('button').remove();
	formToApp.find('.paid').removeClass('hasDatepicker');
	formToApp.find('.paid').val('');
	formToApp.find('#id_invoicenumber1').removeClass('invoice'+' '+nofinv);
	formToApp.find('#id_invoicestatus1').removeClass('invoiceadditional'+' '+nofinv);
	formToApp.find('#id_paidon1').removeClass('paid'+' '+nofinv);
	formToApp.find('#id_rejectreason1').removeClass('reject'+' '+nofinv);
	formToApp.find("#id_amount1").removeClass("amount"+" "+nofinv);
	formToApp.find("#id_currency1").removeClass("currency"+" "+nofinv);
	nofinv = nofinv + 1;
	formToApp.find('#id_rejectreason1').addClass('reject'+' '+nofinv);
	formToApp.find('#id_rejectreason1').attr('name', 'reject'+nofinv);
	formToApp.find('#id_rejectreason1').attr('id', 'id_rejectreason'+nofinv);
	formToApp.find('#id_paidon1').addClass('paid'+' '+nofinv);
	formToApp.find('#id_paidon1').attr('name', 'paid'+nofinv);
	formToApp.find('#id_paidon1').attr('id', 'id_paidon'+nofinv);
	formToApp.find('#id_invoicenumber1').addClass('invoice'+' '+nofinv);
	formToApp.find('#id_invoicenumber1').attr('name', 'invoicenumber'+nofinv);
	formToApp.find('#id_invoicenumber1').attr('id', 'id_invoicenumber'+nofinv);
	formToApp.find('#id_invoicestatus1').addClass('invoiceadditional'+' '+nofinv);
	formToApp.find('#id_invoicestatus1').attr('name', 'invoicestatus'+nofinv);
	formToApp.find('#id_invoicestatus1').attr('id', 'id_invoicestatus'+nofinv);
	formToApp.find("#id_amount1").addClass("amount"+" "+nofinv);
	formToApp.find("#id_amount1").attr("name", "amount"+nofinv);
	formToApp.find("#id_amount1").attr("id", "id_amount"+nofinv);
	formToApp.find("#id_currency1").addClass("currency"+" "+nofinv);
	formToApp.find("#id_currency1").attr("name", "currency"+nofinv);
	formToApp.find("#id_currency1").attr("id", "id_currency"+nofinv);
	$('#vendorform').before(formToApp);
	formToApp.find('.paid').datepicker({
	    dateFormat: 'yy-mm-dd',
	    constrainInput: false
	});
    });

    $('#rembutt').on('click', function() {
	//Remove additional invoices if there are at least 2 of them.
	if ($('.invoice').length == 1) {
	    ;
	} else {
	    $('.addhiddendata:last').remove();
	};
    });

    $('#id_reminderdate').on('change', function() {
	var rdate = $(this).val().split('-');
	var market = $('#id_market').val();
	$('#id_remindernumber').val('');
	$('#id_remindernumber').val(market+rdate[0]+rdate[1]+rdate[2]+'/');
    });

    function DunningTrack() {
	// get the total number of invoices.
	var invo = $('.invoice').length;

	var data = new Array()

	//loop through the invoice to create our data to post
	for (x = 1; x <= invo; x++) {
	    var formn = 'form'+x;
	    var obj = {
		market: $('#id_market').val(),
		ccode: $('#id_ccode').val(),
		clerk: $('#id_clerk').val(),
		actiondate: $('#id_actiondate').val(),
		reminderdate: $('#id_actiondate').val(),
		level: $('#id_level').val(),
		amount: $("#id_amount"+x).val(),
		currency: $("#id_currency"+x).val(),
		remindernumber: $('#id_remindernumber').val(),
		vendor: $('#id_vendor').val(),
		mailvendor: $('#id_mailvendor').val(),
		invoicenumber: $('#id_invoicenumber'+x).val(),
		invoicestatus: $('#id_invoicestatus'+x).val(),
		//actiontaken: $('#id_actiontaken').val(),
		rejectreason: $('#id_rejectreason'+x).val(),
		paidon: $('#id_paidon'+x).val()
	    };
	    data.push(obj);
	}

	//setup the AJAX request
	$.ajaxSetup({
	    type: 'POST',
	    dataType: 'json'
	});

	//the real AJAX request
	$.ajax({
	    url: '/ajax/',
	    data: {
		form_type: 'multi',
		mass_data: JSON.stringify(data)
	    },
	    success: window.location.replace("/main/"),
	    error: function (ajaxObj, textStatus, error) {
		alert(error);
	    }
	});
	return true;
    };

    $('#trackbutton').on('click', ValidateForm);

    function ValidateForm() {
	DunningTrack();
    };
});

function SuccessfulTracking() {
    $('#trform *').filter(':input').each(function() {
	$(this).val('');
    });
};
<|endoftext|>


<commit_before>(function() {
    var arrayOf = function(pseudoArray) {
            return Array.prototype.slice.call(pseudoArray);
        },

        getLowerCaseExtension = function(filename) {
            var extIdx = filename.lastIndexOf(".") + 1;

            if (extIdx > 0) {
                return filename.substr(extIdx, filename.length - extIdx).toLowerCase();
            }
        },

        getResultOfCountLimitValidation = function(limit, files) {
            if (limit > 0 && limit < files.length) {
                return {
                    invalid: files.slice(limit, files.length),
                    valid: files.slice(0, limit)
                };
            }

            return {invalid: [], valid: files};
        },

        getResultOfExtensionsValidation = function(extensionsStr, files) {
            if (extensionsStr) {
                var negate = extensionsStr.charAt(0) === "!",
                    extensions = JSON.parse(extensionsStr.toLowerCase().substr(negate ? 1 : 0)),
                    result = {invalid: [], valid: []};

                files.forEach(function(file) {
                    var extension = getLowerCaseExtension(file.name);

                    if (extensions.indexOf(extension) >= 0) {
                        result[negate ? "invalid" : "valid"].push(file);
                    }
                    else {
                        result[negate? "valid" : "invalid"].push(file);
                    }
                });

                return result;
            }

            return {invalid: [], valid: files};
        },

        getResultOfSizeValidation = function(minSize, maxSize, files) {
            if (!minSize && !maxSize) {
                return {tooBig: [], tooSmall: [], valid: files};
            }

            var valid = [],
                tooBig = [],
                tooSmall = [];

            files.forEach(function(file) {
                if (minSize && file.size < minSize) {
                    tooSmall.push(file);
                }
                else if (maxSize && file.size > maxSize) {
                    tooBig.push(file);
                }
                else {
                    valid.push(file);
                }
            });

            return {tooBig: tooBig, tooSmall: tooSmall, valid: valid};
        },

        isIos = function() {
            return navigator.userAgent.indexOf("iPad") !== -1 ||
                navigator.userAgent.indexOf("iPod") !== -1 ||
                navigator.userAgent.indexOf("iPhone") !== -1;
        },

        // This is the only way (I am aware of) to reset an `<input type="file">`
        // without removing it from the DOM.  Removing it disconnects it
        // from the CE/Polymer.
        resetInput = function(customEl) {
            // create a form with a hidden reset button
            var tempForm = document.createElement("form"),
                tempResetButton = document.createElement("button");

            tempResetButton.setAttribute("type", "reset");
            tempResetButton.style.display = "none";
            tempForm.appendChild(tempResetButton);

            // temporarily move the `<input type="file">` into the form & add form to DOM
            customEl.$.fileInput.parentNode.insertBefore(tempForm, customEl.$.fileInput);
            tempForm.appendChild(customEl.$.fileInput);

            // reset the `<input type="file">`
            tempResetButton.click();

            // move the `<input type="file">` back to its original spot & remove form
            tempForm.parentNode.appendChild(customEl.$.fileInput);
            tempForm.parentNode.removeChild(tempForm);

            updateValidity(customEl);
        },

        setupValidationTarget = function(customEl) {
            validationTarget = document.createElement("input");
            validationTarget.setAttribute("type", "text");

            validationTarget.style.width = 0;
            validationTarget.style.height = 0;
            validationTarget.style.opacity = 0;

            validationTarget.customElementRef = customEl;

            customEl.parentNode.insertBefore(validationTarget, customEl);

            updateValidity(customEl);
        },

        updateValidity = function(customEl) {
            if (validationTarget) {
                if (customEl.files.length) {
                    validationTarget.setCustomValidity("");
                }
                else {
                    validationTarget.setCustomValidity(customEl.invalidText);
                }
            }
        },

        validationTarget;

   this.fileInput = {
        changeHandler: function() {
            var customEl = this,
                files = arrayOf(customEl.$.fileInput.files),
                invalid = {count: 0},
                valid = [];

            // Some browsers may fire a change event when the file chooser
            // dialog is closed via cancel button.  In this case, the
            //files array will be empty and the event should be ignored.
            if (files.length) {
                var sizeValidationResult = getResultOfSizeValidation(customEl.minSize, customEl.maxSize, files);
                var extensionValidationResult = getResultOfExtensionsValidation(customEl.extensions, sizeValidationResult.valid);
                var countLimitValidationResult = getResultOfCountLimitValidation(customEl.maxFiles, extensionValidationResult.valid);

                if (sizeValidationResult.tooBig.length) {
                    invalid.tooBig = sizeValidationResult.tooBig;
                    invalid.count += sizeValidationResult.tooBig.length;
                }
                if (sizeValidationResult.tooSmall.length) {
                    invalid.tooSmall = sizeValidationResult.tooSmall;
                    invalid.count += sizeValidationResult.tooSmall.length;
                }
                if (extensionValidationResult.invalid.length) {
                    invalid.badExtension = extensionValidationResult.invalid;
                    invalid.count += extensionValidationResult.invalid.length;
                }
                if (countLimitValidationResult.invalid.length) {
                    invalid.tooMany = countLimitValidationResult.invalid;
                    invalid.count += countLimitValidationResult.invalid.length;
                }

                valid = countLimitValidationResult.valid;

                customEl.invalid = invalid;
                customEl.files = valid;

                updateValidity(customEl);
                customEl.fire("change", {invalid: invalid, valid: valid});
            }
        },

        created: function() {
            var customEl = this;

            customEl.files = [];
            customEl.invalid = {count: 0};
        },

        invalidText: "No valid files selected.",

        maxFiles: 0,

        maxSize: 0,

        minSize: 0,

        domReady: function() {
            var customEl = this;

            if (customEl.camera != null && isIos()) {
                customEl.maxFiles = 1;

                var iosCameraAccept = "image/*;capture=camera";
                if (customEl.accept && customEl.accept.length.trim().length > 0) {
                    customEl.accept += "," + iosCameraAccept;
                }
                else {
                    customEl.accept = iosCameraAccept;
                }
            }

            if (customEl.maxFiles !== 1) {
                customEl.$.fileInput.setAttribute("multiple", "");
            }

            if (customEl.directory != null && customEl.$.fileInput.webkitdirectory !== undefined) {
                customEl.$.fileInput.setAttribute("webkitdirectory", "");
            }

            if (customEl.required != null) {
                setupValidationTarget(customEl);
            }
        },

        reset: function() {
            var customEl = this;

            customEl.created();
            resetInput(customEl);
        }
    };
}());<commit_msg>fix(validation): delegate input may be visible, focusable fixes #22<commit_after>(function() {
    var arrayOf = function(pseudoArray) {
            return Array.prototype.slice.call(pseudoArray);
        },

        getLowerCaseExtension = function(filename) {
            var extIdx = filename.lastIndexOf(".") + 1;

            if (extIdx > 0) {
                return filename.substr(extIdx, filename.length - extIdx).toLowerCase();
            }
        },

        getResultOfCountLimitValidation = function(limit, files) {
            if (limit > 0 && limit < files.length) {
                return {
                    invalid: files.slice(limit, files.length),
                    valid: files.slice(0, limit)
                };
            }

            return {invalid: [], valid: files};
        },

        getResultOfExtensionsValidation = function(extensionsStr, files) {
            if (extensionsStr) {
                var negate = extensionsStr.charAt(0) === "!",
                    extensions = JSON.parse(extensionsStr.toLowerCase().substr(negate ? 1 : 0)),
                    result = {invalid: [], valid: []};

                files.forEach(function(file) {
                    var extension = getLowerCaseExtension(file.name);

                    if (extensions.indexOf(extension) >= 0) {
                        result[negate ? "invalid" : "valid"].push(file);
                    }
                    else {
                        result[negate? "valid" : "invalid"].push(file);
                    }
                });

                return result;
            }

            return {invalid: [], valid: files};
        },

        getResultOfSizeValidation = function(minSize, maxSize, files) {
            if (!minSize && !maxSize) {
                return {tooBig: [], tooSmall: [], valid: files};
            }

            var valid = [],
                tooBig = [],
                tooSmall = [];

            files.forEach(function(file) {
                if (minSize && file.size < minSize) {
                    tooSmall.push(file);
                }
                else if (maxSize && file.size > maxSize) {
                    tooBig.push(file);
                }
                else {
                    valid.push(file);
                }
            });

            return {tooBig: tooBig, tooSmall: tooSmall, valid: valid};
        },

        isIos = function() {
            return navigator.userAgent.indexOf("iPad") !== -1 ||
                navigator.userAgent.indexOf("iPod") !== -1 ||
                navigator.userAgent.indexOf("iPhone") !== -1;
        },

        // This is the only way (I am aware of) to reset an `<input type="file">`
        // without removing it from the DOM.  Removing it disconnects it
        // from the CE/Polymer.
        resetInput = function(customEl) {
            // create a form with a hidden reset button
            var tempForm = document.createElement("form"),
                tempResetButton = document.createElement("button");

            tempResetButton.setAttribute("type", "reset");
            tempResetButton.style.display = "none";
            tempForm.appendChild(tempResetButton);

            // temporarily move the `<input type="file">` into the form & add form to DOM
            customEl.$.fileInput.parentNode.insertBefore(tempForm, customEl.$.fileInput);
            tempForm.appendChild(customEl.$.fileInput);

            // reset the `<input type="file">`
            tempResetButton.click();

            // move the `<input type="file">` back to its original spot & remove form
            tempForm.parentNode.appendChild(customEl.$.fileInput);
            tempForm.parentNode.removeChild(tempForm);

            updateValidity(customEl);
        },

        setupValidationTarget = function(customEl) {
            validationTarget = document.createElement("input");
            validationTarget.setAttribute("tabindex", "-1");
            validationTarget.setAttribute("type", "text");

            // Strange margin/padding needed to ensure some browsers
            // don't hide the validation message immediately after it
            // appears (Chrome at this time)
            validationTarget.style.padding = "1px";
            validationTarget.style.margin = "-1px";

            validationTarget.style.border = 0;
            validationTarget.style.height = 0;
            validationTarget.style.opacity = 0;
            validationTarget.style.width = 0;

            validationTarget.className = "fileInputDelegate";

            validationTarget.customElementRef = customEl;

            customEl.parentNode.insertBefore(validationTarget, customEl);

            updateValidity(customEl);
        },

        updateValidity = function(customEl) {
            if (validationTarget) {
                if (customEl.files.length) {
                    validationTarget.setCustomValidity("");
                }
                else {
                    validationTarget.setCustomValidity(customEl.invalidText);
                }
            }
        },

        validationTarget;

   this.fileInput = {
        changeHandler: function() {
            var customEl = this,
                files = arrayOf(customEl.$.fileInput.files),
                invalid = {count: 0},
                valid = [];

            // Some browsers may fire a change event when the file chooser
            // dialog is closed via cancel button.  In this case, the
            //files array will be empty and the event should be ignored.
            if (files.length) {
                var sizeValidationResult = getResultOfSizeValidation(customEl.minSize, customEl.maxSize, files);
                var extensionValidationResult = getResultOfExtensionsValidation(customEl.extensions, sizeValidationResult.valid);
                var countLimitValidationResult = getResultOfCountLimitValidation(customEl.maxFiles, extensionValidationResult.valid);

                if (sizeValidationResult.tooBig.length) {
                    invalid.tooBig = sizeValidationResult.tooBig;
                    invalid.count += sizeValidationResult.tooBig.length;
                }
                if (sizeValidationResult.tooSmall.length) {
                    invalid.tooSmall = sizeValidationResult.tooSmall;
                    invalid.count += sizeValidationResult.tooSmall.length;
                }
                if (extensionValidationResult.invalid.length) {
                    invalid.badExtension = extensionValidationResult.invalid;
                    invalid.count += extensionValidationResult.invalid.length;
                }
                if (countLimitValidationResult.invalid.length) {
                    invalid.tooMany = countLimitValidationResult.invalid;
                    invalid.count += countLimitValidationResult.invalid.length;
                }

                valid = countLimitValidationResult.valid;

                customEl.invalid = invalid;
                customEl.files = valid;

                updateValidity(customEl);
                customEl.fire("change", {invalid: invalid, valid: valid});
            }
        },

        created: function() {
            var customEl = this;

            customEl.files = [];
            customEl.invalid = {count: 0};
        },

        invalidText: "No valid files selected.",

        maxFiles: 0,

        maxSize: 0,

        minSize: 0,

        domReady: function() {
            var customEl = this;

            if (customEl.camera != null && isIos()) {
                customEl.maxFiles = 1;

                var iosCameraAccept = "image/*;capture=camera";
                if (customEl.accept && customEl.accept.length.trim().length > 0) {
                    customEl.accept += "," + iosCameraAccept;
                }
                else {
                    customEl.accept = iosCameraAccept;
                }
            }

            if (customEl.maxFiles !== 1) {
                customEl.$.fileInput.setAttribute("multiple", "");
            }

            if (customEl.directory != null && customEl.$.fileInput.webkitdirectory !== undefined) {
                customEl.$.fileInput.setAttribute("webkitdirectory", "");
            }

            if (customEl.required != null) {
                setupValidationTarget(customEl);
            }
        },

        reset: function() {
            var customEl = this;

            customEl.created();
            resetInput(customEl);
        }
    };
}());<|endoftext|>


<commit_before>/*global module:false */

module.exports = function(grunt) {

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		meta: {

			banner_long: '/*!\n' +
			             ' * <%= pkg.title || pkg.name %>\n' +
			             '<%= pkg.description ? " * " + pkg.description + "\\n" : "" %>' +
			             ' *\n' +
			             '<%= pkg.author.name ? " * @author " + pkg.author.name + "\\n" : "" %>' +
			             '<%= pkg.author.url ? " * @link " + pkg.author.url + "\\n" : "" %>' +
			             '<%= pkg.homepage ? " * @docs " + pkg.homepage + "\\n" : "" %>' +
			             ' * @copyright Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>.\n' +
			             '<%= pkg.licenses ? " * @license Released under the " + _.pluck(pkg.licenses, "type").join(", ") + ".\\n" : "" %>' +
			             '<%= pkg.version ? " * @version " + pkg.version + "\\n" : "" %>' +
			             ' * @date <%= grunt.template.today("yyyy/mm/dd") %>\n' +
			             ' */\r\r',

			banner_short: '/*! ' +
			              '<%= pkg.title || pkg.name %>' +
			              '<%= pkg.version ? " v" + pkg.version : "" %>' +
			              '<%= pkg.licenses ? " | " + _.pluck(pkg.licenses, "type").join(", ") : "" %>' +
			              '<%= pkg.homepage ? " | " + pkg.homepage : "" %>' +
			              ' */'

		},

		//----------------------------------

		/**
		 * @see http://www.jshint.com/docs/
		 */

		jshint: {

			options: {

				smarttabs: true,
				browser: true,
				quotmark: true,
				curly: true

			},

			init: [

				'./Gruntfile.js',
				'./src/jquery.<%= pkg.name %>.js'

			]

		},

		//----------------------------------

		/**
		 * @see https://github.com/gruntjs/grunt-contrib-uglify
		 */

		uglify: {

			my_target: {

				options: {

					banner: '<%= meta.banner_short %>'

				},

				files: {

					'../<%= pkg.name %>/jquery.<%= pkg.name %>.min.js': ['./src/jquery.<%= pkg.name %>.js']

				}

			}

		},

		concat: {

			options: {

				banner: '<%= meta.banner_long %>'

			},

			dist: {

				src: ['./src/jquery.<%= pkg.name %>.js'],
				dest: '../<%= pkg.name %>/jquery.<%= pkg.name %>.js'

			}
		}

	});

	//--------------------------------------------------------------------

	grunt.loadNpmTasks('grunt-contrib-jshint');

	grunt.loadNpmTasks('grunt-contrib-uglify');

	grunt.loadNpmTasks('grunt-contrib-concat');

	//----------------------------------

	grunt.registerTask('default', ['jshint', 'uglify', 'concat']);

};
<commit_msg>Small adjustment.<commit_after>/*global module:false */

module.exports = function(grunt) {

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		meta: {

			banner_long: '/*!\n' +
			             ' * <%= pkg.title || pkg.name %>\n' +
			             '<%= pkg.description ? " * " + pkg.description + "\\n" : "" %>' +
			             ' *\n' +
			             '<%= pkg.author.name ? " * @author " + pkg.author.name + "\\n" : "" %>' +
			             '<%= pkg.author.url ? " * @link " + pkg.author.url + "\\n" : "" %>' +
			             '<%= pkg.homepage ? " * @docs " + pkg.homepage + "\\n" : "" %>' +
			             ' * @copyright Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>.\n' +
			             '<%= pkg.licenses ? " * @license Released under the " + _.pluck(pkg.licenses, "type").join(", ") + ".\\n" : "" %>' +
			             '<%= pkg.version ? " * @version " + pkg.version + "\\n" : "" %>' +
			             ' * @date <%= grunt.template.today("yyyy/mm/dd") %>\n' +
			             ' */\r\r',

			banner_short: '/*! ' +
			              '<%= pkg.title || pkg.name %>' +
			              '<%= pkg.version ? " v" + pkg.version : "" %>' +
			              '<%= pkg.licenses ? " | " + _.pluck(pkg.licenses, "type").join(", ") : "" %>' +
			              '<%= pkg.homepage ? " | " + pkg.homepage : "" %>' +
			              ' */'

		},

		//----------------------------------

		/**
		 * @see http://www.jshint.com/docs/
		 */

		jshint: {

			options: {

				smarttabs: true,
				browser: true,
				quotmark: true,
				curly: true

			},

			init: [

				'./Gruntfile.js',
				'./src/jquery.<%= pkg.name %>.js'

			]

		},

		//----------------------------------

		/**
		 * @see https://github.com/gruntjs/grunt-contrib-uglify
		 */

		uglify: {

			my_target: {

				options: {

					banner: '<%= meta.banner_short %>'

				},

				files: {

					'../<%= pkg.name %>/jquery.<%= pkg.name %>.min.js': ['./src/jquery.<%= pkg.name %>.js']

				}

			}

		},

		//----------------------------------

		/**
		 * @see https://github.com/gruntjs/grunt-contrib-concat
		 */

		concat: {

			options: {

				banner: '<%= meta.banner_long %>'

			},

			dist: {

				src: ['./src/jquery.<%= pkg.name %>.js'],
				dest: '../<%= pkg.name %>/jquery.<%= pkg.name %>.js'

			}

		},

	});

	//--------------------------------------------------------------------

	grunt.loadNpmTasks('grunt-contrib-jshint');

	grunt.loadNpmTasks('grunt-contrib-uglify');

	grunt.loadNpmTasks('grunt-contrib-concat');

	//----------------------------------

	grunt.registerTask('default', ['jshint', 'uglify', 'concat']);

};
<|endoftext|>


<commit_before>// Global object to hold the gesture information for touch events
var gameGesture;

// Detect when the document has loaded
$(document).ready(function(){
    // initialize
    init();
});

// Inialize all the events for the game
function init() {
    // Handle the Window Resize event, redraw the grid to fill the screen
    window.onresize = function (e) {
        console.log('height:' + $(document).height() + ' width:' + $(document).width());
        //TODO: Redraw the grid
    }

	// Setup event listener for Keydown event
	window.addEventListener('keydown', handleKeypress, true);
	console.log('Application init');

	// Detect pointer events for IE and Windows
	if(window.navigator.msPointerEnabled){
		gameGesture = new MSGesture();
		gameGesture.target = document.body;
		document.body.addEventListener("MSGestureChange", handleIEGestures, false);
		document.body.addEventListener("pointerdown", function(e){
			gameGesture.addPointer(e.pointerId);
		}, true);
	} else {
	    var element = document.getElementById('board');
	    gameGesture = Hammer(element).on("swipeleft swiperight swipeup swipedown dragup dragdown dragleft dragright", function (event) {
	        handleWebkitGestures(event);
	    });
	}

	// Setup the game grid
	gameGrid = Object.create(grid);
	gameGrid.createGrid(8,8);
	gameGrid.drawGrid(document.getElementById('board'));
	//gameGrid.updateCell('red',5,5);
	gameGrid.addSquare(2,1);

	// Setup event listeners for CSS Animations
	var flipper = document.getElementById('flipper');

    //IE event listeners
	flipper.addEventListener('MSAnimationEnd', flipperAnimationEnded, false);
	flipper.addEventListener('MSAnimationStart', flipperAnimationStarted, false);

    // Webkit event listeners
	flipper.addEventListener('webkitAnimationEnd', flipperAnimationEnded, false);
	flipper.addEventListener('webkitAnimationStart', flipperAnimationStarted, false);

    // Firefox event listeners
	flipper.addEventListener('animationend', flipperAnimationEnded, false);
	flipper.addEventListener('animationstart', flipperAnimationStarted, false);

    // Generate the colorqueue
	generateColorQueue();

    // Draw the colorqueue
	drawColorQueue();

}

function flipperAnimationEnded(e) {
	if(!game.isOver){
		gameGrid.moveSquare(game.direction);
	}
}

function flipperAnimationStarted(e) {
    game.animating = true;
    game.nextColor = getNextColor();
    document.getElementById('flipper').style.backgroundColor = game.nextColor;
}<commit_msg>small update for onresize<commit_after>// Global object to hold the gesture information for touch events
var gameGesture;

// Detect when the document has loaded
$(document).ready(function(){
    // initialize
    init();
});

// Inialize all the events for the game
function init() {
    // Handle the Window Resize event, redraw the grid to fill the screen
    window.onresize = function (e) {
        console.log('height:' + $(document).height() + ' width:' + $(document).width());
        //TODO: Redraw the grid

    }

	// Setup event listener for Keydown event
	window.addEventListener('keydown', handleKeypress, true);
	console.log('Application init');

	// Detect pointer events for IE and Windows
	if(window.navigator.msPointerEnabled){
		gameGesture = new MSGesture();
		gameGesture.target = document.body;
		document.body.addEventListener("MSGestureChange", handleIEGestures, false);
		document.body.addEventListener("pointerdown", function(e){
			gameGesture.addPointer(e.pointerId);
		}, true);
	} else {
	    var element = document.getElementById('board');
	    gameGesture = Hammer(element).on("swipeleft swiperight swipeup swipedown dragup dragdown dragleft dragright", function (event) {
	        handleWebkitGestures(event);
	    });
	}

	// Setup the game grid
	gameGrid = Object.create(grid);
	gameGrid.createGrid(8,8);
	gameGrid.drawGrid(document.getElementById('board'));
	//gameGrid.updateCell('red',5,5);
	gameGrid.addSquare(2,1);

	// Setup event listeners for CSS Animations
	var flipper = document.getElementById('flipper');

    //IE event listeners
	flipper.addEventListener('MSAnimationEnd', flipperAnimationEnded, false);
	flipper.addEventListener('MSAnimationStart', flipperAnimationStarted, false);

    // Webkit event listeners
	flipper.addEventListener('webkitAnimationEnd', flipperAnimationEnded, false);
	flipper.addEventListener('webkitAnimationStart', flipperAnimationStarted, false);

    // Firefox event listeners
	flipper.addEventListener('animationend', flipperAnimationEnded, false);
	flipper.addEventListener('animationstart', flipperAnimationStarted, false);

    // Generate the colorqueue
	generateColorQueue();

    // Draw the colorqueue
	drawColorQueue();

}

function flipperAnimationEnded(e) {
	if(!game.isOver){
		gameGrid.moveSquare(game.direction);
	}
}

function flipperAnimationStarted(e) {
    game.animating = true;
    game.nextColor = getNextColor();
    document.getElementById('flipper').style.backgroundColor = game.nextColor;
}<|endoftext|>


<commit_before>
var _gaq = _gaq || [];  // asynchronous stack used by google analytics

openerp.web_analytics = function(instance) {

    /*
    *  The Web Analytics Module inserts the Google Analytics JS Snippet
    *  at the top of the page, and sends to google an url each time the
    *  openerp url is changed.
    *  The pushes of the urls is made by triggering the 'state_pushed' event in the
    *  web_client.do_push_state() method which is responsible of changing the openerp current url
    */

    // Google Analytics Code snippet
    (function() {
        var ga   = document.createElement('script');
        ga.type  = 'text/javascript';
        ga.async = true;
        ga.src   = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ga,s);
    })();

    instance.web_analytics.Tracker = instance.web.Class.extend({
        /*
        *  This method initializes the tracker
        */
        init: function() {
            /* Comment this lines when going on production, only used for testing on localhost */
            _gaq.push(['_setAccount', 'UA-35793871-1']);
            _gaq.push(['_setDomainName', 'none']);
            /**/

            /* Uncomment this lines when going on production
            _gaq.push(['_setAccount', 'UA-7333765-1']);
            _gaq.push(['_setDomainName', '.openerp.com']);  // Allow multi-domain
            */
        },
        /*
        * This method MUST be overriden by saas_demo and saas_trial in order to
        * set the correct user type. By default, the user connected is local to the DB.
        */
        _get_user_type: function() {
            return 'Local User';
        },
        /*
        * This method gets the user access level, to be used as CV in GA
        */
        _get_user_access_level: function() {
            if (instance.session.uid === 1) {
                return 'Admin User';
            // Make the difference between portal users and anonymous users
            } else if (instance.session.username.indexOf('@') !== -1) {
                if (instance.session.username.indexOf('anonymous') === -1) {
                    return 'Portal User';
                } else {
                    return 'Anonymous User';
                }
            } else if (instance.session.username.indexOf('anonymous') !== -1) {
                return 'Anonymous User';
            } else {
                return 'Normal User';
            }
        },
        /*
        * This method contains the initialization of all user-related custom variables
        * stored in GA. Also other modules can override it to add new custom variables
        */
        initialize_custom: function() {
            // Track User Access Level, Custom Variable 4 in GA with visitor level scope
            // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
            _gaq.push(['_setCustomVar', 4, 'User Access Level', this.user_access_level, 1]);

            // Track User Type Conversion, Custom Variable 3 in GA with session level scope
            // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
            _gaq.push(['_setCustomVar', 1, 'User Type Conversion', this._get_user_type(), 2]);

            return instance.session.rpc("/web/webclient/version_info", {})
                .done(function(res) {
                    _gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
                    return;
                });
        },
        /*
        *  This method contains the initialization of the object and view type
        *  as an event in GA.
        */
        on_state_pushed: function(state) {
            // Track only pages corresponding to a 'normal' view of OpenERP, views
            // related to client actions are tracked by the action manager
            if (state.model && state.view_type) {
                // Track the page
                var url = instance.web_analytics.generateUrl({'model': state.model, 'view_type': state.view_type});
                this._push_event({
                    'category': state.model,
                    'action': state.view_type,
                    'label': url,
                });
            }
        },
        /*
        * This method includes the tracker into views and managers. It can be overriden
        * by other modules in order to extend tracking functionalities
        */
        include_tracker: function() {
            var t = this;
            // Track the events related with the creation and the  modification of records,
            // the view type is always form
            instance.web.FormView.include({
                init: function(parent, dataset, view_id, options) {
                    this._super.apply(this, arguments);
                    var self = this;
                    this.on('record_created', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                    this.on('record_saved', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                }
            });

            // Track client actions
            instance.web.ActionManager.include({
                ir_actions_client: function (action, options) {
                    var url = instance.web_analytics.generateUrl({'action': action.tag});
                    var category = action.res_model || action.type;
                    t._push_event({
                        'category': action.res_model || action.type,
                        'action': action.name || action.tag,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track button events
            instance.web.View.include({
                do_execute_action: function(action_data, dataset, record_id, on_closed) {
                    var category = this.model || dataset.model || '';
                    var action;
                    if (action_data.name && _.isNaN(action_data.name-0)) {
                        action = action_data.name;
                    } else {
                        action = action_data.string || action_data.special || '';
                    }
                    var url = instance.web_analytics.generateUrl({'model': category, 'view_type': this.view_type});
                    t._push_event({
                        'category': category,
                        'action': action,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track error events
            instance.web.CrashManager.include({
                show_error: function(error) {
                    var hash = window.location.hash;
                    var params = $.deparam(hash.substr(hash.indexOf('#')+1));
                    var options = {};
                    if (params.model && params.view_type) {
                        options = {'model': params.model, 'view_type': params.view_type};
                    } else {
                        options = {'action': params.action};
                    }
                    var url = instance.web_analytics.generateUrl(options);
                    if (error.code) {
                        t._push_event({
                            'category': error.message,
                            'action': error.data.fault_code,
                            'label': url,
                            'noninteraction': true,
                        });
                    } else {
                        t._push_event({
                            'category': error.type,
                            'action': error.data.debug,
                            'label': url,
                            'noninteraction': true,
                        });
                    }
                    this._super.apply(this, arguments);
                },
            });
        },
        /*
        * Method called in order to send _trackEvent to GA
        */
        _push_event: function(options) {
            _gaq.push(['_trackEvent',
                options.category,
                options.action,
                options.label,
                options.value,
                options.noninteraction
            ]);
        },
        /*
        * Method called in order to send ecommerce transactions to GA
        */
        _push_ecommerce: function(trans_data, item_list) {
            _gaq.push(['_addTrans',
                trans_data.order_id,
                trans_data.store_name,
                trans_data.total,
                trans_data.tax,
                trans_data.shipping,
                trans_data.city,
                trans_data.state
                trans_data.country,
            ]);
            _.each(item_list, function(item) {
                _gaq.push(['_addItem',
                    item.order_id,
                    item.sku,
                    item.name,
                    item.category,
                    item.price,
                    item.quantity,
                ]);
            });
            _gaq.push(['_trackTrans']);
        },
    });

    // ----------------------------------------------------------------
    // utility functions
    // ----------------------------------------------------------------

    instance.web_analytics.generateUrl = function(options) {
        var url = '';
        _.each(options, function(value, key) {
            url += '/' + key + '=' + value;
        });
        return url;
    };

    instance.web_analytics.setupTracker = function(wc) {
        var t = wc.tracker;
        return $.when(t._get_user_access_level()).then(function(r) {
            t.user_access_level = r;
            t.initialize_custom().then(function() {
                wc.on('state_pushed', wc, t.on_state_pushed);
                t.include_tracker();
            });
        });
    };

    // Set correctly the tracker in the current instance
    if (instance.client instanceof instance.web.WebClient) {        // not for embedded clients
        instance.webclient.tracker = new instance.web_analytics.Tracker();
        instance.web_analytics.setupTracker(instance.webclient);
    } else if (!instance.client) {
        // client does not already exists, we are in monodb mode
        instance.web.WebClient.include({
            start: function() {
                var d = this._super.apply(this, arguments);
                this.tracker = new instance.web_analytics.Tracker();
                return d;
            },
            show_application: function() {
                var self = this;
                instance.web_analytics.setupTracker(self).then(function() {
                    self._super();
                });
            },
        });
    }

};
<commit_msg>[FIX] Going into production<commit_after>
var _gaq = _gaq || [];  // asynchronous stack used by google analytics

openerp.web_analytics = function(instance) {

    /*
    *  The Web Analytics Module inserts the Google Analytics JS Snippet
    *  at the top of the page, and sends to google an url each time the
    *  openerp url is changed.
    *  The pushes of the urls is made by triggering the 'state_pushed' event in the
    *  web_client.do_push_state() method which is responsible of changing the openerp current url
    */

    // Google Analytics Code snippet
    (function() {
        var ga   = document.createElement('script');
        ga.type  = 'text/javascript';
        ga.async = true;
        ga.src   = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(ga,s);
    })();

    instance.web_analytics.Tracker = instance.web.Class.extend({
        /*
        *  This method initializes the tracker
        */
        init: function() {
            /* Comment this lines when going on production, only used for testing on localhost
            _gaq.push(['_setAccount', 'UA-35793871-1']);
            _gaq.push(['_setDomainName', 'none']);
            */

            /* Uncomment this lines when going on production */
            _gaq.push(['_setAccount', 'UA-7333765-1']);
            _gaq.push(['_setDomainName', '.openerp.com']);  // Allow multi-domain
            /**/
        },
        /*
        * This method MUST be overriden by saas_demo and saas_trial in order to
        * set the correct user type. By default, the user connected is local to the DB.
        */
        _get_user_type: function() {
            return 'Local User';
        },
        /*
        * This method gets the user access level, to be used as CV in GA
        */
        _get_user_access_level: function() {
            if (instance.session.uid === 1) {
                return 'Admin User';
            // Make the difference between portal users and anonymous users
            } else if (instance.session.username.indexOf('@') !== -1) {
                if (instance.session.username.indexOf('anonymous') === -1) {
                    return 'Portal User';
                } else {
                    return 'Anonymous User';
                }
            } else if (instance.session.username.indexOf('anonymous') !== -1) {
                return 'Anonymous User';
            } else {
                return 'Normal User';
            }
        },
        /*
        * This method contains the initialization of all user-related custom variables
        * stored in GA. Also other modules can override it to add new custom variables
        */
        initialize_custom: function() {
            // Track User Access Level, Custom Variable 4 in GA with visitor level scope
            // Values: 'Admin User', 'Normal User', 'Portal User', 'Anonymous User'
            _gaq.push(['_setCustomVar', 4, 'User Access Level', this.user_access_level, 1]);

            // Track User Type Conversion, Custom Variable 3 in GA with session level scope
            // Values: 'Visitor', 'Demo', 'Online Trial', 'Online Paying', 'Local User'
            _gaq.push(['_setCustomVar', 1, 'User Type Conversion', this._get_user_type(), 2]);

            return instance.session.rpc("/web/webclient/version_info", {})
                .done(function(res) {
                    _gaq.push(['_setCustomVar', 5, 'Version', res.server_version, 3]);
                    return;
                });
        },
        /*
        *  This method contains the initialization of the object and view type
        *  as an event in GA.
        */
        on_state_pushed: function(state) {
            // Track only pages corresponding to a 'normal' view of OpenERP, views
            // related to client actions are tracked by the action manager
            if (state.model && state.view_type) {
                // Track the page
                var url = instance.web_analytics.generateUrl({'model': state.model, 'view_type': state.view_type});
                this._push_event({
                    'category': state.model,
                    'action': state.view_type,
                    'label': url,
                });
            }
        },
        /*
        * This method includes the tracker into views and managers. It can be overriden
        * by other modules in order to extend tracking functionalities
        */
        include_tracker: function() {
            var t = this;
            // Track the events related with the creation and the  modification of records,
            // the view type is always form
            instance.web.FormView.include({
                init: function(parent, dataset, view_id, options) {
                    this._super.apply(this, arguments);
                    var self = this;
                    this.on('record_created', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                    this.on('record_saved', self, function(r) {
                        var url = instance.web_analytics.generateUrl({'model': r.model, 'view_type': 'form'});
                        t._push_event({
                            'category': r.model,
                            'action': 'form',
                            'label': url,
                        });
                    });
                }
            });

            // Track client actions
            instance.web.ActionManager.include({
                ir_actions_client: function (action, options) {
                    var url = instance.web_analytics.generateUrl({'action': action.tag});
                    var category = action.res_model || action.type;
                    t._push_event({
                        'category': action.res_model || action.type,
                        'action': action.name || action.tag,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track button events
            instance.web.View.include({
                do_execute_action: function(action_data, dataset, record_id, on_closed) {
                    var category = this.model || dataset.model || '';
                    var action;
                    if (action_data.name && _.isNaN(action_data.name-0)) {
                        action = action_data.name;
                    } else {
                        action = action_data.string || action_data.special || '';
                    }
                    var url = instance.web_analytics.generateUrl({'model': category, 'view_type': this.view_type});
                    t._push_event({
                        'category': category,
                        'action': action,
                        'label': url,
                    });
                    return this._super.apply(this, arguments);
                },
            });

            // Track error events
            instance.web.CrashManager.include({
                show_error: function(error) {
                    var hash = window.location.hash;
                    var params = $.deparam(hash.substr(hash.indexOf('#')+1));
                    var options = {};
                    if (params.model && params.view_type) {
                        options = {'model': params.model, 'view_type': params.view_type};
                    } else {
                        options = {'action': params.action};
                    }
                    var url = instance.web_analytics.generateUrl(options);
                    if (error.code) {
                        t._push_event({
                            'category': error.message,
                            'action': error.data.fault_code,
                            'label': url,
                            'noninteraction': true,
                        });
                    } else {
                        t._push_event({
                            'category': error.type,
                            'action': error.data.debug,
                            'label': url,
                            'noninteraction': true,
                        });
                    }
                    this._super.apply(this, arguments);
                },
            });
        },
        /*
        * Method called in order to send _trackEvent to GA
        */
        _push_event: function(options) {
            _gaq.push(['_trackEvent',
                options.category,
                options.action,
                options.label,
                options.value,
                options.noninteraction
            ]);
        },
        /*
        * Method called in order to send ecommerce transactions to GA
        */
        _push_ecommerce: function(trans_data, item_list) {
            _gaq.push(['_addTrans',
                trans_data.order_id,
                trans_data.store_name,
                trans_data.total,
                trans_data.tax,
                trans_data.shipping,
                trans_data.city,
                trans_data.state
                trans_data.country,
            ]);
            _.each(item_list, function(item) {
                _gaq.push(['_addItem',
                    item.order_id,
                    item.sku,
                    item.name,
                    item.category,
                    item.price,
                    item.quantity,
                ]);
            });
            _gaq.push(['_trackTrans']);
        },
    });

    // ----------------------------------------------------------------
    // utility functions
    // ----------------------------------------------------------------

    instance.web_analytics.generateUrl = function(options) {
        var url = '';
        _.each(options, function(value, key) {
            url += '/' + key + '=' + value;
        });
        return url;
    };

    instance.web_analytics.setupTracker = function(wc) {
        var t = wc.tracker;
        return $.when(t._get_user_access_level()).then(function(r) {
            t.user_access_level = r;
            t.initialize_custom().then(function() {
                wc.on('state_pushed', wc, t.on_state_pushed);
                t.include_tracker();
            });
        });
    };

    // Set correctly the tracker in the current instance
    if (instance.client instanceof instance.web.WebClient) {        // not for embedded clients
        instance.webclient.tracker = new instance.web_analytics.Tracker();
        instance.web_analytics.setupTracker(instance.webclient);
    } else if (!instance.client) {
        // client does not already exists, we are in monodb mode
        instance.web.WebClient.include({
            start: function() {
                var d = this._super.apply(this, arguments);
                this.tracker = new instance.web_analytics.Tracker();
                return d;
            },
            show_application: function() {
                var self = this;
                instance.web_analytics.setupTracker(self).then(function() {
                    self._super();
                });
            },
        });
    }

};
<|endoftext|>


<commit_before>minerva.collections.SourceCollection = minerva.collections.MinervaCollection.extend({

    model: minerva.models.SourceModel,
    path: 'minerva_source'

});
<commit_msg>Source collection creates source subclass on fetch<commit_after>minerva.collections.SourceCollection = minerva.collections.MinervaCollection.extend({

    model: function (attrs, options) {
        if (attrs.meta && ('minerva' in attrs.meta)) {
            if (attrs.meta.minerva.source_type === 'wms') {
                return new minerva.models.WmsSourceModel(attrs, options);
            }
        }
        else {
            console.error('Source collection includes unknown source type');
            console.error(attrs);
            girder.events.trigger('g:alert', {
                icon: 'cancel',
                text: 'Unknown source type in collection.',
                type: 'error',
                timeout: 4000
            });
        }
    },

    model: minerva.models.SourceModel,
    path: 'minerva_source'

});
<|endoftext|>


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

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { useRef, useEffect, useState } from 'react';

/**
 * Internal dependencies
 */
import Movable from '../movable';
import { useStory, useDropTargets } from '../../app';
import objectWithout from '../../utils/objectWithout';
import { useTransform } from '../transform';
import { useUnits } from '../../units';
import { getDefinitionForType } from '../../elements';
import { useGlobalIsKeyPressed } from '../keyboard';
import isClick from '../../utils/isClick';
import useCanvas from './useCanvas';

const CORNER_HANDLES = ['nw', 'ne', 'sw', 'se'];

function MultiSelectionMovable({ selectedElements }) {
  const moveable = useRef();

  const eventTracker = useRef({
    time: 0,
    coordinates: {},
  });

  const {
    actions: { updateElementsById, setSelectedElementsById },
    state: { currentPage },
  } = useStory();
  const {
    state: {
      pageSize: { width: canvasWidth, height: canvasHeight },
      nodesById,
    },
    actions: { handleSelectElement },
  } = useCanvas();
  const {
    actions: { editorToDataX, editorToDataY, dataToEditorY },
  } = useUnits();
  const {
    actions: { pushTransform },
  } = useTransform();
  const {
    state: { draggingResource },
  } = useDropTargets();

  const [isDragging, setIsDragging] = useState(false);

  // Update moveable with whatever properties could be updated outside moveable
  // itself.
  useEffect(() => {
    if (moveable.current) {
      moveable.current.updateRect();
    }
  }, [selectedElements, moveable, nodesById]);

  // ⌘ key disables snapping
  const canSnap = !useGlobalIsKeyPressed('meta');

  // ⇧ key rotates the element 30 degrees at a time
  const throttleRotation = useGlobalIsKeyPressed('shift');

  // Create targets list including nodes and also necessary attributes.
  const targetList = selectedElements.map((element) => ({
    element,
    node: nodesById[element.id],
    updateForResizeEvent: getDefinitionForType(element.type)
      .updateForResizeEvent,
  }));
  // Not all targets have been defined yet.
  if (targetList.some(({ node }) => node === undefined)) {
    return null;
  }
  const otherNodes = Object.values(
    objectWithout(
      nodesById,
      selectedElements.map((element) => element.id)
    )
  );

  /**
   * Set style to the element.
   *
   * @param {string} id Target element's id.
   * @param {Object} target Target element to update.
   * @param {Object} frame Properties from the frame for that specific element.
   */
  const setTransformStyle = (id, target, frame) => {
    target.style.transform = `translate(${frame.translate[0]}px, ${frame.translate[1]}px) rotate(${frame.rotate}deg)`;
    pushTransform(id, frame);
  };

  const frames = targetList
    ? targetList.map(({ element }) => ({
        translate: [0, 0],
        rotate: element.rotationAngle,
        direction: [0, 0],
        resize: [0, 0],
        updates: null,
      }))
    : [];

  /**
   * Resets Movable once the action is done, sets the initial values.
   */
  const resetMoveable = () => {
    targetList.forEach(({ element, node }, i) => {
      frames[i].direction = [0, 0];
      frames[i].translate = [0, 0];
      frames[i].resize = [0, 0];
      frames[i].updates = null;
      node.style.transform = '';
      node.style.width = '';
      node.style.height = '';
      pushTransform(element.id, null);
    });
    if (moveable.current) {
      moveable.current.updateRect();
    }
  };

  const onGroupEventStart = ({ events, isDrag, isRotate }) => {
    events.forEach((ev, i) => {
      const sFrame = frames[i];
      if (isDrag) {
        ev.set(sFrame.translate);
      } else if (isRotate) {
        ev.set(sFrame.rotate);
      }
    });
  };

  // Update elements once the event has ended.
  const onGroupEventEnd = ({ targets, isRotate, isResize }) => {
    targets.forEach((target, i) => {
      // Update position in all cases.
      const frame = frames[i];
      const { direction } = frame;
      const { element, updateForResizeEvent } = targetList[i];
      const properties = {
        x: element.x + editorToDataX(frame.translate[0]),
        y: element.y + editorToDataY(frame.translate[1]),
      };
      if (isRotate) {
        properties.rotationAngle = frame.rotate;
      }
      const [editorWidth, editorHeight] = frame.resize;
      const didResize = editorWidth !== 0 && editorHeight !== 0;
      if (isResize && didResize) {
        const newWidth = editorToDataX(editorWidth);
        const newHeight = editorToDataY(editorHeight);
        properties.width = newWidth;
        properties.height = newHeight;
        if (updateForResizeEvent) {
          Object.assign(
            properties,
            updateForResizeEvent(element, direction, newWidth, newHeight)
          );
        }
      }
      updateElementsById({ elementIds: [element.id], properties });
    });
    resetMoveable();
  };

  const startEventTracking = (evt) => {
    eventTracker.current.time = window.performance.now();
    eventTracker.current.coordinates = {
      x: evt.clientX,
      y: evt.clientY,
    };
  };

  const hideHandles = isDragging || Boolean(draggingResource);
  return (
    <Movable
      className={`default-movable ${hideHandles ? 'hide-handles' : ''}`}
      ref={moveable}
      zIndex={0}
      target={targetList.map(({ node }) => node)}
      draggable={true}
      resizable={!hideHandles}
      rotatable={!hideHandles}
      onDragGroup={({ events }) => {
        events.forEach(({ target, beforeTranslate }, i) => {
          const sFrame = frames[i];
          const { element } = targetList[i];
          sFrame.translate = beforeTranslate;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onDragGroupStart={({ events, inputEvent }) => {
        startEventTracking(inputEvent);
        if (!isDragging) {
          setIsDragging(true);
        }
        onGroupEventStart({ events, isDrag: true });
      }}
      onDragGroupEnd={({ targets, inputEvent }) => {
        setIsDragging(false);
        // Let's check if we consider this a drag or a click.
        // In case of a click we should select the element instead.
        if (
          isClick(
            inputEvent,
            eventTracker.current.time,
            eventTracker.current.coordinates
          )
        ) {
          const clickedElement = Object.keys(nodesById).find(
            (id) =>
              currentPage.elements[0].id !== id &&
              nodesById[id].contains(inputEvent.target)
          );
          if (clickedElement) {
            handleSelectElement(clickedElement, inputEvent);
          } else if (!inputEvent.shiftKey) {
            // Clear selection.
            setSelectedElementsById({ elementIds: [] });
          }
        } else {
          onGroupEventEnd({ targets });
        }
      }}
      onRotateGroupStart={({ events }) => {
        onGroupEventStart({ events, isRotate: true });
      }}
      onRotateGroup={({ events }) => {
        events.forEach(({ target, beforeRotate, drag }, i) => {
          const sFrame = frames[i];
          const { element } = targetList[i];
          sFrame.rotate = ((beforeRotate % 360) + 360) % 360;
          sFrame.translate = drag.beforeTranslate;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onRotateGroupEnd={({ targets }) => {
        onGroupEventEnd({ targets, isRotate: true });
      }}
      throttleRotate={throttleRotation ? 30 : 0}
      onResizeGroupStart={({ events }) => {
        events.forEach((ev, i) => {
          const frame = frames[i];
          ev.setOrigin(['%', '%']);
          if (ev.dragStart) {
            ev.dragStart.set(frame.translate);
          }
        });
      }}
      onResizeGroup={({ events }) => {
        events.forEach(({ target, direction, width, height, drag }, i) => {
          const sFrame = frames[i];
          const { element, updateForResizeEvent } = targetList[i];
          let newHeight = height;
          const newWidth = width;
          let updates = null;
          if (updateForResizeEvent) {
            updates = updateForResizeEvent(
              element,
              direction,
              editorToDataX(newWidth),
              editorToDataY(newHeight)
            );
          }
          if (updates && updates.height) {
            newHeight = dataToEditorY(updates.height);
          }
          target.style.width = `${newWidth}px`;
          target.style.height = `${newHeight}px`;
          sFrame.direction = direction;
          sFrame.resize = [newWidth, newHeight];
          sFrame.translate = drag.beforeTranslate;
          sFrame.updates = updates;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onResizeGroupEnd={({ targets }) => {
        onGroupEventEnd({ targets, isResize: true });
      }}
      renderDirections={CORNER_HANDLES}
      snappable={canSnap}
      snapElement={canSnap}
      snapHorizontal={canSnap}
      snapVertical={canSnap}
      snapCenter={canSnap}
      horizontalGuidelines={canSnap ? [0, canvasHeight / 2, canvasHeight] : []}
      verticalGuidelines={canSnap ? [0, canvasWidth / 2, canvasWidth] : []}
      elementGuidelines={otherNodes}
      snapGap={canSnap}
      isDisplaySnapDigit={false}
    />
  );
}

MultiSelectionMovable.propTypes = {
  selectedElements: PropTypes.arrayOf(PropTypes.object).isRequired,
};

export default MultiSelectionMovable;
<commit_msg>Separate handling click better within Moveable.<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import PropTypes from 'prop-types';
import { useRef, useEffect, useState } from 'react';

/**
 * Internal dependencies
 */
import Movable from '../movable';
import { useStory, useDropTargets } from '../../app';
import objectWithout from '../../utils/objectWithout';
import { useTransform } from '../transform';
import { useUnits } from '../../units';
import { getDefinitionForType } from '../../elements';
import { useGlobalIsKeyPressed } from '../keyboard';
import isClick from '../../utils/isClick';
import useCanvas from './useCanvas';

const CORNER_HANDLES = ['nw', 'ne', 'sw', 'se'];

function MultiSelectionMovable({ selectedElements }) {
  const moveable = useRef();

  const eventTracker = useRef({
    time: 0,
    coordinates: {},
  });

  const {
    actions: { updateElementsById, setSelectedElementsById },
    state: { currentPage },
  } = useStory();
  const {
    state: {
      pageSize: { width: canvasWidth, height: canvasHeight },
      nodesById,
    },
    actions: { handleSelectElement },
  } = useCanvas();
  const {
    actions: { editorToDataX, editorToDataY, dataToEditorY },
  } = useUnits();
  const {
    actions: { pushTransform },
  } = useTransform();
  const {
    state: { draggingResource },
  } = useDropTargets();

  const [isDragging, setIsDragging] = useState(false);

  // Update moveable with whatever properties could be updated outside moveable
  // itself.
  useEffect(() => {
    if (moveable.current) {
      moveable.current.updateRect();
    }
  }, [selectedElements, moveable, nodesById]);

  // ⌘ key disables snapping
  const canSnap = !useGlobalIsKeyPressed('meta');

  // ⇧ key rotates the element 30 degrees at a time
  const throttleRotation = useGlobalIsKeyPressed('shift');

  // Create targets list including nodes and also necessary attributes.
  const targetList = selectedElements.map((element) => ({
    element,
    node: nodesById[element.id],
    updateForResizeEvent: getDefinitionForType(element.type)
      .updateForResizeEvent,
  }));
  // Not all targets have been defined yet.
  if (targetList.some(({ node }) => node === undefined)) {
    return null;
  }
  const otherNodes = Object.values(
    objectWithout(
      nodesById,
      selectedElements.map((element) => element.id)
    )
  );

  /**
   * Set style to the element.
   *
   * @param {string} id Target element's id.
   * @param {Object} target Target element to update.
   * @param {Object} frame Properties from the frame for that specific element.
   */
  const setTransformStyle = (id, target, frame) => {
    target.style.transform = `translate(${frame.translate[0]}px, ${frame.translate[1]}px) rotate(${frame.rotate}deg)`;
    pushTransform(id, frame);
  };

  const frames = targetList
    ? targetList.map(({ element }) => ({
        translate: [0, 0],
        rotate: element.rotationAngle,
        direction: [0, 0],
        resize: [0, 0],
        updates: null,
      }))
    : [];

  /**
   * Resets Movable once the action is done, sets the initial values.
   */
  const resetMoveable = () => {
    targetList.forEach(({ element, node }, i) => {
      frames[i].direction = [0, 0];
      frames[i].translate = [0, 0];
      frames[i].resize = [0, 0];
      frames[i].updates = null;
      node.style.transform = '';
      node.style.width = '';
      node.style.height = '';
      pushTransform(element.id, null);
    });
    if (moveable.current) {
      moveable.current.updateRect();
    }
  };

  const onGroupEventStart = ({ events, isDrag, isRotate }) => {
    events.forEach((ev, i) => {
      const sFrame = frames[i];
      if (isDrag) {
        ev.set(sFrame.translate);
      } else if (isRotate) {
        ev.set(sFrame.rotate);
      }
    });
  };

  // Update elements once the event has ended.
  const onGroupEventEnd = ({ targets, isRotate, isResize }) => {
    targets.forEach((target, i) => {
      // Update position in all cases.
      const frame = frames[i];
      const { direction } = frame;
      const { element, updateForResizeEvent } = targetList[i];
      const properties = {
        x: element.x + editorToDataX(frame.translate[0]),
        y: element.y + editorToDataY(frame.translate[1]),
      };
      if (isRotate) {
        properties.rotationAngle = frame.rotate;
      }
      const [editorWidth, editorHeight] = frame.resize;
      const didResize = editorWidth !== 0 && editorHeight !== 0;
      if (isResize && didResize) {
        const newWidth = editorToDataX(editorWidth);
        const newHeight = editorToDataY(editorHeight);
        properties.width = newWidth;
        properties.height = newHeight;
        if (updateForResizeEvent) {
          Object.assign(
            properties,
            updateForResizeEvent(element, direction, newWidth, newHeight)
          );
        }
      }
      updateElementsById({ elementIds: [element.id], properties });
    });
    resetMoveable();
  };

  const startEventTracking = (evt) => {
    eventTracker.current.time = window.performance.now();
    eventTracker.current.coordinates = {
      x: evt.clientX,
      y: evt.clientY,
    };
  };

  // Let's check if we consider this a drag or a click, In case of a click handle click instead.
  // We are doing this here in Moveable selection since it takes over the mouseup event
  // and it can be captured here and not in the frame element.
  const clickHandled = (inputEvent) => {
    if (
      isClick(
        inputEvent,
        eventTracker.current.time,
        eventTracker.current.coordinates
      )
    ) {
      const clickedElement = Object.keys(nodesById).find(
        (id) =>
          currentPage.elements[0].id !== id &&
          nodesById[id].contains(inputEvent.target)
      );
      if (clickedElement) {
        handleSelectElement(clickedElement, inputEvent);
      } else if (!inputEvent.shiftKey) {
        // Clear selection.
        setSelectedElementsById({ elementIds: [] });
      }
      // Click was handled.
      return true;
    }
    // No click was found/handled.
    return false;
  };

  const hideHandles = isDragging || Boolean(draggingResource);
  return (
    <Movable
      className={`default-movable ${hideHandles ? 'hide-handles' : ''}`}
      ref={moveable}
      zIndex={0}
      target={targetList.map(({ node }) => node)}
      draggable={true}
      resizable={!hideHandles}
      rotatable={!hideHandles}
      onDragGroup={({ events }) => {
        events.forEach(({ target, beforeTranslate }, i) => {
          const sFrame = frames[i];
          const { element } = targetList[i];
          sFrame.translate = beforeTranslate;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onDragGroupStart={({ events, inputEvent }) => {
        startEventTracking(inputEvent);
        if (!isDragging) {
          setIsDragging(true);
        }
        onGroupEventStart({ events, isDrag: true });
      }}
      onDragGroupEnd={({ targets, inputEvent }) => {
        setIsDragging(false);
        if (!clickHandled(inputEvent)) {
          onGroupEventEnd({ targets });
        }
      }}
      onRotateGroupStart={({ events }) => {
        onGroupEventStart({ events, isRotate: true });
      }}
      onRotateGroup={({ events }) => {
        events.forEach(({ target, beforeRotate, drag }, i) => {
          const sFrame = frames[i];
          const { element } = targetList[i];
          sFrame.rotate = ((beforeRotate % 360) + 360) % 360;
          sFrame.translate = drag.beforeTranslate;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onRotateGroupEnd={({ targets }) => {
        onGroupEventEnd({ targets, isRotate: true });
      }}
      throttleRotate={throttleRotation ? 30 : 0}
      onResizeGroupStart={({ events }) => {
        events.forEach((ev, i) => {
          const frame = frames[i];
          ev.setOrigin(['%', '%']);
          if (ev.dragStart) {
            ev.dragStart.set(frame.translate);
          }
        });
      }}
      onResizeGroup={({ events }) => {
        events.forEach(({ target, direction, width, height, drag }, i) => {
          const sFrame = frames[i];
          const { element, updateForResizeEvent } = targetList[i];
          let newHeight = height;
          const newWidth = width;
          let updates = null;
          if (updateForResizeEvent) {
            updates = updateForResizeEvent(
              element,
              direction,
              editorToDataX(newWidth),
              editorToDataY(newHeight)
            );
          }
          if (updates && updates.height) {
            newHeight = dataToEditorY(updates.height);
          }
          target.style.width = `${newWidth}px`;
          target.style.height = `${newHeight}px`;
          sFrame.direction = direction;
          sFrame.resize = [newWidth, newHeight];
          sFrame.translate = drag.beforeTranslate;
          sFrame.updates = updates;
          setTransformStyle(element.id, target, sFrame);
        });
      }}
      onResizeGroupEnd={({ targets }) => {
        onGroupEventEnd({ targets, isResize: true });
      }}
      renderDirections={CORNER_HANDLES}
      snappable={canSnap}
      snapElement={canSnap}
      snapHorizontal={canSnap}
      snapVertical={canSnap}
      snapCenter={canSnap}
      horizontalGuidelines={canSnap ? [0, canvasHeight / 2, canvasHeight] : []}
      verticalGuidelines={canSnap ? [0, canvasWidth / 2, canvasWidth] : []}
      elementGuidelines={otherNodes}
      snapGap={canSnap}
      isDisplaySnapDigit={false}
    />
  );
}

MultiSelectionMovable.propTypes = {
  selectedElements: PropTypes.arrayOf(PropTypes.object).isRequired,
};

export default MultiSelectionMovable;
<|endoftext|>


<commit_before>var helper = require(__dirname + '/test-helper');
var sink;

var testForTypeCoercion = function(type){
  helper.pg.connect(helper.config, function(err, client) {
    assert.isNull(err);
    client.query("create temp table test_type(col " + type.name + ")", assert.calls(function(err, result) {
      assert.isNull(err);
      test("Coerces " + type.name, function() {
        type.values.forEach(function(val) {

          var insertQuery = client.query('insert into test_type(col) VALUES($1)',[val],assert.calls(function(err, result) {
            assert.isNull(err);
          }));

          var query = client.query({
            name: 'get type ' + type.name ,
            text: 'select col from test_type'
          });
          query.on('error', function(err) {
            console.log(err);
            throw err;
          });

          assert.emits(query, 'row', function(row) {
            assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row.col);
          }, "row should have been called for " + type.name + " of " + val);

          client.query('delete from test_type');
        });

        client.query('drop table test_type', function() {
          sink.add();
        });
      })
    }));
  })
};

var types = [{
  name: 'integer',
  values: [1, -1, null]
},{
  name: 'smallint',
  values: [-1, 0, 1, null]
},{
  name: 'bigint',
  values: [-10000, 0, 10000, null]
},{
  name: 'varchar(5)',
  values: ['yo', '', 'zomg!', null]
},{
  name: 'oid',
  values: [0, 204410, null]
},{
  name: 'bool',
  values: [true, false, null]
},{
  //TODO get some actual huge numbers here
  name: 'numeric',
  values: [-12.34, 0, 12.34, null]
},{
  name: 'real',
  values: [101.1, 0, -101.3, null]
},{
  name: 'double precision',
  values: [-1.2, 0, 1.2, null]
},{
  name: 'timestamptz',
  values: [null]
},{
  name: 'timestamp',
  values: [null]
},{
  name: 'timetz',
  values: ['13:11:12.1234-05:30',null]
},{
  name: 'time',
  values: ['13:12:12.321', null]
}];

// ignore some tests in binary mode
if (helper.config.binary) {
  types = types.filter(function(type) {
    return !(type.name in {'real':1, 'timetz':1, 'time':1});
  });
}

var valueCount = 0;
types.forEach(function(type) {
  valueCount += type.values.length;
})
sink = new helper.Sink(types.length + 1, function() {
  helper.pg.end();
})

types.forEach(function(type) {
  testForTypeCoercion(type)
});

test("timestampz round trip", function() {
  var now = new Date();
  var client = helper.client();
  client.on('error', function(err) {
    console.log(err);
    client.end();
  });
  client.query("create temp table date_tests(name varchar(10), tstz timestamptz(3))");
  client.query({
    text: "insert into date_tests(name, tstz)VALUES($1, $2)",
    name: 'add date',
    values: ['now', now]
  });
  var result = client.query({
    name: 'get date',
    text: 'select * from date_tests where name = $1',
    values: ['now']
  });

  assert.emits(result, 'row', function(row) {
    var date = row.tstz;
    assert.equal(date.getYear(),now.getYear());
    assert.equal(date.getMonth(), now.getMonth());
    assert.equal(date.getDate(), now.getDate());
    assert.equal(date.getHours(), now.getHours());
    assert.equal(date.getMinutes(), now.getMinutes());
    assert.equal(date.getSeconds(), now.getSeconds());
    test("milliseconds are equal", function() {
      assert.equal(date.getMilliseconds(), now.getMilliseconds());
    });
  });

  client.on('drain', client.end.bind(client));
});

helper.pg.connect(helper.config, assert.calls(function(err, client) {
  assert.isNull(err);
  client.query('select null as res;', assert.calls(function(err, res) {
    assert.isNull(err);
    assert.strictEqual(res.rows[0].res, null)
  }))
  client.query('select 7 <> $1 as res;',[null], function(err, res) {
    assert.isNull(err);
    assert.strictEqual(res.rows[0].res, null);
    sink.add();
  })
}))
<commit_msg>Add missing integeration test for date type parser.<commit_after>var helper = require(__dirname + '/test-helper');
var sink;

var testForTypeCoercion = function(type){
  helper.pg.connect(helper.config, function(err, client) {
    assert.isNull(err);
    client.query("create temp table test_type(col " + type.name + ")", assert.calls(function(err, result) {
      assert.isNull(err);
      test("Coerces " + type.name, function() {
        type.values.forEach(function(val) {

          var insertQuery = client.query('insert into test_type(col) VALUES($1)',[val],assert.calls(function(err, result) {
            assert.isNull(err);
          }));

          var query = client.query({
            name: 'get type ' + type.name ,
            text: 'select col from test_type'
          });
          query.on('error', function(err) {
            console.log(err);
            throw err;
          });

          assert.emits(query, 'row', function(row) {
            assert.strictEqual(row.col, val, "expected " + type.name + " of " + val + " but got " + row.col);
          }, "row should have been called for " + type.name + " of " + val);

          client.query('delete from test_type');
        });

        client.query('drop table test_type', function() {
          sink.add();
        });
      })
    }));
  })
};

var types = [{
  name: 'integer',
  values: [1, -1, null]
},{
  name: 'smallint',
  values: [-1, 0, 1, null]
},{
  name: 'bigint',
  values: [-10000, 0, 10000, null]
},{
  name: 'varchar(5)',
  values: ['yo', '', 'zomg!', null]
},{
  name: 'oid',
  values: [0, 204410, null]
},{
  name: 'bool',
  values: [true, false, null]
},{
  //TODO get some actual huge numbers here
  name: 'numeric',
  values: [-12.34, 0, 12.34, null]
},{
  name: 'real',
  values: [101.1, 0, -101.3, null]
},{
  name: 'double precision',
  values: [-1.2, 0, 1.2, null]
},{
  name: 'timestamptz',
  values: [null]
},{
  name: 'timestamp',
  values: [null]
},{
  name: 'timetz',
  values: ['13:11:12.1234-05:30',null]
},{
  name: 'time',
  values: ['13:12:12.321', null]
}];

// ignore some tests in binary mode
if (helper.config.binary) {
  types = types.filter(function(type) {
    return !(type.name in {'real':1, 'timetz':1, 'time':1});
  });
}

var valueCount = 0;
types.forEach(function(type) {
  valueCount += type.values.length;
})
sink = new helper.Sink(types.length + 1, function() {
  helper.pg.end();
})

types.forEach(function(type) {
  testForTypeCoercion(type)
});

test("timestampz round trip", function() {
  var now = new Date();
  var client = helper.client();
  client.on('error', function(err) {
    console.log(err);
    client.end();
  });
  client.query("create temp table date_tests(name varchar(10), tstz timestamptz(3))");
  client.query({
    text: "insert into date_tests(name, tstz)VALUES($1, $2)",
    name: 'add date',
    values: ['now', now]
  });
  var result = client.query({
    name: 'get date',
    text: 'select * from date_tests where name = $1',
    values: ['now']
  });

  assert.emits(result, 'row', function(row) {
    var date = row.tstz;
    assert.equal(date.getYear(),now.getYear());
    assert.equal(date.getMonth(), now.getMonth());
    assert.equal(date.getDate(), now.getDate());
    assert.equal(date.getHours(), now.getHours());
    assert.equal(date.getMinutes(), now.getMinutes());
    assert.equal(date.getSeconds(), now.getSeconds());
    test("milliseconds are equal", function() {
      assert.equal(date.getMilliseconds(), now.getMilliseconds());
    });
  });

  client.on('drain', client.end.bind(client));
});

helper.pg.connect(helper.config, assert.calls(function(err, client) {
  assert.isNull(err);
  client.query('select null as res;', assert.calls(function(err, res) {
    assert.isNull(err);
    assert.strictEqual(res.rows[0].res, null)
  }))
  client.query('select 7 <> $1 as res;',[null], function(err, res) {
    assert.isNull(err);
    assert.strictEqual(res.rows[0].res, null);
    sink.add();
  })
}))

if(!helper.config.binary) {
  test("postgres date type", function() {
    var client = helper.client();
    client.on('error', function(err) {
      console.log(err);
      client.end();
    });
    client.query("SELECT '2010-10-31'::date", assert.calls(function(err, result){
      assert.isNull(err);
      assert.UTCDate(result.rows[0].date, 2010, 9, 31, 0, 0, 0, 0);
    }));
    client.on('drain', client.end.bind(client));
  });
}
<|endoftext|>


<commit_before>import validate from './strickland';

export default function props(propRules, validatorProps) {
    return function validateProps(value, validationProps) {
        validationProps = {
            ...validatorProps,
            ...validationProps
        };

        function executeValidators(currentResult, validators) {
            if (!value || typeof value !== 'object' || !validators) {
                return currentResult;
            }

            const propNames = Object.keys(validators);

            propNames.forEach((propName) => {
                const propResult = validate(validators[propName], value[propName], validationProps);
                currentResult = applyPropResult(currentResult, propName, propResult);
            });

            return currentResult;
        }

        let initialResult = {
            props: {}
        };

        const result = executeValidators(initialResult, propRules)
        return prepareResult(value, validationProps, result);
    }
}

function applyPropResult(topLevelResult, propName, propResult) {
    return {
        ...topLevelResult,
        props: {
            ...topLevelResult.props,
            [propName]: propResult
        }
    };
}

function prepareResult(value, validationProps, result) {
    const propNames = Object.keys(result.props);
    const propPromises = [];
    let isValid = true;

    propNames.forEach((propName) => {
        const propResult = result.props[propName];

        if (propResult instanceof Promise) {
            propPromises.push(propResult.then((resolvedPropResult) => ({
                propName,
                resolvedPropResult
            })));
        } else {
            isValid = isValid && propResult.isValid;
        }
    });

    if (propPromises.length) {
        return Promise.all(propPromises).then((resolvedProps) => {
            resolvedProps.forEach(({propName, resolvedPropResult}) => {
                result = applyPropResult(result, propName, resolvedPropResult);
                isValid = isValid && resolvedPropResult.isValid;
            });

            return prepareResult(value, validationProps, result);
        });
    }

    return {
        ...validationProps,
        ...result,
        isValid
    };
}
<commit_msg>refactor: reduce the code in the props validator with a simpler approach<commit_after>import validate from './strickland';

export default function props(propRules, validatorProps) {
    return function validateProps(value, validationProps) {
        validationProps = {
            ...validatorProps,
            ...validationProps
        };

        let propsResult = {};

        if (value && typeof value === 'object' && propRules) {
            const propNames = Object.keys(propRules);

            propsResult = propNames.reduce((previousResult, propName) => ({
                ...previousResult,
                [propName]: validate(propRules[propName], value[propName], validationProps)
            }), propsResult);
        }

        return prepareResult(value, validationProps, propsResult);
    }
}

function prepareResult(value, validationProps, propsResult) {
    const propNames = Object.keys(propsResult);
    const propPromises = [];
    let isValid = true;

    propNames.forEach((propName) => {
        const propResult = propsResult[propName];

        if (propResult instanceof Promise) {
            propPromises.push(propResult.then((resolvedPropResult) => ({
                propName,
                resolvedPropResult
            })));
        } else {
            isValid = isValid && propResult.isValid;
        }
    });

    if (propPromises.length) {
        return Promise.all(propPromises).then((resolvedProps) => {
            propsResult = resolvedProps.reduce((previousResult, {propName, resolvedPropResult}) => ({
                ...previousResult,
                [propName]: resolvedPropResult
            }), propsResult);

            return prepareResult(value, validationProps, propsResult);
        });
    }

    return {
        ...validationProps,
        props: propsResult,
        isValid
    };
}
<|endoftext|>