1
\$\begingroup\$

I've been using x-editable, but recently needed to perform in-line editing, but required the user to enter one or more additional fields. For instance, to change one's password, they must confirm the password spelling and submit their old password as well. I've implemented it here.

I am far from an expert, and would appreciate any constructive criticism or suggestions. In addition to the script, if you have any UX recommendations and they are considered off topic here, please post them at the UX.SE question.

jQuery.fn.extend({
    dialog_prompt: function (options) {

        function updateTips(t) {
            tips.text(t)
                .addClass("ui-state-highlight");
            setTimeout(function () {
                tips.removeClass("ui-state-highlight", 1500);
            }, 500);
        }

        //Validation methods available to the user
        vm = {};
        vm.checkLength = function (o, n, min, max) {
            if (o.val().length > max || o.val().length < min) {
                return "Length of " + n + " must be between " + min + " and " + max + ".";
            } else {
                return false;
            }
        }
        vm.checkRequired = function (o, n) {
            if (o.val().length < 1) {
                return "Input for " + n + " is required.";
            } else {
                return false;
            }
        }
        vm.checkRegexp = function (o, regexp, n) {
            if (!(regexp.test(o.val()))) {
                return n;
            } else {
                return false;
            }
        }
        vm.checkMatches = function (e, n) {
            var val = $.trim(e[0].val());
            var arrayLength = e.length;
            for (var i = 1; i < arrayLength; i++) {
                if ($.trim(e[i].val()) != val) {
                    return n;
                }
            }
            return false;
        }

        var defaults = {
            height: 250,
            width: 250,
            validate: function () {
                return true;
            },
            title: false,
            tips: 'All fields are required.',
            url: 'index.php',
            param: {}
        };
        var settings = $.extend({}, defaults, options);
        var opener; //original element that opened

        var tips = $('<p/>', {
            text: settings.tips,
            css: {
                border: '1px solid transparent',
                padding: '0.3em'
            }
        });
        var dialog = $('<div/>').append(tips);
        var form = $('<form/>').append($('<input/>', {
            type: 'hidden',
            autofocus: 'autofocus'
        })).appendTo(dialog);
        if (settings.title) {
            dialog.prepend($('<p/>', {
                html: settings.title,
                css: {
                    color: 'blue'
                }
            }));
        }

        var update; //Input to use to update the clicked on element text
        var allFields = $([]);
        $(settings.elements).each(function () {
            var default_value = this.text;
            if (this.type == 'password') {
                var obj = {
                    value: this.text,
                    css: {
                        color: '#929292',
                        margin: '1px 0px'
                    }
                };
                if (this.width) {
                    obj.css.width = this.width;
                }
                var input_fake = $('<input/>', obj)
                    .focus(function () {
                    $(this).hide();
                    input_real.show().focus();
                })
                    .blur(function () {
                    $(this).val(default_value);
                })
                    .appendTo(form);
                allFields = allFields.add(input_fake);

                var obj = {
                    css: {
                        margin: '1px 0px',
                        display: 'none'
                    },
                    type: 'password'
                };
                if (this.width) {
                    obj.css.width = this.width;
                }
                if (this.name) {
                    obj.name = this.name;
                }
                var input_real = $('<input/>', obj)
                    .focus(function () {
                    $(this).removeClass('ui-state-error');
                })
                    .blur(function () {
                    if ($.trim(this.value) == '') {
                        $(this).hide();
                        input_fake.show();
                    }
                })
                    .appendTo(form);
                allFields = allFields.add(input_real);

                if (this.update) {
                    update = input_real
                }
            } else {
                var obj = {
                    value: this.text,
                    css: {
                        color: '#929292',
                        margin: '1px 0px'
                    }
                };
                if (this.width) {
                    obj.css.width = this.width;
                }
                if (this.type) {
                    obj.type = this.type;
                }
                if (this.name) {
                    obj.name = this.name;
                }
                var input = $('<input/>', obj)
                    .focus(function () {
                    $(this).removeClass('ui-state-error');
                    if (this.value == default_value) {
                        $(this).val('').css('color', 'black');
                    }
                })
                    .blur(function () {
                    if ($.trim(this.value) == '') {
                        $(this).val(default_value).css('color', '#929292');
                    }
                })
                    .appendTo(form);
                allFields = allFields.add(input);
                if (this.update) {
                    update = input
                }
            }
        })

        dialog.appendTo('body').dialog({
            autoOpen: false,
            height: settings.height,
            width: settings.width,
            close: function () {
                allFields.removeClass("ui-state-error").val('').blur();
                opener.blur();
                tips.text(settings.tips);
            },
            position: {
                my: "left top",
                at: "left bottom",
                of: this
            },
            buttons: [{
                text: "Ok",
                icons: {
                    primary: "ui-icon-check",
                },
                showText: false,
                click: function () {
                    allFields.removeClass("ui-state-error");
                    var error = settings.validate(form, vm);
                    if (error === true) {
                        var $t = $(this);
                        var post = {};
                        allFields.each(function (i) {
                            if (this.name) {
                                post[this.name] = this.value;
                            }
                        });
                        $.post(settings.url, $.extend(post, settings.param), function (error) {
                            if (error) {
                                updateTips(error)
                            } else {
                                if (update) {
                                    opener.text(update.val());
                                }
                                $t.dialog("close");
                            }
                        });
                    } else {
                        updateTips(error.error);
                        if (error.element.attr('type') == 'password') {
                            error.element.addClass("ui-state-error").prev().addClass("ui-state-error");
                        } else {
                            error.element.addClass("ui-state-error");
                        }
                    }
                }
            }, {
                text: "Cancel",
                icons: {
                    primary: "ui-icon-closethick",
                },
                showText: false,
                click: function () {
                    $(this).dialog("close");
                }
            }]
        })
            .parent().find('.ui-dialog-titlebar').hide();

        return this.each(function () {
            $(this).css({
                'border-bottom': '1px dashed #0088cc',
                    'text-decoration': 'none',
                    'color': '#dd1144',
                    'font-style': 'italic'
            })
                .click(function () {
                opener = $(this);
                dialog.dialog('open');
            });
        });
    }
});

$('#name').editable();

$("#email").dialog_prompt({
    elements: [{
        text: 'Email',
        name: 'email',
        update: true
    }, {
        text: 'Enter Your Password',
        name: 'password',
        type: 'password'
    }],
    url: '/echo/html/',
    param: {
        task: 'saveEmail'
    },
    //title:'Update email',
    validate: function (form, vm) {
        //return {error:'error text', element:jQueryOBJ} if error, and true if okay
        var emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
        var email = form.find('input[name=email]');
        var password = form.find('input[name=password]');
        if (error = vm.checkLength(email, "email", 6, 80)) {
            return {
                error: error,
                element: email
            }
        };
        if (error = vm.checkRequired(password, "password")) {
            return {
                error: error,
                element: password
            }
        };
        if (error = vm.checkRegexp(email, emailRegex, "Invalid email address.")) {
            return {
                error: error,
                element: email
            }
        };
        if (error = vm.checkRegexp(password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9")) {
            return {
                error: error,
                element: password
            }
        };
        return true;
    }
});
$("#password").dialog_prompt({
    elements: [{
        text: 'New Password',
        name: 'password',
        width: 200,
        type: 'password'
    }, {
        text: 'Confirm New Password',
        name: 'password2',
        width: 200,
        type: 'password'
    }, {
        text: 'Old Password',
        name: 'adminConfirmPassword',
        width: 200,
        type: 'password'
    }],
    height: 300,
    width: 250,
    url: '/echo/html/',
    param: {
        task: 'savePassword'
    },
    validate: function (form, vm) {
        console.log(form, vm, this)
        //return {error:'error text', element:jQueryOBJ} if error, and true if okay
        var password = form.find('input[name=password]');
        var password2 = form.find('input[name=password2]');
        var adminConfirmPassword = form.find('input[name=adminConfirmPassword]');
        if (error = vm.checkLength(password, "password", 5, 16)) {
            return {
                error: error,
                element: password
            }
        };
        if (error = vm.checkRegexp(password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9")) {
            return {
                error: error,
                element: password
            }
        };
        if (error = vm.checkMatches([password, password2], "Passwords do not match.")) {
            return {
                error: error,
                element: password2
            }
        };
        if (error = vm.checkRequired(adminConfirmPassword, "password")) {
            return {
                error: error,
                element: adminConfirmPassword
            }
        };
        return true;
    }
});

<div>Name: <a id="name" href="javascript:void(0)"></a>

</div>
<div>Email: <a id="email" href="javascript:void(0)">Empty</a>

</div>
<div>Password: <a id="password" href="javascript:void(0)">***</a>

</div>
\$\endgroup\$
  • \$\begingroup\$ This question is a little confusing. You've got links pointing all over the place, and you say that the code snippet you've provided is an old version? Why do you want an old version (something you've already updated/improved upon) to be reviewed? How likely is it that an answer will be greeted with "Thanks for reviewed, but I've actually already fixed that problem in my new version of this script"? \$\endgroup\$ – nhgrif Apr 26 '15 at 15:34
  • \$\begingroup\$ @nhgrif Yea, agree. I edited the original post to get rid of the old version. Thanks \$\endgroup\$ – user1032531 Apr 26 '15 at 17:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.