'Problem with caret position when modifying a field (HTML+JS)

The original developer programmed the following JavaScript, which is a little amateurish in my opinion, but I don't work much in Javscript, so I can't offer a better solution with the time I have.

The problem I do need to solve is that each time you press any key that sends input to the text field (any <input type="text" class="phone_val"...), the caret moves to the end, cause the code is replacing it.

The purpose of the code is to format the number for use in the database. Allowed patterns are:

          235 - 5555
    (321) 234 - 5555
  1 (321) 234 - 5555
 21 (321) 234 - 5555
012 (321) 234 - 5555

These are the phone number types we use in our customer base. I need to be able to apply these patterns without the caret (text cursor position) moving to the end every time a key is pressed. It's not a problem until the person needs to correct some characters in the middle of the field. I wouldn't mind being able to seriously simplify and shrink the code down as well, with a regular expression.

HTML:

<input type="text" class="phone_val" style="width: 85%; text-align: right;"
       value="<%= CustomerFields("billing_phone") %>" id="billing_phone"
       name="billing_phone" tabindex="10" />

Javascript (jQuery assumed):

$(document).ready(function() {
    $('.phone_val').attr('maxlength', 20);
    $('.phone_val').keyup(function(){
        var startVal, finVal, i;
        startVal = $(this).val().replace(/\D/g,'');
        if (startVal.length <= 7) {
            finVal = "";
            for (i = 0; i < startVal.length; i += 1) {
                if (i === 3) {
                    finVal += " - " + startVal.charAt(i);
                }
                else {
                    finVal += startVal.charAt(i);
                }
            }
        }
        else if (startVal.length > 7 && startVal.length < 11) {
            finVal = "(";
            for (i = 0; i < startVal.length; i += 1) {
                if (i === 3) {
                    finVal += ") " + startVal.charAt(i);
                }
                else if (i === 6) {
                    finVal += " - " + startVal.charAt(i);
                }
                else {
                    finVal += startVal.charAt(i);
                }
            }
        }
        else if (startVal.length >= 11) {
            finVal = "";
            stopP = startVal.length < 13 ? startVal.length - 11 : 2;
            for (i = 0; i < startVal.length; i += 1) {
                if (i === stopP) {
                    finVal += startVal.charAt(i) + " (";
                }
                else if (i === (stopP + 4)) {
                    finVal += ") " + startVal.charAt(i);
                }
                else if (i === (stopP + 7)) {
                    finVal += " - " + startVal.charAt(i);
                }
                else {
                    finVal += startVal.charAt(i);
                }
            }
        }

        if (startVal.length < 4) {
            finVal = finVal.replace(/\D/g,'');
        }
        $(this).val(finVal);
    });
});


Solution 1:[1]

Here's what I've got so far:

$('.phone_val').blur(function () {
    var inpVal = $(this).val().replace(/\D/g, ''); //get rid of everything but numbers

    // RegEx for:
    //    xxx (xxx) xxx - xxxx
    //     xx (xxx) xxx - xxxx
    //      x (xxx) xxx - xxxx
    //        (xxx) xxx - xxxx
    inpVal = inpVal.replace(/^(\d{0,3})(\d{3})(\d{3})(\d{4})$/, '$1($2) $3 - $4');

    // RegEx for (needs a separate one because of the parentheses):
    //              xxx - xxxx
    inpVal = inpVal.replace(/^(\d{3})(\d{4})$/, '$1 - $2');

    $(this).val(inpVal);
});

That takes care of 7 digits and 10-13 digits, but I'm not sure what to do with the ones in between. Should I format those as well, so that the user can see their mistakes easily? Or should I leave them alone?

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1