<commit_before>html.displayErrorMessage = function(validationResults, observer, input){
    //callback when validation finish
    var error = validationResults.firstOrDefault(function(i){return i.isValid === false;});
    if(error){
        input.style.color = 'red';
        input.setAttribute('data-toggle', 'popover');
        input.setAttribute('data-content', error.message);
        $(input).popover('show');
        $(input).parent().prev().css('color', 'red');
    } else {
        input.style.color = 'black';
        input.title = '';
        input.removeAttribute('data-toggle');
        input.removeAttribute('data-content');
        $(input).popover('destroy');
        $(input).parent().prev().css('color', '');
    }
};

html.scripts.render('../html-ui/datepicker.js').done(function () {
    html.data.validation.availableName = function (message) {
        var self = this;
        self.validate(function(newValue, oldValue) {
            html.getJSON('./resources/existNames.json')
                .done(function (names) {
                    if (names.indexOf(html.trim(newValue)) < 0) {
                        self.setValidationResult(true, message);
                    } else {
                        self.setValidationResult(false, message);
                    }
                });
        });
        return self;
    };
    
    var Step1 = function(model) {
        var self = this;
        this.login = html.data('')
            .required('Login info is required.')
            .availableName('This name is not available.')
            .delay(300);
        this.email = html.data('').required('Email is required.').isEmail('Must be a valid email.').delay(300);
        this.password = html.data('')
            .required('Password is required.')
            .minLength(6, 'Password must contain at least 6 characters')
            .delay(300)
            .subscribe(function(val) {
                self.confirmation.isDirty() && self.confirmation.validate();
            });
        this.confirmation = html.data('')
            .required('Password confirmation is required.')
            .equal(this.password, 'Password confirmation not matched.')
            .delay(300);
    };

    var Step2 = function(model) {
        var self = this;
        this.name = html.data('').required('Name is required.');
        this.lastName = html.data('').required('Last name is required.');
        this.dateOfBirth = html.data('').required('Date of birth is requried.')
        this.gender = html.data('').required('Gender is required.'); 
        this.comment = html.data('')
            .subscribe(function(newVal, oldVal) {
                if (newVal && newVal.length > 520) {
                    setTimeout(function () {
                        self.comment(oldVal);
                    });
                }
            });
        this.charLeft = html.data(function() {
            var length = self.comment().length;
            return length <= 520? 520 - length: 0;
        });
    };

    var Step3 = function(model) {
        var self = this;
        this.phoneNo = html.data('');
        this.phoneNo.pattern = '(999) 999-99-99';
        this.phoneNo.maskInputRequired(this.phoneNo.pattern,'Phone number is required.');
        this.country = html.data('').required('Country is required.');
        this.city = html.data('').required('City is requried.')
        this.address = html.data('').required('Address is required.'); 
        this.address2 = html.data('');
        this.address2Enabled = html.data(function() {
            return self.address.isValid();
        });
        //this.address.setDependency(this.address2Enabled);
        this.socialNetwork = html.data(['', 'Facebook', 'Twitter', 'Instagram', 'Google+']);
        this.selectedSocialNetwork = html.data('').required('Social network is required');
    };

    var ViewModel = function () {
        var self = this;
        this.checkStepValid = function (stepNumber) {
            stepNumber = stepNumber || self.step();
            var step = self['step' + stepNumber],
                result = true;
            for (var prop in step) {
                if(!step[prop].isValid) continue;
                var isValid = step[prop].isValid();
                if(!isValid) {
                    result = false;
                }
            }
            return result;
        };
        this.step = html.data(1);
        
        // events
        this.nextStepClick = function(e) {
            vm.step(vm.step() + 1);
            html.navigate('#step' + vm.step());
        };
        this.step1 = new Step1;
        this.step2 = new Step2;
        this.step3 = new Step3;
        
        this.nextStepEnabled = html.data(function () {
            return self.checkStepValid(self.step());
        });
    };

    var vm = new ViewModel;
    window.vm = vm;

    /* BINDING DATA TO VIEW */
    (function(vm) {
        $('form > div').hide();
        $('form > div').first().show();
        html('#next').click(vm.nextStepClick).enable(vm.nextStepEnabled);
        
        // step1
        html('#txtLogin').input(vm.step1.login);
        html('#txtEmail').input(vm.step1.email);
        html('#txtPassword').input(vm.step1.password);
        html('#txtPasswordConfirmation').input(vm.step1.confirmation);
        
        // step2
        html('#txtName').input(vm.step2.name);
        html('#txtLastName').input(vm.step2.lastName);
        html.datepicker(vm.step2.dateOfBirth).input(html.id.txtDoB).autoClose(true);
        html('#txtGender').input(vm.step2.gender);
        vm.step2.comment.displayError = false;
        html('#txtComment').textarea(vm.step2.comment);
        html('#charLeft').text(vm.step2.charLeft);
        
        // step3
        html('#txtPhone').maskInput(vm.step3.phoneNo, vm.step3.phoneNo.pattern);
        html('#txtCountry').input(vm.step3.country);
        html('#txtCity').input(vm.step3.city);
        html('#txtAddress').input(vm.step3.address);
        html('#txtAddress2').input(vm.step3.address2).enable(vm.step3.address2Enabled);
        html('#ddlSocialNetwork').dropdown(vm.step3.socialNetwork, vm.step3.selectedSocialNetwork);
    })(vm);
    
    /* ROUTING */
    html.router('#step:step', function(step) {
        step = parseInt(step);
        if(step > 1 && !vm.checkStepValid(step - 1)) {
            html.navigate('#step' + (step - 1));
            // show error message when the previous step is not valid
            var models = vm['step' + (step - 1)];
            for (var i in models) {
                models[i].validate();
            }
            $('.html-error').first().prev().focus();
            return;
        }
        vm.step(step);
        $('#lastStep').hide();
        $('form > div').hide();<commit_msg>fix bug for maximum length textarea - caret position not in the right place<commit_after>html.displayErrorMessage = function(validationResults, observer, input){
    //callback when validation finish
    var error = validationResults.firstOrDefault(function(i){return i.isValid === false;});
    if(error){
        input.style.color = 'red';
        input.setAttribute('data-toggle', 'popover');
        input.setAttribute('data-content', error.message);
        $(input).popover('show');
        $(input).parent().prev().css('color', 'red');
    } else {
        input.style.color = 'black';
        input.title = '';
        input.removeAttribute('data-toggle');
        input.removeAttribute('data-content');
        $(input).popover('destroy');
        $(input).parent().prev().css('color', '');
    }
};

html.maximumLength = function (observer, maxLength) {
    var ele = html.element(),
        startPosition,
        endPosition;
    html.keydown(function () {
        startPosition = ele.selectionStart;
        endPosition = ele.selectionEnd;
    });
    observer.subscribe(function (newVal, oldVal) {
        if (observer().length > maxLength) {
            observer(oldVal);
            ele.selectionStart = startPosition;
            ele.selectionEnd = endPosition;
        }
    });
};

html.scripts.render('../html-ui/datepicker.js').done(function () {
    html.data.validation.availableName = function (message) {
        var self = this;
        self.validate(function(newValue, oldValue) {
            html.getJSON('./resources/existNames.json')
                .done(function (names) {
                    if (names.indexOf(html.trim(newValue)) < 0) {
                        self.setValidationResult(true, message);
                    } else {
                        self.setValidationResult(false, message);
                    }
                });
        });
        return self;
    };
    
    var Step1 = function(model) {
        var self = this;
        this.login = html.data('')
            .required('Login info is required.')
            .availableName('This name is not available.')
            .delay(300);
        this.email = html.data('').required('Email is required.').isEmail('Must be a valid email.').delay(300);
        this.password = html.data('')
            .required('Password is required.')
            .minLength(6, 'Password must contain at least 6 characters')
            .delay(300)
            .subscribe(function(val) {
                self.confirmation.isDirty() && self.confirmation.validate();
            });
        this.confirmation = html.data('')
            .required('Password confirmation is required.')
            .equal(this.password, 'Password confirmation not matched.')
            .delay(300);
    };

    var Step2 = function(model) {
        var self = this;
        this.name = html.data('').required('Name is required.');
        this.lastName = html.data('').required('Last name is required.');
        this.dateOfBirth = html.data('').required('Date of birth is requried.')
        this.gender = html.data('').required('Gender is required.'); 
        this.comment = html.data('');
        this.charLeft = html.data(function() {
            var length = self.comment().length;
            return length <= 520? 520 - length: 0;
        });
    };

    var Step3 = function(model) {
        var self = this;
        this.phoneNo = html.data('');
        this.phoneNo.pattern = '(999) 999-99-99';
        this.phoneNo.maskInputRequired(this.phoneNo.pattern,'Phone number is required.');
        this.country = html.data('').required('Country is required.');
        this.city = html.data('').required('City is requried.')
        this.address = html.data('').required('Address is required.'); 
        this.address2 = html.data('');
        this.address2Enabled = html.data(function() {
            return self.address.isValid();
        });
        //this.address.setDependency(this.address2Enabled);
        this.socialNetwork = html.data(['', 'Facebook', 'Twitter', 'Instagram', 'Google+']);
        this.selectedSocialNetwork = html.data('').required('Social network is required');
    };

    var ViewModel = function () {
        var self = this;
        this.checkStepValid = function (stepNumber) {
            stepNumber = stepNumber || self.step();
            var step = self['step' + stepNumber],
                result = true;
            for (var prop in step) {
                if(!step[prop].isValid) continue;
                var isValid = step[prop].isValid();
                if(!isValid) {
                    result = false;
                }
            }
            return result;
        };
        this.step = html.data(1);
        
        // events
        this.nextStepClick = function(e) {
            vm.step(vm.step() + 1);
            html.navigate('#step' + vm.step());
        };
        this.step1 = new Step1;
        this.step2 = new Step2;
        this.step3 = new Step3;
        
        this.nextStepEnabled = html.data(function () {
            return self.checkStepValid(self.step());
        });
    };

    var vm = new ViewModel;
    window.vm = vm;

    /* BINDING DATA TO VIEW */
    (function(vm) {
        $('form > div').hide();
        $('form > div').first().show();
        html('#next').click(vm.nextStepClick).enable(vm.nextStepEnabled);
        
        // step1
        html('#txtLogin').input(vm.step1.login);
        html('#txtEmail').input(vm.step1.email);
        html('#txtPassword').input(vm.step1.password);
        html('#txtPasswordConfirmation').input(vm.step1.confirmation);
        
        // step2
        html('#txtName').input(vm.step2.name);
        html('#txtLastName').input(vm.step2.lastName);
        html.datepicker(vm.step2.dateOfBirth).input(html.id.txtDoB).autoClose(true);
        html('#txtGender').input(vm.step2.gender);
        vm.step2.comment.displayError = false;
        html('#txtComment').textarea(vm.step2.comment).maximumLength(vm.step2.comment, 520);
        html('#charLeft').text(vm.step2.charLeft);
        
        // step3
        html('#txtPhone').maskInput(vm.step3.phoneNo, vm.step3.phoneNo.pattern);
        html('#txtCountry').input(vm.step3.country);
        html('#txtCity').input(vm.step3.city);
        html('#txtAddress').input(vm.step3.address);
        html('#txtAddress2').input(vm.step3.address2).enable(vm.step3.address2Enabled);
        html('#ddlSocialNetwork').dropdown(vm.step3.socialNetwork, vm.step3.selectedSocialNetwork);
    })(vm);
    
    /* ROUTING */
    html.router('#step:step', function(step) {
        step = parseInt(step);
        if(step > 1 && !vm.checkStepValid(step - 1)) {
            html.navigate('#step' + (step - 1));
            // show error message when the previous step is not valid
            var models = vm['step' + (step - 1)];
            for (var i in models) {
                models[i].validate();
            }
            $('.html-error').first().prev().focus();
            return;
        }
        vm.step(step);
        $('#lastStep').hide();
        $('form > div').hide();
{'fraction_non_alphanumeric': 0.1579250305777394, 'fraction_numerical': 0.011439671918843082, 'mean_word_length': 2.004755728491137, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '104172', 'n_tokens_mistral': 3952, 'n_tokens_neox': 3838, 'n_words': 695}