@@ -45,16 +45,21 @@ function Formatter(el, opts) {
// Merge opts with defaults
self .opts = utils .extend ({}, defaults, opts);
+ // 1 pattern is special case
+ if (typeof self .opts .pattern !== ' undefined' ) {
+ self .opts .patterns = self ._specFromSinglePattern (self .opts .pattern );
+ delete self .opts .pattern ;
+ }
+
// Make sure we have valid opts
- if (typeof self .opts .pattern === ' undefined' ) {
- throw new TypeError (' Must provide a pattern' );
+ if (typeof self .opts .patterns === ' undefined' ) {
+ throw new TypeError (' Must provide a pattern or array of patterns ' );
}
- // Get info about the given pattern
- var parsed = pattern .parse (self .opts .pattern );
- self .mLength = parsed .mLength ;
- self .chars = parsed .chars ;
- self .inpts = parsed .inpts ;
+ self .patternMatcher = patternMatcher (self .opts .patterns );
+
+ // Upate pattern with initial value
+ self ._updatePattern ();
// Init values
self .hldrs = {};
@@ -100,13 +105,11 @@ Formatter.addInptType = function (chr, reg) {
//
// @public
-// Handler called on all keyDown strokes. All keys trigger
-// this handler. Only process delete keys.
+// Apply the given pattern to the current input without moving caret.
//
Formatter .prototype .resetPattern = function (str ) {
// Update opts to hold new pattern
- str = str || this .opts .pattern ;
- this .opts .pattern = str;
+ this .opts .patterns = str ? this ._specFromSinglePattern (str) : this .opts .patterns ;
// Get current state
this .sel = inptSel .get (this .el );
@@ -118,14 +121,34 @@ Formatter.prototype.resetPattern = function (str) {
// Remove all formatted chars from val
this ._removeChars ();
+ this .patternMatcher = patternMatcher (this .opts .patterns );
+
// Update pattern
- var parsed = pattern . parse (str );
- this .mLength = parsed .mLength ;
- this .chars = parsed .chars ;
- this .inpts = parsed .inpts ;
+ var newPattern = this . patternMatcher . getPattern ( this . val );
+ this .mLength = newPattern .mLength ;
+ this .chars = newPattern .chars ;
+ this .inpts = newPattern .inpts ;
// Format on start
- this ._processKey (' ' , false );
+ this ._processKey (' ' , false , true );
+};
+
+//
+// @private
+// Determine correct format pattern based on input val
+//
+Formatter .prototype ._updatePattern = function () {
+ // Determine appropriate pattern
+ var newPattern = this .patternMatcher .getPattern (this .val );
+
+ // Only update the pattern if there is an appropriate pattern for the value.
+ // Otherwise, leave the current pattern (and likely delete the latest character.)
+ if (newPattern) {
+ // Get info about the given pattern
+ this .mLength = newPattern .mLength ;
+ this .chars = newPattern .chars ;
+ this .inpts = newPattern .inpts ;
+ }
};
//
@@ -202,7 +225,7 @@ Formatter.prototype._focus = function () {
// @private
// Using the provided key information, alter el value.
//
-Formatter .prototype ._processKey = function (chars , delKey ) {
+Formatter .prototype ._processKey = function (chars , delKey , ingoreCaret ) {
// Get current state
this .sel = inptSel .get (this .el );
this .val = this .el .value ;
@@ -238,7 +261,7 @@ Formatter.prototype._processKey = function (chars, delKey) {
}
// Format el.value (also handles updating caret position)
- this ._formatValue ();
+ this ._formatValue (ingoreCaret );
};
//
@@ -273,24 +296,30 @@ Formatter.prototype._nextPos = function () {
//
// @private
// Alter element value to display characters matching the provided
-// instance pattern. Also responsible for updatin
+// instance pattern. Also responsible for updating
//
-Formatter .prototype ._formatValue = function () {
+Formatter .prototype ._formatValue = function (ignoreCaret ) {
// Set caret pos
this .newPos = this .sel .end + this .delta ;
// Remove all formatted chars from val
this ._removeChars ();
- // Validate inpts
+
+ // Switch to first matching pattern based on val
+ this ._updatePattern ();
+
+ // Validate inputs
this ._validateInpts ();
// Add formatted characters
this ._addChars ();
- // Set vakye and adhere to maxLength
+ // Set value and adhere to maxLength
this .el .value = this .val .substr (0 , this .mLength );
// Set new caret position
- inptSel .set (this .el , this .newPos );
+ if ((typeof ignoreCaret) === ' undefined' || ignoreCaret === false ) {
+ inptSel .set (this .el , this .newPos );
+ }
};
//
@@ -419,6 +448,16 @@ Formatter.prototype._addChar = function (i) {
this .val = utils .addChars (this .val , chr, i);
};
+//
+// @private
+// Create a patternSpec for passing into patternMatcher that
+// has exactly one catch all pattern.
+//
+Formatter .prototype ._specFromSinglePattern = function (patternStr ) {
+ return [{ ' *' : patternStr }];
+};
+
+
// Define module
var pattern = {};
@@ -483,6 +522,64 @@ pattern.parse = function (pattern) {
info .mLength = i - (mCount * DELIM_SIZE );
return info;
};
+//
+// Parse a matcher string into a RegExp. Accepts valid regular
+// expressions and the catchall '*'.
+// @private
+//
+var parseMatcher = function (matcher ) {
+ if (matcher === ' *' ) {
+ return / . * / ;
+ }
+ return new RegExp (matcher);
+};
+
+//
+// Parse a pattern spec and return a function that returns a pattern
+// based on user input. The first matching pattern will be chosen.
+// Pattern spec format:
+// Array [
+// Object: { Matcher(RegExp String) : Pattern(Pattern String) },
+// ...
+// ]
+function patternMatcher (patternSpec ) {
+ var matchers = [],
+ patterns = [];
+
+ // Iterate over each pattern in order.
+ utils .forEach (patternSpec, function (patternMatcher ) {
+ // Process single property object to obtain pattern and matcher.
+ utils .forEach (patternMatcher, function (patternStr , matcherStr ) {
+ var parsedPattern = pattern .parse (patternStr),
+ regExpMatcher = parseMatcher (matcherStr);
+
+ matchers .push (regExpMatcher);
+ patterns .push (parsedPattern);
+
+ // Stop after one iteration.
+ return false ;
+ });
+ });
+
+ var getPattern = function (input ) {
+ var matchedIndex;
+ utils .forEach (matchers, function (matcher , index ) {
+ if (matcher .test (input)) {
+ matchedIndex = index;
+ return false ;
+ }
+ });
+
+ return matchedIndex === undefined ? null : patterns[matchedIndex];
+ };
+
+ return {
+ getPattern: getPattern,
+ patterns: patterns,
+ matchers: matchers
+ };
+}
+
// Define module
var inptSel = {};
@@ -649,6 +746,28 @@ utils.isSpecialKey = function (k) {
utils .isModifier = function (evt ) {
return evt .ctrlKey || evt .altKey || evt .metaKey ;
};
+
+//
+// Iterates over each property of object or array.
+//
+utils .forEach = function (collection , callback , thisArg ) {
+ if (collection .hasOwnProperty (" length" )) {
+ for (var index = 0 , len = collection .length ; index < len; index++ ) {
+ if (callback .call (thisArg, collection[index], index, collection) === false ) {
+ break ;
+ }
+ }
+ } else {
+ for (var key in collection) {
+ if (collection .hasOwnProperty (key)) {
+ if (callback .call (thisArg, collection[key], key, collection) === false ) {
+ break ;
+ }
+ }
+ }
+ }
+};
+
return Formatter;
});
0 comments on commit
8ce0d48