A library which can help you create custom input elements in the browser. Add mask and validation to input[text]!
MIT License
A library helping you create custom input elements in the browser. Add mask and validation to input[text]! Originally included in angular-datetime.
Via npm:
npm install custom-input
var {InputMask, TextParser} = require("custom-input");
There is also a pre-built dist which can be used in the browser:
<!-- export cusomInput into global -->
<script src="https://unpkg.com/[email protected]/dist/custom-input.js"></script>
var {InputMask, TextParser} = customInput;
The pre-built dist is compatible with IE 8, but you have to polyfill missing APIs by including @babel/polyfill.
A small example showing how it works: https://rawgit.com/eight04/custom-input/master/demo.html
This module exports following members:
TextParser
- a parser which can parse text into model value.InputMask
- bind a parser with an input
element and create a nice input mask.utils
- a set of utilities used by the library.new TextParser({
tokens: Array<Token>,
value: any,
copyValue: value => clonedValue
})
=> parser
Create a stateful parser which can convert a model value to a string and vise versa. The parser uses a series of Token
to construct a template. For example, the IP address: xxx.xxx.xxx.xxx
can be represented with 7 tokens, which are Number{1,3}, String ".", Number{1,3}, String ".", Number{1,3}, String ".", Number{1,3}. The parser will try to parse text along the tokens, extract the value from text and store the value in the model.
tokens
is a list of Token.value
is the initial model value.copyValue
is a function which can clone the model.parser.parse(text: String) => parser
Parse a string and store the value in the parser.
This method returns the parser itself.
parser.setValue(value, preserveEmpty? = false) => parser
Set a new model value and format text according to the new value.
If preserveEmpty
is false
, parser will the reset empty flag of all nodes.
This method returns the parser itself.
parser.getValue() => value
Get the model value.
parser.getText() => text: String
Get formatted text.
parser.isEmpty(text?: String) => Boolean
If text
is supplied, parse the text without saving data and check if nodes contains empty node.
If some nodes are set, return false
.
parser.isInit() => Boolean
If some nodes are empty, return false
.
Note: it is possible that
parser.isEmpty()
andparser.isInit()
both returnstrue
, which means all nodes are static.
parser.unset() => parser
Unset every node. Mark them as empty.
parser.getNodes(name?: String) => Array<Node>
Get a list of nodes. If name
is provided, return the nodes having the same name.
change
- Emit when the model value is changed.A token is an object that contains special information for parsing. Each token may represents a static string, a number, or a choice list.
{
type: "static",
value: String
}
Set type
to "static"
to create a static token. It represent a static string.
value
is the static string value.
Mutable tokens includes number
token and select
token. Some properties are shared with all types of mutable tokens:
{
name?: String,
placeholder: String,
prior?: Number,
extract: (modelValue) => nodeValue,
restore: (modelValue, nodeValue) => void,
add: (modelValue, increment) => void
}
name
property should be used with parser.getNodes()
. There is no need to set a name if you are not going to retrieve the node.
placeholder
is a string, which is displayed when the node is empty e.g. after calling parser.unset()
.
prior
controls which node should be evaluated first. If there are two nodes whose value has been changed in the same time (via parser.parse
), the node having higher prior will apply the change to the model first.
Usually, it doesn't matter which node is evaluated first because the model value stores node values independently. But if you want to create a date string parser, you may have to decide the order carefully since each node will affect each other (e.g. the month may change when the day is changed/overflowed).
extract
, restore
, and add
are three hooks. The parser will call them when it want to perform corresponded operation to the model value.
nodeValue
is always a number. For number
node, it is the node value. For select
node, it is the index starting from 1.
increment
is an integer, can be negative.
{
type: "number",
minLength?: Number,
maxLength?: Number,
min?: Number,
max?: Number
}
minLength
and maxLength
controls how the number should be represented. The formatter will zero-pad the value when the length is shorter than minLength
, and will trim the text when the length is longer than maxLength
.
min
and max
controls the bounding of the number. You may want to set min
to 0
so it won't become negative. It also affect the input mask. If the node value hits the limit, up/down arrow keys will be disabled.
{
type: "select",
select: Array<option: String>
}
select
is a list of string that the text should match one of them.
When converting text to model value, the parser will find the index of matched text, plus 1, then save it as node value (store it via the restore
hook).
InputMask is built with an <input>
element and a TextParser
. It handles most of the HTML stuff like listening to events, tracking selection range of the input element, etc.
After the mask is applied, users can only edit part of the text that is not defined as "static". Users can also press left/right arrow keys or tab to navigate between each mutable node. Use up/down arrow keys to increase/decrease node value. If it is a "select" node, it will act like a typeahead component. If the user tries to delete the node, it will be replaced by the placeholder.
new InputMask(element: Element, parser: TextParser, separators: String = "") => mask
element
is an object implementing Element interface.parser
is a parser object.separators
- apart from tab key, add other keys that can navigate through nodes.mask.digest(node: Node | void, text: String, fixError?: Boolean = false)
The mask will try to parse the text. If an error occurs, try fixing it and parse it again.
node
- can be null
If node
is null
, the mask will parse the text along with all nodes.
If node
is a node object, the mask will treat the text as the view value of the node.
text
is the text which should be parsed.
fixError
If fixError
is true
, the mask will try hardest to fix the error, even revert back the text to the previous state.
If fixError
is false
, it will fix fatal errors, but leave NUMBER_TOOSHORT
, LEADING_ZERO
, etc.
digest
- emit when an digest error occurs. It may fire multiple times during one digest.The Element interface wraps native input element and exposes some methods similar to jQuery.
Element.on(eventType: String, callback: (event) => void) => void
Wrap addEventListener
. InputMask
will listen to input
event for text update, you might want to proxy it for cross browser compatibility.
InputMask
uses following events:
Element.getSelection() => Range | void
Get the current selection from the input element. Return null
if the element is not focused/selected.
Range
has following shape:
{
start: Number,
end: Number
}
Element.setSelection(start: Number, end: Number) => void
Set selection on the input. You may need to check if the input is active or some browsers will try to focus the input element when the selection changed.
Element.val() => String
Element.val(text: String) => void
Get or set the value of the input element. Like jQuery.
A set of utilities.
utils.num2str(number, minLength, maxLength) => String
Convert a number to a string. Pad the text with zero and trim the text if needed.
0.4.0 (Jun 27, 2019)
Some changes to InputMask
:
Bump dependencies.
0.3.1 (Sep 17, 2017)
0.3.0 (Sep 17, 2017)
0.2.1 (Jul 24, 2017)
textParser
arg to token.add
and token.restore
.name
attribute to Node
.name
arg to TextParser.getNodes
.0.2.0 (Mar 9, 2017)
0.1.0 (Dec 19, 2016)