30 марта 2012 г.

Поле для форматированного ввода числа

Вступление
Вам никогда не требовалось контролировать пользователя при вводе данных в форму на сайте? На этой недели такую задачу я получил на работе. Имелось поле для ввода ссумы. Но чтобы ввод был форматированным не "100000", а "100 000". И соответстенно только цифры.

Что нам Google подскажет
Как Google(Yandex) не борется за хороший поиск, а оригинальные варианты он не отбирает. Получается список почти идентичных вариантов контроля ввода через событие keypress. Html5 тоже не помог type="number" даже не контролирует ввод только цифр. Не много отвлекусь, поиск по блогам Google или Яндекса частично помогает разрядить выдачу однотипных решений. Но все равно чтобы найти хороший метод в выдаче нужно постараться.

Что нам понадобится
В стартное html поле ввода input можно ввести данные тремя спосбами:
  1. с клавиатуры. Это можно отловить слушая события keypress, keydown, keyup;
  2. вставить из буфера обмена;
  3. автоподстановка в браузере. 
Почти все найденные мной в поисковике решения борятся с первым способом, неучитывая два других. Для борьбы с вставкой из буфера обмена я воспользовался JQuery плагином jQueryTextChange (ссылка1, ссылка2).  Для борьбы с автоподстановкой в тег input можно добавить атрибут autocomplete со значением off:
<input autocomplete="off" autofocus="" id="principal_amount" name="principal_amount" required type="text">
Как это выглядит
Представляю свое решение
if (!Array.prototype.indexOf){// Привет IE
    Array.prototype.indexOf = function(elt/*, from*/){
        var len = this.length,
            from = Number(arguments[1]) || 0;
        from = (from < 0) ? Math.ceil(from) : Math.floor(from);
        if (from < 0) from += len;
        for (; from < len; from++){
            if (from in this && this[from] === elt)
                return from;
        }
        return -1;
    };
}
function numberFormat(str){ // форматируем строку 12000 -> 12 000
    var     str_array=[],
            length=str.length;
    var undefined2string=function(val){
        return val?val:"";
    }
    for(var i=length-1; i>=0;i-=3){
        str_array.unshift(
            undefined2string(str[i-2])+undefined2string(str[i-1])+undefined2string(str[i])
        );
    }
    var resStr=str_array.join(" ");
    return resStr;
}
function createFormatControl(element,onchange_callback){
    if (!(element instanceof HTMLInputElement))
        throw("Wrong type of node, need HTMLInputElement");
        
    onchange_callback=onchange_callback||function(){};
    /*
    @e.keyCode:
        9 - Tab
        8 - Backspace
        46 - Del
        48-57 - 0-9
        13 - Enter
        37-40 - arrow: left,top,right,bottom
        35 -Home
        36 -End
    */
    $(element).bind("keydown",function(e){//контролируем ввод с клавиатуры
        var     keyCodeArray=[8,9,13,46];
        if(
            (e.keyCode>47 &&  e.keyCode<58) ||
            keyCodeArray.indexOf(e.keyCode) >= 0 ||
            (e.keyCode>34 &&  e.keyCode<41)
        ){
            return true;
        }else{
            return false;
        }
    }).bind("textchange",function(e){// Контролируем изменение текста (вставку из буфера обмена.)
    
        var     $this=$(this),
                origStr=$this.val().replace(/\D+/g,""),
                str=numberFormat(origStr);
        if(!(e.keyCode>34 &&  e.keyCode<41)){
            $this.val(str);
        }
        onchange_callback(str);
    });
}
$(document).ready(function(){
    var     in2 = document.getElementById("in2"),
            $deb3=$("#deb3");
    createFormatControl(in2,function(e){$deb3.text(e);});
});
Верстка:
<script type="text/javascript" src="jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="jquery.textchange.min.js"></script>
<p>
    <label>#2: </label>
    <input type="text" id="in2" autocomplete="off"/>
</p>
<p id="deb3"></p>

Скачать архив с исходниками