From 0983617a3ab4f934c42f398ceb5f70b3e93f4d7f Mon Sep 17 00:00:00 2001
From: scottrippey
Date: Tue, 18 Jan 2011 14:37:00 -0800
Subject: [PATCH 1/5] Added code for custom patterns and custom placeholders.
---
src/jquery.maskedinput.js | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js
index 54cf2e4..753bd65 100644
--- a/src/jquery.maskedinput.js
+++ b/src/jquery.maskedinput.js
@@ -1,4 +1,4 @@
-/*
+/*
Masked Input plugin for jQuery
Copyright (c) 2007-2010 Josh Bush (digitalbush.com)
Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
@@ -72,7 +72,7 @@
len--;
partialPosition = i;
} else if (defs[c]) {
- tests.push(new RegExp(defs[c]));
+ tests.push((defs[c].test) ? defs[c] : new RegExp(defs[c])); // (See if the def already has a test function defined)
if(firstNonMaskPos==null)
firstNonMaskPos = tests.length - 1;
} else {
@@ -82,7 +82,7 @@
return this.each(function() {
var input = $(this);
- var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c });
+ var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return (defs[c] ? (defs[c].placeholder || settings.placeholder) : c); });
var ignore = false; //Variable for ignoring control keys
var focusText = input.val();
@@ -97,7 +97,7 @@
while (!tests[pos] && --pos >= 0);
for (var i = pos; i < len; i++) {
if (tests[i]) {
- buffer[i] = settings.placeholder;
+ buffer[i] = tests[i].placeholder || settings.placeholder;
var j = seekNext(i);
if (j < len && tests[i].test(buffer[j])) {
buffer[i] = buffer[j];
@@ -110,11 +110,11 @@
};
function shiftR(pos) {
- for (var i = pos, c = settings.placeholder; i < len; i++) {
+ for (var i = pos, c = null; i < len; i++) {
if (tests[i]) {
var j = seekNext(i);
var t = buffer[i];
- buffer[i] = c;
+ buffer[i] = c || tests[i].placeholder || settings.placeholder;
if (j < len && tests[j].test(t))
c = t;
else
@@ -176,7 +176,7 @@
function clearBuffer(start, end) {
for (var i = start; i < end && i < len; i++) {
if (tests[i])
- buffer[i] = settings.placeholder;
+ buffer[i] = tests[i].placeholder || settings.placeholder;
}
};
@@ -188,7 +188,7 @@
var lastMatch = -1;
for (var i = 0, pos = 0; i < len; i++) {
if (tests[i]) {
- buffer[i] = settings.placeholder;
+ buffer[i] = tests[i].placeholder || settings.placeholder;
while (pos++ < test.length) {
var c = test.charAt(pos - 1);
if (tests[i].test(c)) {
From 80e122cc182025bf7772a3b12bc09ef7e18fd2a3 Mon Sep 17 00:00:00 2001
From: scottrippey
Date: Wed, 19 Jan 2011 23:50:07 -0800
Subject: [PATCH 2/5] Manually merged "focus fix" from trunk
---
src/jquery.maskedinput.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js
index 753bd65..ab22f97 100644
--- a/src/jquery.maskedinput.js
+++ b/src/jquery.maskedinput.js
@@ -25,7 +25,6 @@
end = (typeof end == 'number') ? end : begin;
return this.each(function() {
if (this.setSelectionRange) {
- this.focus();
this.setSelectionRange(begin, end);
} else if (this.createTextRange) {
var range = this.createTextRange();
@@ -226,12 +225,13 @@
focusText = input.val();
var pos = checkVal();
writeBuffer();
- setTimeout(function() {
+ var moveCaret = function() {
if (pos == mask.length)
input.caret(0, pos);
else
input.caret(pos);
- }, 0);
+ };
+ $.browser.msie ? moveCaret() : setTimeout(moveCaret,0);
})
.bind("blur.mask", function() {
checkVal();
From fa908d1e79a2733bb4e113bb3256dfa1c13fa66a Mon Sep 17 00:00:00 2001
From: scottrippey
Date: Wed, 19 Jan 2011 23:51:19 -0800
Subject: [PATCH 3/5] Added working "dollar field" code with a customized,
heavily refactored "maskedinput"
---
src/jquery.maskedinput-custom.js | 325 +++++++++++++++++++++++++++++++
src/toDollarField.js | 141 ++++++++++++++
2 files changed, 466 insertions(+)
create mode 100644 src/jquery.maskedinput-custom.js
create mode 100644 src/toDollarField.js
diff --git a/src/jquery.maskedinput-custom.js b/src/jquery.maskedinput-custom.js
new file mode 100644
index 0000000..7b9f5c1
--- /dev/null
+++ b/src/jquery.maskedinput-custom.js
@@ -0,0 +1,325 @@
+/*
+ Masked Input plugin for jQuery
+ Copyright (c) 2007-2010 Josh Bush (digitalbush.com)
+ Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license)
+ Version: 1.2.3
+*/
+(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]"
+ },
+ createBuffer: function (input, mask, settings) {
+ ///
+ /// This method creates a "buffer" object that handles
+ /// all masking logic.
+ /// The "buffer" object has 4 public methods:
+ /// getText() // Returns the un-masked text
+ /// insert(c) // Inserts a character
+ /// remove(d) // Removes a character in the specified direction
+ /// checkVal() // Checks and formats the current value
+ ///
+
+ // Parse the mask, and create the tests:
+ var defs = $.mask.definitions;
+ var tests = [];
+ var partialPosition = null;
+ var firstNonMaskPos = null;
+ var lastNonMaskPos = null;
+
+ $.each(mask.split(""), function (i, c) {
+ if (c == '?') {
+ partialPosition = i;
+ } else if (defs[c]) {
+ tests.push(new RegExp(defs[c]));
+ if (firstNonMaskPos == null)
+ firstNonMaskPos = tests.length - 1;
+ lastNonMaskPos = tests.length - 1;
+ } else {
+ tests.push(null);
+ }
+ });
+ if (partialPosition == null) {
+ partialPosition = lastNonMaskPos;
+ }
+
+ var buffer = $.map(mask.split(""), function (c, i) { if (c != '?') return (defs[c] ? (defs[c].placeholder || settings.placeholder) : c); });
+
+
+ // Private functions:
+ function seekNext(pos) {
+ while (++pos <= tests.length && !tests[pos]);
+ return pos;
+ };
+
+ function shiftL(pos) {
+ for (var i = pos; i < tests.length; i++) {
+ if (tests[i]) {
+ var j = seekNext(i);
+ buffer[i] = tests[i].placeholder || settings.placeholder;
+ if (j < tests.length && tests[i].test(buffer[j])) {
+ buffer[i] = buffer[j];
+ } else
+ break;
+ }
+ }
+ };
+
+ function shiftR(pos) {
+ for (var i = pos, c = null; i < tests.length; i++) {
+ if (tests[i]) {
+ var j = seekNext(i);
+ var t = buffer[i];
+ buffer[i] = c || tests[i].placeholder || settings.placeholder;
+ if (j < tests.length && tests[j].test(t))
+ c = t;
+ else
+ break;
+ }
+ }
+ };
+
+
+ function clearBuffer(start, end) {
+ for (var i = start; i < end && i < tests.length; i++) {
+ if (tests[i])
+ buffer[i] = tests[i].placeholder || settings.placeholder;
+ }
+ };
+
+ function writeBuffer() { input.val(buffer.join('')); };
+
+ buffer.getText = function () {
+ return $.map(buffer, function (c, i) {
+ return tests[i] ? c : null;
+ }).join('');
+ };
+ buffer.insert = function (c) {
+ var pos = input.caret();
+ //delete selection before proceeding
+ if (pos.begin != pos.end) {
+ clearBuffer(pos.begin, pos.end);
+ }
+ var p = seekNext(pos.begin - 1);
+ if (p < tests.length) {
+ if (tests[p].test(c)) {
+ shiftR(p);
+ buffer[p] = c;
+ var next = seekNext(p);
+ writeBuffer();
+ input.caret(next);
+
+ if (settings.completed && next >= tests.length)
+ settings.completed.call(input);
+ }
+ }
+ };
+ buffer.remove = function (d) {
+ // From KeyDown:
+ var pos = input.caret();
+ var npos;
+ //delete selection before proceeding
+ if (pos.begin != pos.end) {
+ clearBuffer(pos.begin, pos.end);
+ npos = seekNext(pos.begin - 1);
+ }
+ else { // Delete the current character:
+ var p = pos.begin;
+ if (d == -1) p--; // "backspace"
+ // Find the closest character to delete:
+ while (!tests[p] && 0 <= p && p < tests.length) p += d;
+ if (tests[p]) {
+ shiftL(p);
+ npos = p;
+ } else {
+ npos = pos.begin;
+ }
+ }
+ writeBuffer();
+ input.caret(npos);
+ };
+ buffer.checkVal = function (allowIncomplete) {
+ //try to place characters where they belong
+ var pos = input.caret();
+ var test = input.val();
+ var lastMatch = -1;
+ for (var i = 0, p = 0; i < tests.length; i++) {
+ if (tests[i]) {
+ buffer[i] = tests[i].placeholder || settings.placeholder;
+ while (p++ < test.length) {
+ var c = test.charAt(p - 1);
+ if (tests[i].test(c)) {
+ buffer[i] = c;
+ lastMatch = i;
+ break;
+ }
+ }
+ if (p > test.length)
+ break;
+ } else if (buffer[i] == test.charAt(p) && i != partialPosition) {
+ p++;
+ lastMatch = i;
+ }
+ }
+ if (!allowIncomplete && lastMatch + 1 < partialPosition) {
+ input.val("");
+ clearBuffer(0, buffer.length);
+ } else if (allowIncomplete || lastMatch + 1 >= partialPosition) {
+ writeBuffer();
+ if (!allowIncomplete) input.val(input.val().substring(0, lastMatch + 1));
+ }
+
+ return (partialPosition ? i : firstNonMaskPos);
+ };
+
+
+
+ return buffer;
+ } // end createBuffer
+ };
+
+ $.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(false)" or no parameters were supplied, return the value without the mask:
+ if (!mask && this.length > 0) {
+ var input = $(this[0]);
+ return input.data("buffer").getText(true);
+ }
+ // If "mask(true)" was called, let's update the text:
+ if (mask === true) {
+ var input = $(this[0]);
+ return input.data("buffer").checkVal();
+ }
+
+ // Default settings:
+ settings = $.extend({
+ placeholder: "_",
+ completed: null
+ }, settings);
+
+ return this.each(function () {
+ var input = $(this);
+ // Store the initial value of the text (for when the user presses Escape, and to fire Change events):
+ var focusText = input.val();
+
+ // Create the buffer:
+ var createBuffer = (settings.createBuffer || $.mask.createBuffer); // Gets the function that will create our buffer (unless it was overridden)
+ var buffer = createBuffer(input, mask, settings);
+ // Store the buffer:
+ input.data("buffer", buffer);
+
+ // Perform initial check for existing values:
+ buffer.checkVal();
+
+
+
+
+ // Variable for ignoring control keys:
+ var ignore = false;
+
+ // Bind the events:
+ if (input.attr("readonly")) return;
+
+ input
+ .one("unmask", function () {
+ input
+ .unbind(".mask")
+ .removeData("buffer")
+ .removeData("tests");
+ })
+ .bind("focus.mask", function () {
+ focusText = input.val();
+ var pos = buffer.checkVal(true);
+ var moveCaret = function(){
+ if (pos == buffer.length)
+ input.caret(0,pos);
+ else
+ input.caret(pos);
+ };
+ $.browser.msie ? moveCaret() : setTimeout(moveCaret,0);
+ })
+ .bind("blur.mask", function () {
+ buffer.checkVal(false);
+ if (input.val() != focusText)
+ input.change();
+ })
+ .bind("keydown.mask", function (e) {
+ var k = e.keyCode;
+ ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));
+
+ // backspace, delete, and escape get special treatment
+ if (k == 8 || k == 46 || (iPhone && k == 127)) { // backspace/delete
+ buffer.remove((k == 46 ? 1 : -1));
+ return false;
+ } else if (k == 27) {// escape
+ input.val(focusText);
+ var pos = buffer.checkVal();
+ if (pos == buffer.length)
+ input.caret(0, pos);
+ else
+ input.caret(pos);
+ return false;
+ }
+ })
+ .bind("keypress.mask", function (e) {
+ if (ignore) {
+ ignore = false;
+ // Fixes Mac FF bug on backspace
+ return (e.keyCode == 8) ? false : null;
+ }
+ e = e || window.event; // (unnecessary? jQuery does this automatically?)
+ var k = e.charCode || e.keyCode || e.which;
+ if (e.ctrlKey || e.altKey || e.metaKey || e.charCode === 0) { // Ignore
+ return true;
+ } else if ((k >= 32 && k <= 125) || k > 186) { // typeable characters
+ var c = String.fromCharCode(k);
+ buffer.insert(c);
+ }
+ return false;
+ })
+ .bind(pasteEventName, function () {
+ setTimeout(function () {
+ var pos = buffer.checkVal(true);
+ input.caret(pos);
+ }, 0);
+ });
+
+ });
+ }
+ });
+})(jQuery);
\ No newline at end of file
diff --git a/src/toDollarField.js b/src/toDollarField.js
new file mode 100644
index 0000000..5556209
--- /dev/null
+++ b/src/toDollarField.js
@@ -0,0 +1,141 @@
+(function($) {
+
+ $.fn.extend({
+ toDollarField: function(decimals, min, max) {
+ // ToDo: implement min, max
+ return this.mask("$#", {decimals:decimals, createBuffer: createNumberBuffer, fillDecimals: true});
+ },
+ toPercentField: function(decimals, min, max) {
+ // ToDo: implement min, max
+ return this.mask("#%", {decimals:decimals, createBuffer: createNumberBuffer, fillDecimals: true});
+ }
+ });
+
+
+ function createNumberBuffer(input, mask, settings) {
+
+ // This is a special "buffer" that can be passed to the maskedinput plugin
+ // in order to handle "currency formatting" in fields.
+
+ // The mask should contain ONLY 1 "#", along with any other "decorations".
+ mask = mask.split("#");
+ if (mask.length != 2) mask = ["",""];
+
+ var buffer = input.val().split("");
+
+ var digit = /[0-9]/;
+
+
+ // Private functions:
+
+ function formatBuffer(cpos) {
+ var coff = 0; // caret offset
+ var maxDecim = settings.decimals == undefined ? 0 : settings.decimals;
+ var decim = null; // Decimal place
+ // Extract all valid characters:
+ var digits = [];
+ for (var i = 0; i < buffer.length; i++) {
+ if (digit.test(buffer[i]) && (decim == null || (digits.length - decim <= maxDecim))) {
+ digits.push(buffer[i]);
+ } else if (decim == null && buffer[i] == ".") {
+ decim = digits.length;
+ if (settings.fillDecimals && (maxDecim > 0))
+ digits.push(".");
+ }
+ else if (cpos > i)
+ coff--; // track the caret as we remove characters.
+ }
+ cpos += coff; // Offset the caret
+ if (decim == null) { // No decimal was found
+ decim = digits.length;
+ if (settings.fillDecimals && (maxDecim > 0))
+ digits.push(".");
+ }
+
+ // Add decimal places if necessary:
+ while (settings.fillDecimals && (digits.length - decim <= maxDecim)) {
+ digits.push("0");
+ }
+
+ // Insert commas:
+ for (var i = decim-3; i > 0; i-=3) {
+ digits.splice(i,0,",");
+ if (cpos >= i) cpos++; // track the caret as we add characters.
+ }
+
+ // Add the mask "decorations":
+ cpos += mask[0].length;
+ Array.prototype.unshift.apply(digits, mask[0].split("")); // before
+ Array.prototype.push.apply(digits, mask[1].split("")); // and after
+
+ // Replace the entire buffer with the new digits:
+ digits.unshift(0,buffer.length);
+ Array.prototype.splice.apply(buffer,digits);
+
+ return cpos;
+ }
+ function writeBuffer() {
+ input.val(buffer.join(''));
+ };
+
+ // "Public" functions, used by maskedinput
+ buffer.getText = function() {
+ return buffer.join("");
+ };
+ buffer.insert = function(c) {
+ var pos = input.caret();
+ // Delete the selection
+ if (pos.begin != pos.end) {
+ buffer.splice(pos.begin, pos.end-pos.begin);
+ }
+ // Insert the character:
+ buffer.splice(pos.begin,0,c);
+ // Update the output:
+ var cpos = formatBuffer(pos.begin+1);
+ writeBuffer();
+ input.caret(cpos);
+ };
+ buffer.remove = function(dir) {
+ var pos = input.caret();
+ var cpos;
+ // Delete the selection
+ if (pos.begin != pos.end) {
+ buffer.splice(pos.begin,pos.end-pos.begin);
+ cpos = formatBuffer(pos.begin);
+ }
+ else { // Delete the current character:
+ var p = pos.begin;
+ if (dir == -1) p--; // "backspace"
+ // Find the closest digit to delete:
+ while (!digit.test(buffer[p]) && 0 <= p && p < buffer.length) p += dir;
+ if (p < 0 || buffer.length <= p) { // Nothing to delete
+ return;
+ }
+ buffer.splice(p,1);
+ cpos = formatBuffer(p);
+ }
+ // Update the output:
+ writeBuffer();
+ input.caret(cpos);
+ };
+ buffer.checkVal = function(allowIncomplete) {
+ //try to place characters where they belong
+ var pos = input.caret();
+ var cpos; // caret position
+ var text = input.val().split("");
+
+ // Replace the entire buffer with the current value:
+ text.unshift(0,buffer.length);
+ Array.prototype.splice.apply(buffer, text);
+
+ // Update the output:
+ cpos = formatBuffer(pos.begin);
+ writeBuffer();
+
+ return cpos; // Return the new caret position
+ };
+
+ return buffer;
+ };
+
+})(jQuery);
\ No newline at end of file
From c3b1503ed06fd02f62d8c1de98df89ba8aad4017 Mon Sep 17 00:00:00 2001
From: scottrippey
Date: Thu, 20 Jan 2011 00:22:01 -0800
Subject: [PATCH 4/5] Added a demo and renamed toDollarField. Also fixed a
small "fillDecimals" issue.
---
demo/numberFieldDemo.html | 36 +++++++++++++++++++
src/jquery.maskedinput-custom.js | 6 ++--
...DollarField.js => jquery.toNumberField.js} | 19 +++++-----
3 files changed, 49 insertions(+), 12 deletions(-)
create mode 100644 demo/numberFieldDemo.html
rename src/{toDollarField.js => jquery.toNumberField.js} (87%)
diff --git a/demo/numberFieldDemo.html b/demo/numberFieldDemo.html
new file mode 100644
index 0000000..f616ea1
--- /dev/null
+++ b/demo/numberFieldDemo.html
@@ -0,0 +1,36 @@
+
+
+ jQuery NumberField Demo
+
+
+
+
+
+
+
+
+
+
diff --git a/src/jquery.maskedinput-custom.js b/src/jquery.maskedinput-custom.js
index 7b9f5c1..31503b6 100644
--- a/src/jquery.maskedinput-custom.js
+++ b/src/jquery.maskedinput-custom.js
@@ -217,13 +217,11 @@
mask: function (mask, settings) {
// If "mask(false)" or no parameters were supplied, return the value without the mask:
if (!mask && this.length > 0) {
- var input = $(this[0]);
- return input.data("buffer").getText(true);
+ return $(this[0]).data("buffer").getText(true);
}
// If "mask(true)" was called, let's update the text:
if (mask === true) {
- var input = $(this[0]);
- return input.data("buffer").checkVal();
+ return $(this[0]).data("buffer").checkVal();
}
// Default settings:
diff --git a/src/toDollarField.js b/src/jquery.toNumberField.js
similarity index 87%
rename from src/toDollarField.js
rename to src/jquery.toNumberField.js
index 5556209..9f48b40 100644
--- a/src/toDollarField.js
+++ b/src/jquery.toNumberField.js
@@ -1,13 +1,16 @@
-(function($) {
+///
+(function($) {
$.fn.extend({
- toDollarField: function(decimals, min, max) {
+ toNumberField: function(mask, decimals, fillDecimals, min, max) {
// ToDo: implement min, max
- return this.mask("$#", {decimals:decimals, createBuffer: createNumberBuffer, fillDecimals: true});
+ return this.mask(mask || "#", {decimals:decimals, createBuffer: createNumberBuffer, fillDecimals: fillDecimals});
},
- toPercentField: function(decimals, min, max) {
- // ToDo: implement min, max
- return this.mask("#%", {decimals:decimals, createBuffer: createNumberBuffer, fillDecimals: true});
+ toDollarField: function(decimals, fillDecimals, min, max) {
+ return this.toNumberField("$#", decimals, fillDecimals, min, max);
+ },
+ toPercentField: function(decimals, fillDecimals, min, max) {
+ return this.toNumberField("#%", decimals, fillDecimals, min, max);
}
});
@@ -30,7 +33,7 @@
function formatBuffer(cpos) {
var coff = 0; // caret offset
- var maxDecim = settings.decimals == undefined ? 0 : settings.decimals;
+ var maxDecim = settings.decimals || 0;
var decim = null; // Decimal place
// Extract all valid characters:
var digits = [];
@@ -39,7 +42,7 @@
digits.push(buffer[i]);
} else if (decim == null && buffer[i] == ".") {
decim = digits.length;
- if (settings.fillDecimals && (maxDecim > 0))
+ if (maxDecim > 0)
digits.push(".");
}
else if (cpos > i)
From 89e2e9fd2cf9dd5a443186acfca29f2b462ae07c Mon Sep 17 00:00:00 2001
From: scottrippey
Date: Thu, 20 Jan 2011 00:35:27 -0800
Subject: [PATCH 5/5] Fixed charCode issue and added
"$.mask.definitions.add(...)" method.
---
src/jquery.maskedinput.js | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/jquery.maskedinput.js b/src/jquery.maskedinput.js
index ab22f97..7366023 100644
--- a/src/jquery.maskedinput.js
+++ b/src/jquery.maskedinput.js
@@ -11,9 +11,14 @@
$.mask = {
//Predefined character definitions
definitions: {
- '9': "[0-9]",
- 'a': "[A-Za-z]",
- '*': "[A-Za-z0-9]"
+ '9': /[0-9]/,
+ 'a': /[A-Za-z]/,
+ '*': /[A-Za-z0-9]/,
+ add: function(key, pattern, placeholder) {
+ if (typeof pattern === 'string') pattern = new RegExp(pattern);
+ pattern.placeholder = placeholder;
+ this[key] = pattern;
+ }
}
};
@@ -152,7 +157,7 @@
var k = e.charCode || e.keyCode || e.which;
var pos = $(this).caret();
- if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
+ if (e.ctrlKey || e.altKey || e.metaKey || e.charCode === 0) {//Ignore
return true;
} else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
var p = seekNext(pos.begin - 1);