IMaskjs — простое маскирование в браузере
Нам нужна была работающая и удобная библиотека без зависимостей для маскирования ввода — и мы ее сделали. Через полгода с момента выпуска нулевой версии была выпущена версия 1.0 с многочисленными изменениями и улучшениями:
- ограничение ввода чисел (целые и дробные, с возможностью ограничения интервала)
- ограничение ввода дат (с поддержкой разных форматов, и также с возможностью ограничения интервала)
- выделение общего алгоритма маскирования позволяет делать крутые кастомные штуки просто
- API изменился минимально, но сильно расширился
- и другие изменения под катом
В качестве предисловия
Для меня это первый опыт активного участия в opensource, и я для себя сделал несколько выводов.
Всем не угодишь, да и не нужно. Но разнообразие не отменяет качество. Если продукт сделан грамотно, с умом, то пользователи найдутся. Кому-то нужен комбайн с миллионом взаимозаменяемых настроек под всевозможные платформы с интеграцией во все фреймворки. Мы же за минимализм с возможностью расширения.
Нужно больше примеров кода и демо. Страница проекта и документация полностью переработаны.
Нужны рабочие варианты из коробки. Добавлены новые маски и примеры использования.
На мобильных устройствах в настоящее время заставить работать курсор правильно невозможно. Буду рад, если докажете обратное. Все библиотеки, изменяющие ввод стоят перед выбором: сделать удобно для десктопа или чтобы работало на мобильных устройствах. Мы выбрали первое. Чтобы работало на мобильных устройствах необходимо учитывать не только платформы и многочисленные браузеры, но также широкий ассортимент виртуальных клавиатур со своими особенностями. Короче говоря, если хотите чтобы работало — не трогайте курсор при вводе. Серьезно, проверьте сами — так и делают (хотя может они тупо забили). В IMaskjs мы сделали достаточно сложное позиционирование курсора для удобства на десктопе с небольшим хаком под мобильные платформы. Хак известный и заключается в том, чтобы устанавливать курсор с небольшой задержкой после ввода — получилось не сильно лучше, но где-то заработало.
Что нового
Библиотека увеличилась в объеме в 2 раза в основном за счет нового функционала. Наиболее значимым дополнением стали маски для работы с числами и датами:
var numberMask = new IMask(inputElement, {
mask: Number,
min: -10000,
max: 10000,
thousandsSeparator: ' '
});
var dateMask = new IMask(inputElement, {
mask: Date,
min: new Date(2000, 0, 1),
max: new Date(2020, 0, 1),
placeholder: {lazy: false}
});
→ Демо тут
Фактически маска для ввода чисел — это надстройка над регулярками. А маска для ввода дат — надстройка над шаблонами. Т.к. дата состоит из условно независимых частей — дня, месяца и года, то для удобства переиспользования маски хотелось иметь возможность отдельной настройки независимых частей маски. Проблема была решена введением групп, которые являются частью основной маски, но также предоставляют возможность независимой обработки значений. Как-то так:
var groupsMask = new IMask(inputElement, {
mask: '19YY.MM.DD',
// описание групп
groups: {
// общее описание группы
YY: {
mask: '00',
// возможно использование валидатора
// validate: function (value, group) {}
},
// но можно создавать группы из интервала значений или перечислений
MM: new IMask.MaskedPattern.Group.Range([1, 12]),
DD: new IMask.MaskedPattern.Group.Range([1, 31])
}
});
В процессе реализации функционала групп стало понятно, что текущая модель обработки ввода неудобна, состояние размазывается где-то в аргументах методов и выходит из под контроля. В результате рефакторинга был выделен общий алгоритм последовательной подстановки и проверки значений. Фактически получилась пошаговая симуляция успешного ввода: посимвольно устанавливается следующее значение и если все проверки выполняются, шаг считается успешным, а иначе состояние откатывается. Такая модель позволила не предсказывать новое состояние, а оценивать его, что сильно упростило реализацию валидаторов.
В процессе рефакторинга также были выделены модель и представление. Модель предоставляет все возможности маскирования без UI. А представление «склеивает» dom-элемент и модель маски, обеспечивая реагирование на события и обновление элемента. Также довольно просто добавить собственные обработчики событий, например, для поддержки старых браузеров (из коробки поддерживаем IE11+).
Планы на будущее
Ближайшие планы — сделать возможность использовать несколько масок, меняющихся на лету, например, ввод телефона и email. Также возможно появятся плагины под любимые фреймворки.
Мы призадумались, а зачем мы вообще все это делаем, присмотрелись к cleave и text-mask — они ведь тоже хороши в принципе. Конечно каждый выберет свое, но нам наша маска нравится больше.
Несмотря на то, что библиотека неплохо работает в проде с несколькими сотнями тысяч активных пользователей, по-прежнему нет нормальных тестов и 0 issues на github))) Стыд и позор, нет слов. Исправляемся.