As part of a new UI library, I have created a custom server control that creates the markup for a simple textbox using the new HTML5 input type of "tel" and the pattern attribute. The Phone Textbox supports the following features:
Just a basic input element, with a normal type attribute of "tel" and some custom data (data-*) attributes to allow feature customization. Once the Script stuff is in place on a website, any page can take advantage of this Phone Textbox by simply setting an input's type attribute to "tel" and setting the desired optional custom data attributes. If native browser support is available, then the browser implementation of the control will be used in addtion to the onkey up and pattern validation.
That sounds like a DRY solution to me (see UI Manifesto).
<div class="form legendLook horizontalFormLayout"> <div id="hdivFormTest1ConfirmationMessage" class="confirmationMessageWrapper hide"></div> <label for="txtPhone1">Phone #1:</label> <input type="tel" id="txtPhone1" style="width:500px;" required placeholder="Regular and toll-free number with optional extension." data-countryIsoCode="US" data-allowExtension="true" data-useTollFreeFormatting="true" data-formGroup="formAuthenticate" name="Value" /> <label for="txtPhone2">Phone #2:</label> <input type="tel" id="txtPhone2" style="width:500px;" required placeholder="Regular and toll-free number, but extension not allowed." data-countryIsoCode="US" data-allowExtension="false" data-useTollFreeFormatting="true" data-formGroup="formAuthenticate" name="_" /> <label for="txtPhone3">Phone #3:</label> <input type="tel" id="txtPhone3" style="width:500px;" required placeholder="Regular number with optional extension, but no toll-free formatting." data-countryIsoCode="US" data-allowExtension="true" data-useTollFreeFormatting="false" data-formGroup="formAuthenticate" name="_" /> <div class="formButtonWrapper clearFix"> <input type="submit" class="ajaxFormPost buttonStrong" value="Submit" data-formGroup="formAuthenticate" data-serviceRequestUrl="..." data-successFunction="successFormTest1" data-confirmActionMessage="" data-processingMessage="" data-overlayWindowWhileProcessing="true" /> </div> </div>
function formatPhoneNumber(value, countryIsoCode, allowExtension, useTollFreeFormatting, event) { var requestingElement = $("#" + event.target.id); //8 = Backspace //9 = Tab (so will stay highlighted) //16 = Reverse Tab - Shift+Tab (so will stay highlighted) if (getKeycode(event) != 8 && getKeycode(event) != 9 && getKeycode(event) != 16) { var unformattedPhoneNumber = makeNumeric(value, false, null, null); var isValidTollFreePrefix = false; var formattedPhoneNumber = ""; switch (countryIsoCode.toUpperCase()) { default: //Build and assign the "pattern", if not already there. if (!isAttrDefined(requestingElement.attr("pattern")) || requestingElement.attr("pattern").length == 0) { //(801) 123-1234 - /^\((\d{3})\) (\d{3})-(\d{4})$/ //(801) 123-1234 ext. 12345 - /^\((\d{3})\) (\d{3})-(\d{4}) ext. \d+$/ //1-800-123-1234 - /^1-(800|888|877|866|855|844|833|822)-(\d{3})-(\d{4})$/ //1-800-123-1234 ext. 12345 - /^1-(800|888|877|866|855|844|833|822)-(\d{3})-(\d{4}) ext. \d+$/ //all combined - /^((\((\d{3})\) (\d{3})-(\d{4}))|(\((\d{3})\) (\d{3})-(\d{4}) ext. \d+)|(1-(800|888|877|866|855|844|833|822)-(\d{3})-(\d{4}))|(1-(800|888|877|866|855|844|833|822)-(\d{3})-(\d{4}) ext. \d+))$/ var patternValue = "/^((\\((\\d{3})\\) (\\d{3})-(\\d{4}))|(\\((\\d{3})\\) (\\d{3})-(\\d{4}) ext. \\d+)|(1-(800|888|877|866|855|844|833|822)-(\\d{3})-(\\d{4}))|(1-(800|888|877|866|855|844|833|822)-(\\d{3})-(\\d{4}) ext. \\d+))$/"; requestingElement.attr("pattern", patternValue); } //Assign the "maxlength", if not already there. if (!isAttrDefined(requestingElement.attr("maxlength")) || requestingElement.attr("maxlength").length == 0) { if (allowExtension) { requestingElement.attr("maxlength", "30"); } else { requestingElement.attr("maxlength", "14"); } } //valid current & future toll free number prefixes : http://en.wikipedia.org/wiki/Toll_free_number var validTollFreePrefixies = new Array("800", "888", "877", "866", "855", "844", "833", "822"); var validTollFreePrefixiesFirst2Only = new Array("80", "88", "87", "86", "85", "84", "83", "82"); var first3Digits = unformattedPhoneNumber.charAt(0) + unformattedPhoneNumber.charAt(1) + unformattedPhoneNumber.charAt(2); var first4Digits = first3Digits + unformattedPhoneNumber.charAt(3); for (pfx in validTollFreePrefixies) { if (validTollFreePrefixies[pfx] == first3Digits) { isValidTollFreePrefix = true; unformattedPhoneNumber = "1" + unformattedPhoneNumber; } else if ("1" + validTollFreePrefixies[pfx] == first4Digits) { isValidTollFreePrefix = true; } else if ("1" + validTollFreePrefixiesFirst2Only[pfx] == first3Digits && unformattedPhoneNumber.length == 3) { isValidTollFreePrefix = true; } } if (!useTollFreeFormatting) { isValidTollFreePrefix = false; } if (isValidTollFreePrefix) { //1-###-###-#### ext. #### formattedPhoneNumber += "1" + "-" + unformattedPhoneNumber.charAt(1) + unformattedPhoneNumber.charAt(2) + unformattedPhoneNumber.charAt(3); if (unformattedPhoneNumber.length > 3) { formattedPhoneNumber += "-"; formattedPhoneNumber += unformattedPhoneNumber.charAt(4) + unformattedPhoneNumber.charAt(5) + unformattedPhoneNumber.charAt(6); if (unformattedPhoneNumber.length > 6) { formattedPhoneNumber += "-"; formattedPhoneNumber += unformattedPhoneNumber.charAt(7) + unformattedPhoneNumber.charAt(8) + unformattedPhoneNumber.charAt(9) + unformattedPhoneNumber.charAt(10); if (allowExtension) { if (unformattedPhoneNumber.length > 11) { formattedPhoneNumber += " ext. "; for (var upn = 11; upn <= (unformattedPhoneNumber.length - 1); upn++) { //the (<= & -1) is needed to not get messed up with Packer 3.1 compression formattedPhoneNumber += unformattedPhoneNumber.charAt(upn); } } } } } } else { //If less then 4 in length, this still could be a valid toll-free number if (unformattedPhoneNumber.length > 2) { if (unformattedPhoneNumber.charAt(0) == "1") { var tempUnformattedPhoneNumber = ""; for (var upn2 = 1; upn2 <= (unformattedPhoneNumber.length - 1); upn2++) { //the (<= & -1) is needed to not get messed up with Packer 3.1 compression tempUnformattedPhoneNumber += unformattedPhoneNumber.charAt(upn2); } unformattedPhoneNumber = tempUnformattedPhoneNumber; } //(###) ###-#### ext. #### if (unformattedPhoneNumber.length > 2 || value.charAt(0) == "(") { formattedPhoneNumber += "("; } formattedPhoneNumber += unformattedPhoneNumber.charAt(0) + unformattedPhoneNumber.charAt(1) + unformattedPhoneNumber.charAt(2); if (unformattedPhoneNumber.length > 2) { formattedPhoneNumber += ") "; formattedPhoneNumber += unformattedPhoneNumber.charAt(3) + unformattedPhoneNumber.charAt(4) + unformattedPhoneNumber.charAt(5); if (unformattedPhoneNumber.length > 5) { formattedPhoneNumber += "-"; formattedPhoneNumber += unformattedPhoneNumber.charAt(6) + unformattedPhoneNumber.charAt(7) + unformattedPhoneNumber.charAt(8) + unformattedPhoneNumber.charAt(9); if (allowExtension) { if (unformattedPhoneNumber.length > 10) { formattedPhoneNumber += " ext. "; for (var upn3 = 10; upn3 <= (unformattedPhoneNumber.length - 1); upn3++) { //the (<= & -1) is needed to not get messed up with Packer 3.1 compression formattedPhoneNumber += unformattedPhoneNumber.charAt(upn3); } } } } } } else { if (value == "1" && useTollFreeFormatting) { formattedPhoneNumber = "1-"; } else if (value == "1--" && useTollFreeFormatting) { formattedPhoneNumber = "1-"; } else if (value == "1-8" && useTollFreeFormatting) { formattedPhoneNumber = "1-8"; } else if (value.charAt(0) == "(") { formattedPhoneNumber = "(" + unformattedPhoneNumber; } else { formattedPhoneNumber = unformattedPhoneNumber; } } } break; } return formattedPhoneNumber; } else { return value; } } //Enable Phone Textbox(es) $(parentElementSelector + " input[type='tel']").each(function () { $(this).keyup(function (event) { var countryIsoCode = ((!isAttrDefined($(this).attr("data-countryIsoCode")) || $(this).attr("data-countryIsoCode").length == 0) ? $("#hfGlobalCountryIsoCode").val() : $(this).attr("data-countryIsoCode")); var allowExtension = (($(this).attr("data-allowExtension") == "true") ? true : false); var useTollFreeFormatting = (($(this).attr("data-useTollFreeFormatting") == "true") ? true : false); $(this).val(formatPhoneNumber($(this).val(), countryIsoCode, allowExtension, useTollFreeFormatting, event)); }); });
Not applicable.