diff --git a/numeric/jquery.numeric.js b/numeric/jquery.numeric.js index bfc79c1..5a6d13e 100644 --- a/numeric/jquery.numeric.js +++ b/numeric/jquery.numeric.js @@ -8,284 +8,252 @@ * Demo: http://www.texotela.co.uk/code/jquery/numeric/ * */ -(function($) { -/* - * Allows only valid characters to be entered into input boxes. - * Note: fixes value when pasting via Ctrl+V, but not when using the mouse to paste - * side-effect: Ctrl+A does not work, though you can still use the mouse to select (or double-click to select all) - * - * @name numeric - * @param config { decimal : "." , negative : true } - * @param callback A function that runs if the number is not valid (fires onblur) - * @author Sam Collett (http://www.texotela.co.uk) - * @example $(".numeric").numeric(); - * @example $(".numeric").numeric(","); // use , as separator - * @example $(".numeric").numeric({ decimal : "," }); // use , as separator - * @example $(".numeric").numeric({ negative : false }); // do not allow negative values - * @example $(".numeric").numeric(null, callback); // use default values, pass on the 'callback' function - * - */ -$.fn.numeric = function(config, callback) -{ - if(typeof config === 'boolean') - { - config = { decimal: config }; - } - config = config || {}; - // if config.negative undefined, set to true (default is to allow negative numbers) - if(typeof config.negative == "undefined") { config.negative = true; } - // set decimal point - var decimal = (config.decimal === false) ? "" : config.decimal || "."; - // allow negatives - var negative = (config.negative === true) ? true : false; - // callback function - callback = (typeof(callback) == "function" ? callback : function() {}); - // set data and methods - return this.data("numeric.decimal", decimal).data("numeric.negative", negative).data("numeric.callback", callback).keypress($.fn.numeric.keypress).keyup($.fn.numeric.keyup).blur($.fn.numeric.blur); -}; +(function ($) { + /* + * Allows only valid characters to be entered into input boxes. + * Note: fixes value when pasting via Ctrl+V, but not when using the mouse to paste + * side-effect: Ctrl+A does not work, though you can still use the mouse to select (or double-click to select all) + * + * @name numeric + * @param config { decimal : "." , negative : true } + * @param callback A function that runs if the number is not valid (fires onblur) + * @author Sam Collett (http://www.texotela.co.uk) + * @example $(".numeric").numeric(); + * @example $(".numeric").numeric(","); // use , as separator + * @example $(".numeric").numeric({ decimal : "," }); // use , as separator + * @example $(".numeric").numeric({ negative : false }); // do not allow negative values + * @example $(".numeric").numeric(null, callback); // use default values, pass on the 'callback' function + * + */ + $.fn.numeric = function (config, callback) { + if (typeof config === 'boolean') { + config = { decimal: config }; + } + config = config || {}; + // if config.negative undefined, set to true (default is to allow negative numbers) + if (typeof config.negative == "undefined") { config.negative = true; } + // set decimal point + var decimal = (config.decimal === false) ? "" : config.decimal || "."; + // allow negatives + var negative = (config.negative === true) ? true : false; + // callback function + callback = (typeof (callback) == "function" ? callback : function () { }); + // set data and methods + return this.data("numeric.decimal", decimal).data("numeric.negative", negative).data("numeric.callback", callback).keydown($.fn.numeric.keydown).keyup($.fn.numeric.keyup).blur($.fn.numeric.blur); + }; + + $.fn.numeric.keydown = function (e) { + // get decimal character and determine if negatives are allowed + var decimal = $.data(this, "numeric.decimal"); + var negative = $.data(this, "numeric.negative"); + // get the key that was pressed + var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0; + // allow enter/return key (only when in an input box) + if (key == 13 && this.nodeName.toLowerCase() == "input") { + return true; + } + else if (key == 13) { + return false; + } + var allow = false; + // allow Ctrl+A + if ((e.ctrlKey && key == 97 /* firefox */) || (e.ctrlKey && key == 65) /* opera */) { return true; } + // allow Ctrl+X (cut) + if ((e.ctrlKey && key == 120 /* firefox */) || (e.ctrlKey && key == 88) /* opera */) { return true; } + // allow Ctrl+C (copy) + if ((e.ctrlKey && key == 99 /* firefox */) || (e.ctrlKey && key == 67) /* opera */) { return true; } + // allow Ctrl+Z (undo) + if ((e.ctrlKey && key == 122 /* firefox */) || (e.ctrlKey && key == 90) /* opera */) { return true; } + // allow or deny Ctrl+V (paste), Shift+Ins + if ((e.ctrlKey && key == 118 /* firefox */) || (e.ctrlKey && key == 86) /* opera */ || + (e.shiftKey && key == 45)) { return true; } + // if a number was not pressed + if (key < 48 || key > 57) { + var value = $(this).val(); + /* '-' only allowed at start and if negative numbers allowed */ + if (value.indexOf("-") !== 0 && negative && key == 45 && (value.length === 0 || parseInt($.fn.getSelectionStart(this), 10) === 0)) { return true; } + /* only one decimal separator allowed */ + if (decimal && key == decimal.charCodeAt(0) && value.indexOf(decimal) != -1) { + allow = false; + } + // check for other keys that have special purposes + if ( + key != 8 /* backspace */ && + key != 9 /* tab */ && + key != 13 /* enter */ && + key != 35 /* end */ && + key != 36 /* home */ && + key != 37 /* left */ && + key != 39 /* right */ && + key != 46 /* del */ + ) { + allow = false; + } + else { + // for detecting special keys (listed above) + // IE does not support 'charCode' and ignores them in keypress anyway + if (typeof e.charCode != "undefined") { + // special keys have 'keyCode' and 'which' the same (e.g. backspace) + if (e.keyCode == e.which && e.which !== 0) { + allow = true; + } + // or keyCode != 0 and 'charCode'/'which' = 0 + else if (e.keyCode !== 0 && e.charCode === 0 && e.which === 0) { + allow = true; + } + } + } + // if key pressed is the decimal and it is not already in the field + if (decimal && key === 190) { + if (this.value.indexOf(decimal) == -1) { + allow = true; + } + else { + allow = false; + } + } + } + else { + allow = true; + } + return allow; + }; + + $.fn.numeric.keyup = function (e) { + var key = e.keyCode; + var isShift = e.shiftKey; + var isCtrl = e.ctrlKey; + var isAlt = e.altKey; + var val = $(this).val(); + var notHeldKeys = !isShift && !isCtrl && !isAlt; + var notHeldKeysReleased = key !== 16 && key !== 17 && key !== 18; + if (val && val.length > 0) { + // get carat (cursor) position + var carat = $.fn.getSelectionStart(this); + var selectionEnd = $.fn.getSelectionEnd(this); + // get decimal character and determine if negatives are allowed + var decimal = $.data(this, "numeric.decimal"); + var negative = $.data(this, "numeric.negative"); + // prepend a 0 if necessary, and only if the 0 isn't being deleted, or if a key is being held (shift/ctrl/alt), or a 'held key' (eg. shift) is released + if (decimal !== "" && decimal !== null && e.keyCode !== 46 && e.keyCode !== 8 && notHeldKeys && notHeldKeysReleased) { + // find decimal point + var dot = val.indexOf(decimal); + // if dot at start, add 0 before + if (dot === 0) { + this.value = "0" + val; + carat++; + } + // if dot at position 1, check if there is a - symbol before it + if (dot == 1 && val.charAt(0) == "-") { + this.value = "-0" + val.substring(1); + carat++; + } + val = this.value; + } -$.fn.numeric.keypress = function(e) -{ - // get decimal character and determine if negatives are allowed - var decimal = $.data(this, "numeric.decimal"); - var negative = $.data(this, "numeric.negative"); - // get the key that was pressed - var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0; - // allow enter/return key (only when in an input box) - if(key == 13 && this.nodeName.toLowerCase() == "input") - { - return true; - } - else if(key == 13) - { - return false; - } - var allow = false; - // allow Ctrl+A - if((e.ctrlKey && key == 97 /* firefox */) || (e.ctrlKey && key == 65) /* opera */) { return true; } - // allow Ctrl+X (cut) - if((e.ctrlKey && key == 120 /* firefox */) || (e.ctrlKey && key == 88) /* opera */) { return true; } - // allow Ctrl+C (copy) - if((e.ctrlKey && key == 99 /* firefox */) || (e.ctrlKey && key == 67) /* opera */) { return true; } - // allow Ctrl+Z (undo) - if((e.ctrlKey && key == 122 /* firefox */) || (e.ctrlKey && key == 90) /* opera */) { return true; } - // allow or deny Ctrl+V (paste), Shift+Ins - if((e.ctrlKey && key == 118 /* firefox */) || (e.ctrlKey && key == 86) /* opera */ || - (e.shiftKey && key == 45)) { return true; } - // if a number was not pressed - if(key < 48 || key > 57) - { - var value = $(this).val(); - /* '-' only allowed at start and if negative numbers allowed */ - if(value.indexOf("-") !== 0 && negative && key == 45 && (value.length === 0 || parseInt($.fn.getSelectionStart(this), 10) === 0)) { return true; } - /* only one decimal separator allowed */ - if(decimal && key == decimal.charCodeAt(0) && value.indexOf(decimal) != -1) - { - allow = false; - } - // check for other keys that have special purposes - if( - key != 8 /* backspace */ && - key != 9 /* tab */ && - key != 13 /* enter */ && - key != 35 /* end */ && - key != 36 /* home */ && - key != 37 /* left */ && - key != 39 /* right */ && - key != 46 /* del */ - ) - { - allow = false; - } - else - { - // for detecting special keys (listed above) - // IE does not support 'charCode' and ignores them in keypress anyway - if(typeof e.charCode != "undefined") - { - // special keys have 'keyCode' and 'which' the same (e.g. backspace) - if(e.keyCode == e.which && e.which !== 0) - { - allow = true; - // . and delete share the same code, don't allow . (will be set to true later if it is the decimal point) - if(e.which == 46) { allow = false; } - } - // or keyCode != 0 and 'charCode'/'which' = 0 - else if(e.keyCode !== 0 && e.charCode === 0 && e.which === 0) - { - allow = true; - } - } - } - // if key pressed is the decimal and it is not already in the field - if(decimal && key == decimal.charCodeAt(0)) - { - if(value.indexOf(decimal) == -1) - { - allow = true; - } - else - { - allow = false; - } - } - } - else - { - allow = true; - } - return allow; -}; + // if pasted in, only allow the following characters + var validChars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '-', decimal]; + // get length of the value (to loop through) + var length = val.length; + // loop backwards (to prevent going out of bounds) + for (var i = length - 1; i >= 0; i--) { + var ch = val.charAt(i); + // remove '-' if it is in the wrong place + if (i !== 0 && ch == "-") { + val = val.substring(0, i) + val.substring(i + 1); + } + // remove character if it is at the start, a '-' and negatives aren't allowed + else if (i === 0 && !negative && ch == "-") { + val = val.substring(1); + } + var validChar = false; + // loop through validChars + for (var j = 0; j < validChars.length; j++) { + // if it is valid, break out the loop + if (ch == validChars[j]) { + validChar = true; + break; + } + } + // if not a valid character, or a space, remove + if (!validChar || ch == " ") { + val = val.substring(0, i) + val.substring(i + 1); + } + } + // remove extra decimal characters + var firstDecimal = val.indexOf(decimal); + if (firstDecimal > 0) { + for (var k = length - 1; k > firstDecimal; k--) { + var chch = val.charAt(k); + // remove decimal character + if (chch == decimal) { + val = val.substring(0, k) + val.substring(k + 1); + } + } + } + // set the value and prevent the cursor moving to the end + this.value = val; -$.fn.numeric.keyup = function(e) -{ - var val = $(this).val(); - if(val && val.length > 0) - { - // get carat (cursor) position - var carat = $.fn.getSelectionStart(this); - var selectionEnd = $.fn.getSelectionEnd(this); - // get decimal character and determine if negatives are allowed - var decimal = $.data(this, "numeric.decimal"); - var negative = $.data(this, "numeric.negative"); - - // prepend a 0 if necessary - if(decimal !== "" && decimal !== null) - { - // find decimal point - var dot = val.indexOf(decimal); - // if dot at start, add 0 before - if(dot === 0) - { - this.value = "0" + val; - } - // if dot at position 1, check if there is a - symbol before it - if(dot == 1 && val.charAt(0) == "-") - { - this.value = "-0" + val.substring(1); - } - val = this.value; - } - - // if pasted in, only allow the following characters - var validChars = [0,1,2,3,4,5,6,7,8,9,'-',decimal]; - // get length of the value (to loop through) - var length = val.length; - // loop backwards (to prevent going out of bounds) - for(var i = length - 1; i >= 0; i--) - { - var ch = val.charAt(i); - // remove '-' if it is in the wrong place - if(i !== 0 && ch == "-") - { - val = val.substring(0, i) + val.substring(i + 1); - } - // remove character if it is at the start, a '-' and negatives aren't allowed - else if(i === 0 && !negative && ch == "-") - { - val = val.substring(1); - } - var validChar = false; - // loop through validChars - for(var j = 0; j < validChars.length; j++) - { - // if it is valid, break out the loop - if(ch == validChars[j]) - { - validChar = true; - break; - } - } - // if not a valid character, or a space, remove - if(!validChar || ch == " ") - { - val = val.substring(0, i) + val.substring(i + 1); - } - } - // remove extra decimal characters - var firstDecimal = val.indexOf(decimal); - if(firstDecimal > 0) - { - for(var k = length - 1; k > firstDecimal; k--) - { - var chch = val.charAt(k); - // remove decimal character - if(chch == decimal) - { - val = val.substring(0, k) + val.substring(k + 1); - } - } - } - // set the value and prevent the cursor moving to the end - this.value = val; - $.fn.setSelection(this, [carat, selectionEnd]); - } -}; + // Don't set position if the user has shift/ctrl/alt key pressed, or the last key was pressed was '.', or the last key pressed was not a numeric key + if (key === 190 || (notHeldKeys && (key < 48 || key > 57)) && notHeldKeysReleased) { + $.fn.setSelection(this, carat); + } + } + }; -$.fn.numeric.blur = function() -{ - var decimal = $.data(this, "numeric.decimal"); - var callback = $.data(this, "numeric.callback"); - var val = this.value; - if(val !== "") - { - var re = new RegExp("^\\d+$|^\\d*" + decimal + "\\d+$"); - if(!re.exec(val)) - { - callback.apply(this); - } - } -}; + $.fn.numeric.blur = function () { + var decimal = $.data(this, "numeric.decimal"); + var callback = $.data(this, "numeric.callback"); + var val = this.value; + if (val !== "") { + var re = new RegExp("^\\d+$|^\\d*" + decimal + "\\d+$"); + if (!re.exec(val)) { + callback.apply(this); + } + } + }; -$.fn.removeNumeric = function() -{ - return this.data("numeric.decimal", null).data("numeric.negative", null).data("numeric.callback", null).unbind("keypress", $.fn.numeric.keypress).unbind("blur", $.fn.numeric.blur); -}; + $.fn.removeNumeric = function () { + return this.data("numeric.decimal", null).data("numeric.negative", null).data("numeric.callback", null).unbind("keypress", $.fn.numeric.keypress).unbind("blur", $.fn.numeric.blur); + }; -// Based on code from http://javascript.nwbox.com/cursor_position/ (Diego Perini ) -$.fn.getSelectionStart = function(o) -{ - if (o.createTextRange) - { - var r = document.selection.createRange().duplicate(); - r.moveEnd('character', o.value.length); - if (r.text === '') { return o.value.length; } - return o.value.lastIndexOf(r.text); - } else { return o.selectionStart; } -}; + // Based on code from http://javascript.nwbox.com/cursor_position/ (Diego Perini ) + $.fn.getSelectionStart = function (o) { + if (o.createTextRange) { + var r = document.selection.createRange().duplicate(); + r.moveEnd('character', o.value.length); + if (r.text === '') { return o.value.length; } + return o.value.lastIndexOf(r.text); + } else { return o.selectionStart; } + }; -// Based on code from http://javascript.nwbox.com/cursor_position/ (Diego Perini ) -$.fn.getSelectionEnd = function(o) -{ - if (o.createTextRange) { - var r = document.selection.createRange().duplicate() - r.moveStart('character', -o.value.length) - return r.text.length - } else return o.selectionEnd -} + // Based on code from http://javascript.nwbox.com/cursor_position/ (Diego Perini ) + $.fn.getSelectionEnd = function (o) { + if (o.createTextRange) { + var r = document.selection.createRange().duplicate() + r.moveStart('character', -o.value.length) + return r.text.length + } else return o.selectionEnd + } -// set the selection, o is the object (input), p is the position ([start, end] or just start) -$.fn.setSelection = function(o, p) -{ - // if p is number, start and end are the same - if(typeof p == "number") { p = [p, p]; } - // only set if p is an array of length 2 - if(p && p.constructor == Array && p.length == 2) - { - if (o.createTextRange) - { - var r = o.createTextRange(); - r.collapse(true); - r.moveStart('character', p[0]); - r.moveEnd('character', p[1]); - r.select(); - } - else if(o.setSelectionRange) - { - o.focus(); - o.setSelectionRange(p[0], p[1]); - } - } -}; + // set the selection, o is the object (input), p is the position ([start, end] or just start) + $.fn.setSelection = function (o, p) { + // if p is number, start and end are the same + if (typeof p == "number") { p = [p, p]; } + // only set if p is an array of length 2 + if (p && p.constructor == Array && p.length == 2) { + if (o.createTextRange) { + var r = o.createTextRange(); + r.collapse(true); + r.moveStart('character', p[0]); + r.moveEnd('character', p[1]); + r.select(); + } + else if (o.setSelectionRange) { + o.focus(); + o.setSelectionRange(p[0], p[1]); + } + } + }; -})(jQuery); +})(jQuery); \ No newline at end of file