diff --git a/.gitignore b/.gitignore index 3260eff..d408882 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,10 @@ .idea/* dist/* +# vim undo files +*~ +# vim swap files +*.swp +acs.tmp +node_modules/ +npm-debug.log diff --git a/Cakefile b/Cakefile index d91b6b2..5965db2 100644 --- a/Cakefile +++ b/Cakefile @@ -18,8 +18,10 @@ minify = (js)-> process = uglify.uglify ast = process.ast_mangle(ast) ast = process.ast_squeeze(ast) - comment = uglify.parser.tokenizer(js)().comments_before[0].value; - '/*'+comment+'*/\n'+process.gen_code(ast) + #comment = uglify.parser.tokenizer(js)().comments_before[0].value; + #'/*'+comment+'*/\n'+process.gen_code(ast) + process.gen_code(ast) + replaceTokens = (js,tokens)-> js.replace( diff --git a/demo/index.html b/demo/index.html index 4beeaab..89e9fb7 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,3 +1,4 @@ + jQuery Mask Test @@ -5,9 +6,15 @@ - + @@ -43,9 +43,12 @@ - - + + + + + diff --git a/spec/lib/jasmine-species/jasmine-grammar.js b/spec/lib/jasmine-species/jasmine-grammar.js index 9f4f734..2645f11 100644 --- a/spec/lib/jasmine-species/jasmine-grammar.js +++ b/spec/lib/jasmine-species/jasmine-grammar.js @@ -84,13 +84,35 @@ jasmine.grammar.GWT = { return this._addStepToCurrentSpec('Then ' + desc, func); }, + /** + * Defines a "whilst" step as a runs block that marks the interesting event in a GWT chain + */ + whilst: function(desc, func) { + return this._addStepToCurrentSpec('Whilst ' + desc, func); + }, + + /** + * Defines a "hence" step as a runs block that marks the conclusion of a Given, Whilst, Hence construct + */ + hence: function(desc, func) { + return this._addStepToCurrentSpec('Hence ' + desc, func); + }, + +/** * Defines an "and" step as a runs block that is a continuation from a "then" statement */ and: function(desc, func) { return this._addStepToCurrentSpec('And ' + desc, func); }, +/** + * Defines an "likewise" step as a runs block that is a continuation from a "then" statement + */ + likewise: function(desc, func) { + return this._addStepToCurrentSpec('Likewise ' + desc, func); + }, + /** * Defines a "but" step as a runs block that is a continuation from a "then" statement */ @@ -230,4 +252,4 @@ jasmine.grammar.Meta = { */ jasmine.grammar.getEnv = function() { return jasmine.grammar._currentEnv = jasmine.grammar._currentEnv || jasmine.getEnv(); -}; \ No newline at end of file +}; diff --git a/spec/lib/jasmine/json2.js b/spec/lib/jasmine/json2.js new file mode 100644 index 0000000..ac58079 --- /dev/null +++ b/spec/lib/jasmine/json2.js @@ -0,0 +1,478 @@ +/* + http://www.JSON.org/json2.js + 2009-08-17 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. +*/ + +/*jslint evil: true */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + +"use strict"; + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); diff --git a/src/jquery.maskedinput.coffee b/src/jquery.maskedinput.coffee new file mode 100644 index 0000000..c6f2e1f --- /dev/null +++ b/src/jquery.maskedinput.coffee @@ -0,0 +1,301 @@ +### Masked Input plugin for jQuery +# +# based upon Masked Input plugin for jQuery by Josh Bush +# (http://digitalbush.com/projects/masked-input-plugin/) +### + +$ = jQuery + +pasteEventName = (if $.browser.msie then 'paste' else 'input') + '.mask' +iPhone = window.orientation? + +$.mask = + # Predefined character definitions + definitions: + '9': "[0-9]" + 'a': "[A-Za-z]" + '*': "[A-Za-z0-9]" + 'm': "[0-9/]" + 'd': "[0-9/]" + 'y': "[0-9]" + + dataName: "rawMaskFn" + autocomplete_predefined: + 'mmddyyyy': [ + { pattern: /^\//, replacement: " " } + { pattern: /^([1-9])\//, replacement: "0$1" } + { pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, replacement: " " } + { pattern: /^(\d\d.)\//, replacement: "$1 " } + { pattern: /^(\d\d.)((3[2-9])|([4-9]\d)|(0[0\/]))/, replacement: "$1 " } + { pattern: /^(\d\d.)(\d\/)./, replacement: "$1" + "0" + "$2" } + { pattern: /^(\d\d.\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, replacement: "$1" + "20" + "$2" } + { pattern: /^(\d\d.\d\d.)([3-8]\d)(?!\d)/, replacement: "$1" + "19" + "$2" } + ] + + + 'mmyyyy': [ + { pattern: /^\//, replacement: " " } + { pattern: /^(\d)\//, replacement: "0$1" } + { pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, replacement: " " } + { pattern: /^(\d\d.)\//, replacement: "$1 " } + { pattern: /^(\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, replacement: "$1" + "20" + "$2" } + { pattern: /^(\d\d.)([3-8]\d)(?!\d)/, replacement: "$1" + "19" + "$2" } + ] + +$.fn.extend + caret: (begin, end) -> + if this.length == 0 then return + if typeof begin == 'number' + end = if typeof end == 'number' then end else begin + return this.each -> + if this.setSelectionRange + this.setSelectionRange begin, end + else if this.createTextRange + range = this.createTextRange() + range.collapse true + range.moveEnd 'character', end + range.moveStart 'character', begin + range.select() + else + if this[0].setSelectionRange + begin = this[0].selectionStart + end = this[0].selectionEnd + else if document.selection and document.selection.createRange + range = document.selection.createRange() + begin = 0 - range.duplicate().moveStart 'character', -100000 + end = begin + range.text.length + return { begin: begin, end: end} + + unmask: -> return this.trigger "unmask" + + mask: (mask, settings) -> + if not mask and this.length > 0 + input = $ this[0] + return (input.data $.mask.dataName)() + + settings = $.extend { + placeholder: "_" + completed: null + autocomplete: [] + progressive_reveal: false + }, settings + + defs = $.mask.definitions + tests = [] + partialPosition = mask.length + firstNonMaskPos = null + len = mask.length + + $.each (mask.split ""), (i, c) -> + if c == '?' + len-- + partialPosition = i + else if defs[c] + tests.push (RegExp defs[c]) + firstNonMaskPos = tests.length - 1 if firstNonMaskPos == null + else + tests.push null + + (this.trigger "unmask").each -> + input = $ this + buffer = $.map (mask.split ""), (c, i) -> + if c != '?' + return if defs[c] then settings.placeholder else c + focusText = input.val() + + seekNext = (pos) -> + while ++pos <= len and not tests[pos] + null + pos + + seekPrev = (pos) -> + ivala = input.val().split "" + while --pos >= 0 and not tests[pos] + ivala[pos] = settings.placeholder + ivala[pos] = settings.placeholder + input.val(ivala.join "") + pos + + shiftL = (begin, end) -> + return null if begin < 0 + + j = seekNext end + + for i in [begin...len] + if tests[i] + if j < len and tests[i].test buffer[j] + buffer[i] = buffer[j] + buffer[j] = settings.placeholder + else + break + + j = seekNext j + + writeBuffer() + input.caret Math.max firstNonMaskPos, begin + + shiftR = (pos) -> + c = settings.placeholder + for i in [pos...len] + if tests[i] + j = seekNext i + t = buffer[i] + buffer[i] = c + if j < len and tests[j].test t + c = t + else + break + + keydownEvent = (e) -> + k = e.which + KEYDELETE = 46 + KEYBACKSPACE = 8 + KEYESCAPE = 27 + + + # backspace, delete, and escape get special treatment + if k == KEYBACKSPACE or k == KEYDELETE or (iPhone and k == 127) + {begin, end} = input.caret() + + if end == begin + + if (k == KEYBACKSPACE or k == KEYDELETE) and begin < input.val().length + resetBuffer() + return false + + begin = if k != KEYDELETE then seekPrev begin else end = seekNext begin - 1 + end = seekNext end if k == KEYDELETE + else + resetBuffer() + return false + + clearBuffer begin, end + shiftL begin, end - 1 + + false + else if k == KEYESCAPE + # escape + input.val focusText + input.caret 0, checkVal() + false + + keypressEvent = (e) -> + k = e.which + i = 0 + startLength = input.mask().length + + pos = input.caret() + + if e.ctrlKey or e.altKey or e.metaKey or k < 32 + true + else if k + if pos.end != pos.begin + clearBuffer pos.begin, pos.end + shiftL pos.begin, pos.end - 1 + + p = seekNext pos.begin - 1 + if p < len + c = String.fromCharCode k + if tests[p].test c + shiftR p + buffer[p] = c + writeBuffer() + next = seekNext p + input.caret next + + if settings.autocomplete.length > 0 + for i in [0...settings.autocomplete.length] + {pattern, replacement} = settings.autocomplete[i] + input.val input.val().replace pattern, replacement + clearBuffer 0, RegExp.lastMatch.length + input.caret checkVal true + + next += input.mask().length - startLength - 1 + if settings.completed and next >= len + settings.completed.call input + false + + resetBuffer = -> + input.val "" + input.caret 0, checkVal() + + clearBuffer = (start, end) -> + for i in [start...end] when i < len + buffer[i] = settings.placeholder if tests[i]? + + wbCount = 0 + + writeBuffer = -> + if settings.progressive_reveal + i = 0 + tmp_array = [] + ival = input.val() + + until not ival[i]? or ival[i] == buffer[i] == settings.placeholder + tmp_array.push ival[i++] + + while buffer[i] and buffer[i] != settings.placeholder + tmp_array.push buffer[i++] + + (input.val tmp_array.join "").val() + else + (input.val buffer.join "").val() + + checkVal = (allow) -> + test = input.val() + lastMatch = -1 + pos = 0 + + for i in [0...len] + if tests[i] + buffer[i] = settings.placeholder + while pos++ < test.length + c = test.charAt pos - 1 + if tests[pos - 1] and tests[pos - 1].test c + buffer[i] = c + lastMatch = i + break + if pos > test.length + break + else if buffer[i] == ( test.charAt pos ) and i != partialPosition + pos++ + lastMatch = i + + if not allow and lastMatch + 1 < partialPosition + input.val "" + clearBuffer 0, len + else if allow or lastMatch + 1 >= partialPosition + writeBuffer() + input.val input.val().substring 0, lastMatch + 1 if not allow + if partialPosition then i else firstNonMaskPos + + + input.data $.mask.dataName, -> + ($.map buffer, (c, i) -> + if tests[i] and c != settings.placeholder then c else null).join '' + + unless input.attr "readonly" + input.one "unmask", -> + input.unbind ".mask" + input.removeData $.mask.dataName + .bind "focus.mask", -> + focusText = input.val() + pos = checkVal() + writeBuffer() + moveCaret = -> + if pos == mask.length + input.caret 0, pos + else + input.caret pos + if $.browser.msie then moveCaret() else do -> setTimeout moveCaret, 0 + .bind( "blur.mask", -> + checkVal() + if input.val() != focusText + input.change() + ).bind( "keydown.mask", keydownEvent) + .bind( "keypress.mask", keypressEvent ) + .bind pasteEventName, -> + setTimeout (() -> + input.caret checkVal true), 0 + + checkVal() # perform initial check for existing values diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js index af67604..12ee34f 100644 --- a/src/jquery.maskedinput.js +++ b/src/jquery.maskedinput.js @@ -1,258 +1,394 @@ -/* - Masked Input plugin for jQuery - Copyright (c) 2007-@Year Josh Bush (digitalbush.com) - Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) - Version: @version -*/ -(function($) { - var pasteEventName = ($.browser.msie ? 'paste' : 'input') + ".mask"; - var iPhone = (window.orientation != undefined); - - $.mask = { - //Predefined character definitions - definitions: { - '9': "[0-9]", - 'a': "[A-Za-z]", - '*': "[A-Za-z0-9]" - }, - dataName:"rawMaskFn" - }; - - $.fn.extend({ - //Helper Function for Caret positioning - caret: function(begin, end) { - if (this.length == 0) return; - if (typeof begin == 'number') { - end = (typeof end == 'number') ? end : begin; - return this.each(function() { - if (this.setSelectionRange) { - this.setSelectionRange(begin, end); - } else if (this.createTextRange) { - var range = this.createTextRange(); - range.collapse(true); - range.moveEnd('character', end); - range.moveStart('character', begin); - range.select(); - } - }); - } else { - if (this[0].setSelectionRange) { - begin = this[0].selectionStart; - end = this[0].selectionEnd; - } else if (document.selection && document.selection.createRange) { - var range = document.selection.createRange(); - begin = 0 - range.duplicate().moveStart('character', -100000); - end = begin + range.text.length; - } - return { begin: begin, end: end }; - } - }, - unmask: function() { return this.trigger("unmask"); }, - mask: function(mask, settings) { - if (!mask && this.length > 0) { - var input = $(this[0]); - return input.data($.mask.dataName)(); - } - settings = $.extend({ - placeholder: "_", - completed: null - }, settings); - - var defs = $.mask.definitions; - var tests = []; - var partialPosition = mask.length; - var firstNonMaskPos = null; - var len = mask.length; - - $.each(mask.split(""), function(i, c) { - if (c == '?') { - len--; - partialPosition = i; - } else if (defs[c]) { - tests.push(new RegExp(defs[c])); - if(firstNonMaskPos==null) - firstNonMaskPos = tests.length - 1; - } else { - tests.push(null); - } - }); - - return this.trigger("unmask").each(function() { - var input = $(this); - var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c }); - var focusText = input.val(); - - function seekNext(pos) { - while (++pos <= len && !tests[pos]); - return pos; - }; - function seekPrev(pos) { - while (--pos >= 0 && !tests[pos]); - return pos; - }; - - function shiftL(begin,end) { - if(begin<0) - return; - for (var i = begin,j = seekNext(end); i < len; i++) { - if (tests[i]) { - if (j < len && tests[i].test(buffer[j])) { - buffer[i] = buffer[j]; - buffer[j] = settings.placeholder; - } else - break; - j = seekNext(j); - } - } - writeBuffer(); - input.caret(Math.max(firstNonMaskPos, begin)); - }; - - function shiftR(pos) { - for (var i = pos, c = settings.placeholder; i < len; i++) { - if (tests[i]) { - var j = seekNext(i); - var t = buffer[i]; - buffer[i] = c; - if (j < len && tests[j].test(t)) - c = t; - else - break; - } - } - }; - - function keydownEvent(e) { - var k=e.which; - - //backspace, delete, and escape get special treatment - if(k == 8 || k == 46 || (iPhone && k == 127)){ - var pos = input.caret(), - begin = pos.begin, - end = pos.end; - - if(end-begin==0){ - begin=k!=46?seekPrev(begin):(end=seekNext(begin-1)); - end=k==46?seekNext(end):end; - } - clearBuffer(begin, end); - shiftL(begin,end-1); - - return false; - } else if (k == 27) {//escape - input.val(focusText); - input.caret(0, checkVal()); - return false; - } - }; - - function keypressEvent(e) { - var k = e.which, - pos = input.caret(); - if (e.ctrlKey || e.altKey || e.metaKey || k<32) {//Ignore - return true; - } else if (k) { - if(pos.end-pos.begin!=0){ - clearBuffer(pos.begin, pos.end); - shiftL(pos.begin, pos.end-1); - } - - var p = seekNext(pos.begin - 1); - if (p < len) { - var c = String.fromCharCode(k); - if (tests[p].test(c)) { - shiftR(p); - buffer[p] = c; - writeBuffer(); - var next = seekNext(p); - input.caret(next); - if (settings.completed && next >= len) - settings.completed.call(input); - } - } - return false; - } - }; - - function clearBuffer(start, end) { - for (var i = start; i < end && i < len; i++) { - if (tests[i]) - buffer[i] = settings.placeholder; - } - }; - - function writeBuffer() { return input.val(buffer.join('')).val(); }; - - function checkVal(allow) { - //try to place characters where they belong - var test = input.val(); - var lastMatch = -1; - for (var i = 0, pos = 0; i < len; i++) { - if (tests[i]) { - buffer[i] = settings.placeholder; - while (pos++ < test.length) { - var c = test.charAt(pos - 1); - if (tests[i].test(c)) { - buffer[i] = c; - lastMatch = i; - break; - } - } - if (pos > test.length) - break; - } else if (buffer[i] == test.charAt(pos) && i!=partialPosition) { - pos++; - lastMatch = i; - } - } - if (!allow && lastMatch + 1 < partialPosition) { - input.val(""); - clearBuffer(0, len); - } else if (allow || lastMatch + 1 >= partialPosition) { - writeBuffer(); - if (!allow) input.val(input.val().substring(0, lastMatch + 1)); - } - return (partialPosition ? i : firstNonMaskPos); - }; - - input.data($.mask.dataName,function(){ - return $.map(buffer, function(c, i) { - return tests[i]&&c!=settings.placeholder ? c : null; - }).join(''); - }) - - if (!input.attr("readonly")) - input - .one("unmask", function() { - input - .unbind(".mask") - .removeData($.mask.dataName); - }) - .bind("focus.mask", function() { - focusText = input.val(); - var pos = checkVal(); - writeBuffer(); - var moveCaret=function(){ - if (pos == mask.length) - input.caret(0, pos); - else - input.caret(pos); - }; - ($.browser.msie ? moveCaret:function(){setTimeout(moveCaret,0)})(); - }) - .bind("blur.mask", function() { - checkVal(); - if (input.val() != focusText) - input.change(); - }) - .bind("keydown.mask", keydownEvent) - .bind("keypress.mask", keypressEvent) - .bind(pasteEventName, function() { - setTimeout(function() { input.caret(checkVal(true)); }, 0); - }); - - checkVal(); //Perform initial check for existing values - }); - } - }); -})(jQuery); +(function() { + /* Masked Input plugin for jQuery + # + # based upon Masked Input plugin for jQuery by Josh Bush + # (http://digitalbush.com/projects/masked-input-plugin/) + */ + var $, iPhone, pasteEventName; + $ = jQuery; + pasteEventName = ($.browser.msie ? 'paste' : 'input') + '.mask'; + iPhone = window.orientation != null; + $.mask = { + definitions: { + '9': "[0-9]", + 'a': "[A-Za-z]", + '*': "[A-Za-z0-9]", + 'm': "[0-9/]", + 'd': "[0-9/]", + 'y': "[0-9]" + }, + dataName: "rawMaskFn", + autocomplete_predefined: { + 'mmddyyyy': [ + { + pattern: /^\//, + replacement: " " + }, { + pattern: /^([1-9])\//, + replacement: "0$1" + }, { + pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, + replacement: " " + }, { + pattern: /^(\d\d.)\//, + replacement: "$1 " + }, { + pattern: /^(\d\d.)((3[2-9])|([4-9]\d)|(0[0\/]))/, + replacement: "$1 " + }, { + pattern: /^(\d\d.)(\d\/)./, + replacement: "$1" + "0" + "$2" + }, { + pattern: /^(\d\d.\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, + replacement: "$1" + "20" + "$2" + }, { + pattern: /^(\d\d.\d\d.)([3-8]\d)(?!\d)/, + replacement: "$1" + "19" + "$2" + } + ], + 'mmyyyy': [ + { + pattern: /^\//, + replacement: " " + }, { + pattern: /^(\d)\//, + replacement: "0$1" + }, { + pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, + replacement: " " + }, { + pattern: /^(\d\d.)\//, + replacement: "$1 " + }, { + pattern: /^(\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, + replacement: "$1" + "20" + "$2" + }, { + pattern: /^(\d\d.)([3-8]\d)(?!\d)/, + replacement: "$1" + "19" + "$2" + } + ] + } + }; + $.fn.extend({ + caret: function(begin, end) { + var range; + if (this.length === 0) { + return; + } + if (typeof begin === 'number') { + end = typeof end === 'number' ? end : begin; + return this.each(function() { + var range; + if (this.setSelectionRange) { + return this.setSelectionRange(begin, end); + } else if (this.createTextRange) { + range = this.createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', begin); + return range.select(); + } + }); + } else { + if (this[0].setSelectionRange) { + begin = this[0].selectionStart; + end = this[0].selectionEnd; + } else if (document.selection && document.selection.createRange) { + range = document.selection.createRange(); + begin = 0 - range.duplicate().moveStart('character', -100000); + end = begin + range.text.length; + } + return { + begin: begin, + end: end + }; + } + }, + unmask: function() { + return this.trigger("unmask"); + }, + mask: function(mask, settings) { + var defs, firstNonMaskPos, input, len, partialPosition, tests; + if (!mask && this.length > 0) { + input = $(this[0]); + return (input.data($.mask.dataName))(); + } + settings = $.extend({ + placeholder: "_", + completed: null, + autocomplete: [], + progressive_reveal: false + }, settings); + defs = $.mask.definitions; + tests = []; + partialPosition = mask.length; + firstNonMaskPos = null; + len = mask.length; + $.each(mask.split(""), function(i, c) { + if (c === '?') { + len--; + return partialPosition = i; + } else if (defs[c]) { + tests.push(RegExp(defs[c])); + if (firstNonMaskPos === null) { + return firstNonMaskPos = tests.length - 1; + } + } else { + return tests.push(null); + } + }); + return (this.trigger("unmask")).each(function() { + var buffer, checkVal, clearBuffer, focusText, keydownEvent, keypressEvent, resetBuffer, seekNext, seekPrev, shiftL, shiftR, wbCount, writeBuffer; + input = $(this); + buffer = $.map(mask.split(""), function(c, i) { + if (c !== '?') { + if (defs[c]) { + return settings.placeholder; + } else { + return c; + } + } + }); + focusText = input.val(); + seekNext = function(pos) { + while (++pos <= len && !tests[pos]) { + null; + } + return pos; + }; + seekPrev = function(pos) { + var ivala; + ivala = input.val().split(""); + while (--pos >= 0 && !tests[pos]) { + ivala[pos] = settings.placeholder; + } + ivala[pos] = settings.placeholder; + input.val(ivala.join("")); + return pos; + }; + shiftL = function(begin, end) { + var i, j; + if (begin < 0) { + return null; + } + j = seekNext(end); + for (i = begin; begin <= len ? i < len : i > len; begin <= len ? i++ : i--) { + if (tests[i]) { + if (j < len && tests[i].test(buffer[j])) { + buffer[i] = buffer[j]; + buffer[j] = settings.placeholder; + } else { + break; + } + j = seekNext(j); + } + } + writeBuffer(); + return input.caret(Math.max(firstNonMaskPos, begin)); + }; + shiftR = function(pos) { + var c, i, j, t, _results; + c = settings.placeholder; + _results = []; + for (i = pos; pos <= len ? i < len : i > len; pos <= len ? i++ : i--) { + if (tests[i]) { + j = seekNext(i); + t = buffer[i]; + buffer[i] = c; + if (j < len && tests[j].test(t)) { + c = t; + } else { + break; + } + } + } + return _results; + }; + keydownEvent = function(e) { + var KEYBACKSPACE, KEYDELETE, KEYESCAPE, begin, end, k, _ref; + k = e.which; + KEYDELETE = 46; + KEYBACKSPACE = 8; + KEYESCAPE = 27; + if (k === KEYBACKSPACE || k === KEYDELETE || (iPhone && k === 127)) { + _ref = input.caret(), begin = _ref.begin, end = _ref.end; + if (end === begin) { + if ((k === KEYBACKSPACE || k === KEYDELETE) && begin < input.val().length) { + resetBuffer(); + return false; + } + begin = k !== KEYDELETE ? seekPrev(begin) : end = seekNext(begin - 1); + if (k === KEYDELETE) { + end = seekNext(end); + } + } else { + resetBuffer(); + return false; + } + clearBuffer(begin, end); + shiftL(begin, end - 1); + return false; + } else if (k === KEYESCAPE) { + input.val(focusText); + input.caret(0, checkVal()); + return false; + } + }; + keypressEvent = function(e) { + var c, i, k, next, p, pattern, pos, replacement, startLength, _ref, _ref2; + k = e.which; + i = 0; + startLength = input.mask().length; + pos = input.caret(); + if (e.ctrlKey || e.altKey || e.metaKey || k < 32) { + return true; + } else if (k) { + if (pos.end !== pos.begin) { + clearBuffer(pos.begin, pos.end); + shiftL(pos.begin, pos.end - 1); + } + p = seekNext(pos.begin - 1); + if (p < len) { + c = String.fromCharCode(k); + if (tests[p].test(c)) { + shiftR(p); + buffer[p] = c; + writeBuffer(); + next = seekNext(p); + input.caret(next); + if (settings.autocomplete.length > 0) { + for (i = 0, _ref = settings.autocomplete.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { + _ref2 = settings.autocomplete[i], pattern = _ref2.pattern, replacement = _ref2.replacement; + input.val(input.val().replace(pattern, replacement)); + clearBuffer(0, RegExp.lastMatch.length); + input.caret(checkVal(true)); + } + } + next += input.mask().length - startLength - 1; + if (settings.completed && next >= len) { + settings.completed.call(input); + } + } + } + return false; + } + }; + resetBuffer = function() { + input.val(""); + return input.caret(0, checkVal()); + }; + clearBuffer = function(start, end) { + var i, _results; + _results = []; + for (i = start; start <= end ? i < end : i > end; start <= end ? i++ : i--) { + if (i < len) { + _results.push(tests[i] != null ? buffer[i] = settings.placeholder : void 0); + } + } + return _results; + }; + wbCount = 0; + writeBuffer = function() { + var i, ival, tmp_array, _ref; + if (settings.progressive_reveal) { + i = 0; + tmp_array = []; + ival = input.val(); + while (!(!(ival[i] != null) || (ival[i] === (_ref = buffer[i]) && _ref === settings.placeholder))) { + tmp_array.push(ival[i++]); + } + while (buffer[i] && buffer[i] !== settings.placeholder) { + tmp_array.push(buffer[i++]); + } + return (input.val(tmp_array.join(""))).val(); + } else { + return (input.val(buffer.join(""))).val(); + } + }; + checkVal = function(allow) { + var c, i, lastMatch, pos, test; + test = input.val(); + lastMatch = -1; + pos = 0; + for (i = 0; 0 <= len ? i < len : i > len; 0 <= len ? i++ : i--) { + if (tests[i]) { + buffer[i] = settings.placeholder; + while (pos++ < test.length) { + c = test.charAt(pos - 1); + if (tests[pos - 1] && tests[pos - 1].test(c)) { + buffer[i] = c; + lastMatch = i; + break; + } + } + if (pos > test.length) { + break; + } + } else if (buffer[i] === (test.charAt(pos)) && i !== partialPosition) { + pos++; + lastMatch = i; + } + } + if (!allow && lastMatch + 1 < partialPosition) { + input.val(""); + clearBuffer(0, len); + } else if (allow || lastMatch + 1 >= partialPosition) { + writeBuffer(); + if (!allow) { + input.val(input.val().substring(0, lastMatch + 1)); + } + } + if (partialPosition) { + return i; + } else { + return firstNonMaskPos; + } + }; + input.data($.mask.dataName, function() { + return ($.map(buffer, function(c, i) { + if (tests[i] && c !== settings.placeholder) { + return c; + } else { + return null; + } + })).join(''); + }); + if (!input.attr("readonly")) { + input.one("unmask", function() { + input.unbind(".mask"); + return input.removeData($.mask.dataName); + }).bind("focus.mask", function() { + var moveCaret, pos; + focusText = input.val(); + pos = checkVal(); + writeBuffer(); + moveCaret = function() { + if (pos === mask.length) { + return input.caret(0, pos); + } else { + return input.caret(pos); + } + }; + if ($.browser.msie) { + return moveCaret(); + } else { + return (function() { + return setTimeout(moveCaret, 0); + })(); + } + }).bind("blur.mask", function() { + checkVal(); + if (input.val() !== focusText) { + return input.change(); + } + }).bind("keydown.mask", keydownEvent).bind("keypress.mask", keypressEvent).bind(pasteEventName, function() { + return setTimeout((function() { + return input.caret(checkVal(true)); + }), 0); + }); + } + return checkVal(); + }); + } + }); +}).call(this); diff --git a/src/jquery.maskedinput.mod.js b/src/jquery.maskedinput.mod.js new file mode 100644 index 0000000..1bc094b --- /dev/null +++ b/src/jquery.maskedinput.mod.js @@ -0,0 +1,372 @@ +(function() { + var $, iPhone, pasteEventName; + $ = jQuery; + pasteEventName = ($.browser.msie ? 'paste' : 'input') + '.mask'; + iPhone = window.orientation != null; + $.mask = { + definitions: { + '9': "[0-9]", + 'a': "[A-Za-z]", + '*': "[A-Za-z0-9]", + 'm': "[0-9/]", + 'd': "[0-9/]", + 'y': "[0-9]" + }, + dataName: "rawMaskFn", + autocomplete_predefined: { + 'mmddyyyy': [ + { + pattern: /^\//, + replacement: " " + }, { + pattern: /^([1-9])\//, + replacement: "0$1" + }, { + pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, + replacement: " " + }, { + pattern: /^(\d\d.)\//, + replacement: "$1 " + }, { + pattern: /^(\d\d.)((3[2-9])|([4-9]\d)|(0[0\/]))/, + replacement: "$1 " + }, { + pattern: /^(\d\d.)(\d\/)./, + replacement: "$1" + "0" + "$2" + }, { + pattern: /^(\d\d.\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, + replacement: "$1" + "20" + "$2" + }, { + pattern: /^(\d\d.\d\d.)([3-8]\d)(?!\d)/, + replacement: "$1" + "19" + "$2" + } + ], + 'mmyyyy': [ + { + pattern: /^\//, + replacement: " " + }, { + pattern: /^(\d)\//, + replacement: "0$1" + }, { + pattern: /^((1[3-9])|([2-9]\d)|(0[0\/]))/, + replacement: " " + }, { + pattern: /^(\d\d.)(1[0-8]|0\d|2[1-9])(?!\d)/, + replacement: "$1" + "20" + "$2" + }, { + pattern: /^(\d\d.)([3-8]\d)(?!\d)/, + replacement: "$1" + "19" + "$2" + } + ] + } + }; + $.fn.extend({ + caret: function(begin, end) { + var range; + if (this.length === 0) { + return; + } + if (typeof begin === 'number') { + end = typeof end === 'number' ? end : begin; + return this.each(function() { + var range; + if (this.setSelectionRange) { + return this.setSelectionRange(begin, end); + } else if (this.createTextRange) { + range = this.createTextRange; + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', begin); + return range.select; + } + }); + } else { + if (this[0].setSelectionRange) { + begin = this[0].selectionStart; + end = this[0].selectionEnd; + } else if (document.selection && document.selection.createRange) { + range = document.selection.createRange; + begin = 0 - range.duplicate().moveStart('character', -100000); + end = begin + range.text.length; + } + return { + begin: begin, + end: end + }; + } + }, + unmask: function() { + return this.trigger("unmask"); + }, + mask: function(mask, settings) { + var defs, firstNonMaskPos, input, len, partialPosition, tests; + if (!mask && this.length > 0) { + input = $(this[0]); + return (input.data($.mask.dataName))(); + } + settings = $.extend({ + placeholder: "_", + completed: null, + autocomplete: [], + progessive_reveal: false + }, settings); + defs = $.mask.definitions; + tests = []; + partialPosition = mask.length; + firstNonMaskPos = null; + len = mask.length; + $.each(mask.split(""), function(i, c) { + if (c === '?') { + len--; + return partialPosition = i; + } else if (defs[c]) { + tests.push(RegExp(defs[c])); + if (firstNonMaskPos === null) { + return firstNonMaskPos = tests.length - 1; + } + } else { + return tests.push(null); + } + }); + return (this.trigger("unmask")).each(function() { + var buffer, checkVal, clearBuffer, focusText, keydownEvent, keypressEvent, seekNext, seekPrev, shiftL, shiftR, wbCount, writeBuffer; + input = $(this); + buffer = $.map(mask.split(""), function(c, i) { + if (c !== '?') { + if (defs[c]) { + return settings.placeholder; + } else { + return c; + } + } + }); + focusText = input.val(); + seekNext = function(pos) { + while (++pos <= len && !tests[pos]) { + null; + } + return pos; + }; + seekPrev = function(pos) { + var ivala; + ivala = input.val().split(""); + while (--pos >= 0 && !tests[pos]) { + ivala[pos] = settings.placeholder; + } + ivala[pos] = settings.placeholder; + input.val(ivala.join("")); + return pos; + }; + shiftL = function(begin, end) { + var i, j; + if (begin < 0) { + return null; + } + j = seekNext(end); + for (i = begin; begin <= len ? i < len : i > len; begin <= len ? i++ : i--) { + if (tests[i]) { + if (j < len && tests[i].test(buffer[j])) { + buffer[i] = buffer[j]; + buffer[j] = settings.placeholder; + } else { + break; + } + j = seekNext(j); + } + } + writeBuffer(); + return input.caret(Math.max(firstNonMaskPos, begin)); + }; + shiftR = function(pos) { + var c, i, j, t, _results; + c = settings.placeholder; + _results = []; + for (i = pos; pos <= len ? i < len : i > len; pos <= len ? i++ : i--) { + if (tests[i]) { + j = seekNext(i); + t = buffer[i]; + buffer[i] = c; + if (j < len && tests[j].test(t)) { + c = t; + } else { + break; + } + } + } + return _results; + }; + keydownEvent = function(e) { + var begin, end, k, _ref; + k = e.which; + if (k === 8 || k === 46 || (iPhone && k === 127)) { + _ref = input.caret(), begin = _ref.begin, end = _ref.end; + if (end === begin) { + begin = k !== 46 ? seekPrev(begin) : end = seekNext(begin - 1); + if (k === 46) { + end = seekNext(end); + } + } + clearBuffer(begin, end); + shiftL(begin, end - 1); + return false; + } else if (k === 27) { + input.val(focusText); + input.caret(0, checkVal()); + return false; + } + }; + keypressEvent = function(e) { + var c, i, k, next, p, pattern, pos, replacement, startLength, _ref, _ref2; + k = e.which; + i = 0; + startLength = input.mask().length; + pos = input.caret(); + if (e.ctrlKey || e.altKey || e.metaKey || k < 32) { + return true; + } else if (k) { + if (pos.end !== pos.begin) { + clearBuffer(pos.begin, pos.end); + shiftL(pos.begin, pos.end - 1); + } + p = seekNext(pos.begin - 1); + if (p < len) { + c = String.fromCharCode(k); + if (tests[p].test(c)) { + shiftR(p); + buffer[p] = c; + writeBuffer(); + next = seekNext(p); + input.caret(next); + if (settings.autocomplete.length > 0) { + for (i = 0, _ref = settings.autocomplete.length; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { + _ref2 = settings.autocomplete[i], pattern = _ref2.pattern, replacement = _ref2.replacement; + input.val(input.val().replace(pattern, replacement)); + clearBuffer(0, RegExp.lastMatch.length); + input.caret(checkVal(true)); + } + } + next += input.mask().length - startLength - 1; + if (settings.completed && next >= len) { + settings.completed.call(input); + } + } + } + return false; + } + }; + clearBuffer = function(start, end) { + var i, _results; + _results = []; + for (i = start; start <= end ? i < end : i > end; start <= end ? i++ : i--) { + if (i < len) { + _results.push(tests[i] != null ? buffer[i] = settings.placeholder : void 0); + } + } + return _results; + }; + wbCount = 0; + writeBuffer = function() { + var i, ival, tmp_array, _ref; + if (settings.progressive_reveal) { + i = 0; + tmp_array = []; + ival = input.val(); + while (!(!(ival[i] != null) || (ival[i] === (_ref = buffer[i]) && _ref === settings.placeholder))) { + tmp_array.push(ival[i++]); + } + while (buffer[i] && buffer[i] !== settings.placeholder) { + tmp_array.push(buffer[i++]); + } + return (input.val(tmp_array.join(""))).val(); + } else { + return (input.val(buffer.join(""))).val(); + } + }; + checkVal = function(allow) { + var c, i, lastMatch, pos, test; + test = input.val(); + lastMatch = -1; + pos = 0; + for (i = 0; 0 <= len ? i < len : i > len; 0 <= len ? i++ : i--) { + if (tests[i]) { + buffer[i] = settings.placeholder; + while (pos++ < test.length) { + c = test.charAt(pos - 1); + if (tests[pos - 1] && tests[pos - 1].test(c)) { + buffer[i] = c; + lastMatch = i; + break; + } + } + if (pos > test.length) { + break; + } + } else if (buffer[i] === test.charAt(pos && i !== partialPosition)) { + pos++; + lastMatch = i; + } + } + if (!allow && lastMatch + 1 < partialPosition) { + input.val(""); + clearBuffer(0, len); + } else if (allow || lastMatch + 1 >= partialPosition) { + writeBuffer(); + if (!allow) { + input.val(input.val().substring(0, lastMatch + 1)); + } + } + if (partialPosition) { + return i; + } else { + return firstNonMaskPos; + } + }; + input.data($.mask.dataName, function() { + return ($.map(buffer, function(c, i) { + if (tests[i] && c !== settings.placeholder) { + return c; + } else { + return null; + } + })).join(''); + }); + if (!input.attr("readonly")) { + input.one("unmask", function() { + input.unbind(".mask"); + return input.removeData($.mask.dataName); + }).bind("focus.mask", function() { + var moveCaret, pos; + focusText = input.val(); + pos = checkVal(); + writeBuffer(); + moveCaret = function() { + if (pos === mask.length) { + return input.caret(0, pos); + } else { + return input.caret(pos); + } + }; + if ($.browser.msie) { + return moveCaret; + } else { + return (function() { + return setTimeout(moveCaret, 0); + })(); + } + }).bind("blur.mask", function() { + checkVal(); + if (input.val() !== focusText) { + return input.change(); + } + }).bind("keydown.mask", keydownEvent).bind("keypress.mask", keypressEvent).bind(pasteEventName, function() { + return setTimeout((function() { + return input.caret(checkVal(true)); + }), 0); + }); + } + return checkVal(); + }); + } + }); +}).call(this);