JavaScript InputMask jQuery插件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript InputMask jQuery插件相关的知识,希望对你有一定的参考价值。
/*---------------------------------------------------------------------------------
*
* InputMask jQuery Plugin
*
*---------------------------------------------------------------------------------
*
* Taking alot of inspiration and code from
* http://digitalbush.com/projects/masked-input-plugin this is a masked input
* solution that should handle most cases. It uses annotations to determine the
* actual mask. Mask characters include,
*
* % - Any digit or numeric sign
* # - Any digit
* @ - Any letter
* * - Any letter or digit
* ~ - Any sign (+/-)
* ? - Currencies ($,£,€,¥)
*
* @author James Hughes
*
* -------------------------------------------------------------------------------
* 29/10/2008 - Initial Version
* -------------------------------------------------------------------------------
*
*///------------------------------------------------------------------------------
(function($){
/*-----------------------------------------------------------------------------
*
* availableMasks
*
*-----------------------------------------------------------------------------
*
* Available Character Masks. This can be extended or modified via the
* $.mask.availableMasks config.
*
*///--------------------------------------------------------------------------
var availableMasks = {
'%' : '[-+0-9]', // Any digit or numeric sign
'#' : '[0-9]', // Any digit
'@' : '[A-Za-z]', // Any letter
'*' : '[A-Za-z0-9]', // Any letter or digit
'~' : '[+-]', // Any sign (+/-)
'?' : '[\$£€¥]' // Typical World Currencies
}
/*-----------------------------------------------------------------------------
*
* $.applyMasks
*
*-----------------------------------------------------------------------------
*
* Deteremines, based @Mask on annotations, all elements below either the
* specified root or the document element that should have masks applied
*
* @plugin
*
* @param opts - options
*
*///--------------------------------------------------------------------------
$.applyMasks = function(root, opts){
$.annotated("@Mask", root || document).mask(opts);
}
/*-----------------------------------------------------------------------------
*
* $.fn.mask
*
*-----------------------------------------------------------------------------
*
* Applies the annotated masks to the passed in elements. Applicable options
*
* invalidHandler custom event fired when field blurs invalid
* placeholder placeholder for mask characters. defaults to _
* alwaysShowMask determine if we always show the input mask
* permitIncomplete determine if we allow the field to be partially
* filled on blur.
* selectOnFocus : true
*
*///--------------------------------------------------------------------------
$.fn.mask = function(opts){
/*-------------------------------------------------------------------------
*
* Apply Mask
*
*-------------------------------------------------------------------------
*
* This section discovers the required mask on a per field basis and
* applies the behaviour to the field
*
*///----------------------------------------------------------------------
return this.each(function(){
/*---------------------------------------------------------------------
*
* No Mask Annotation Failover
*
*---------------------------------------------------------------------
*
* Most of this API is open to the public therefore open to the
* irresponsible, ignorant, clueless and just plain stupid. We need
* to cater for as much worst case edge cases as we can without
* making the good people suffer. Exit if no mask defined on the
* element.
*
*///------------------------------------------------------------------
if(!$(this).annotations("@Mask")[0]){ return undefined };
/*---------------------------------------------------------------------
*
* Apply Options
*
*---------------------------------------------------------------------
*
* Merge the default and custom options resulting in a specific
* options map for this function call.
*
*///------------------------------------------------------------------
var o = $.extend({}, defaultOptions, opts);
/*---------------------------------------------------------------------
*
* Assign Buffers
*
*---------------------------------------------------------------------
*
* Iterate over the jQuery collection of fields passed in and add
* the intial buffer data to each.
*
*///------------------------------------------------------------------
$(this).each(function(){
$(this).data("mask-buffer", new MaskBuffer(
$(this).annotations("@Mask")[0].data, o.placeholder
));
});
/*---------------------------------------------------------------------
*
* Handle Blur
*
*---------------------------------------------------------------------
*
* When a masked field blurs we need to handle overall validation and
* based on the confguration options hide and show the mask. If the
* field is invalid the event will fire the custom handler.
*
*///------------------------------------------------------------------
function handleBlur(){
var buffer = $(this).data("mask-buffer");
if(!o.permitIncomplete){
var v = $(this).val();
if(((!v || v === "") || !buffer.test())){
buffer.reset();
$(this).val( o.alwaysShowMask ? buffer.get() : "" );
o.invalidHandler(this, v);
}
}
}
/*---------------------------------------------------------------------
*
* Handle Key Press
*
*---------------------------------------------------------------------
*
* In the keypress event we are responsible for handling the standard
* keys and managing the buffer
*
*///------------------------------------------------------------------
function handleKeyPress(e){
var code = ($.browser.msie) ? e.which : e.charCode;
if(code != 0 && !(e.ctrlKey || e.altKey)){
var buffer = $(this).data("mask-buffer");
var carat = $.carat.get(this);
var ncp = buffer.nextMaskPosition(carat.start-1);
if(ncp < buffer.size()){
var characterTest = new RegExp(availableMasks[buffer.getMaskValue(ncp)]);
var value = String.fromCharCode(code);
if(characterTest.test(value)){
buffer.set(ncp, value);
$(this).val(buffer.get());
$.carat.set(this, new Carat(buffer.nextMaskPosition(ncp)));
}
}
/* handle ourselves */
return false;
}
}
/*---------------------------------------------------------------------
*
* Handle Key Down
*
*---------------------------------------------------------------------
*
* In the key down we are responsible for handling special characters
* such as delete, backspace and escape. As well as clearing any
* selections
*
*///------------------------------------------------------------------
function handleKeyDown(e){
/*-----------------------------------------------------------------
*
* Key Code Constants
*
*-----------------------------------------------------------------
*
* Constant representing the useful keycodes
*
*///--------------------------------------------------------------
var BACKSPACE = 8;
var DELETE = 46;
var ESCAPE = 27;
var carat = $.carat.get(this);
var code = e.keyCode;
var buffer = $(this).data("mask-buffer");
if(carat.isSelection() && (code == BACKSPACE || code == DELETE)){
buffer.reset(carat.start, carat.end);
}
switch(code){
case BACKSPACE:
while(carat.start-- >= 0){
if(availableMasks[buffer.getMaskValue(carat.start)]){
buffer.reset(carat.start);
if($.browser.opera){
/* Opera can't cancel backspace, prevent deletion */
$(this).val(buffer.get().substring(0, carat.start) + " " + buffer.get().substring(carat.start));
$.carat.set(this, new Carat(carat.start++));
}else{
$(this).val(buffer.get());
$.carat.set(this, new Carat(Math.max(buffer.getStartingMaskPosition(), carat.start)));
}
return false;
}
}
break;
case DELETE:
buffer.reset(carat.start);
$(this).val(buffer.get());
$.carat.set(this, new Carat(Math.max(buffer.getStartingMaskPosition(), carat.start)));
return false;
case ESCAPE:
buffer.reset();
$(this).val(buffer.get());
$.carat.set(this, new Carat(buffer.getStartingMaskPosition()));
return false;
}
}
/*---------------------------------------------------------------------
*
* Handle Focus
*
*---------------------------------------------------------------------
*
* On focus we want to set the value to the current buffer state and
* determine where we set the carat
*
*///------------------------------------------------------------------
function handleFocus(){
$(this).val($(this).data("mask-buffer").get());
if(o.selectOnFocus){
$.carat.set(this, new Carat(0, $(this).val().length));
}else{
$.carat.set(this, new Carat(Math.max(start, this.value.indexOf(o.placeholder))));
}
}
/*---------------------------------------------------------------------
*
* Handle Paste
*
*---------------------------------------------------------------------
*
* Custom event used to handle onpaste events. When we paste data
* into a masked field we loop over the buffer and only apply the
* valid parts of the paste.
*
* This method is not ideal but it does the job for now.
*
*///------------------------------------------------------------------
function handlePaste(){
var currentValue = $(this).val().split('');
var buffer = $(this).data("mask-buffer");
for(var i = 0; i < buffer.size(); i++){
if(availableMasks[buffer.getMaskValue(i)]){
var re = new RegExp(availableMasks[buffer.getMaskValue(i)]);
if(re.test(currentValue[i])){
buffer.set(i, currentValue[i])
}else{
buffer.reset(i);
}
}
}
$(this).val(buffer.get());
$.carat.set(this, new Carat((this.value.indexOf(o.placeholder) == -1)?buffer.size():this.value.indexOf(o.placeholder)));
handleBlur.call(this);
}
/*---------------------------------------------------------------------
*
* Bind Events
*
*---------------------------------------------------------------------
*
* Bind the mask events to the current field. Include the custom
* paste event.
*
*///------------------------------------------------------------------
$(this).bind('blur', handleBlur);
$(this).bind('keypress', handleKeyPress);
$(this).bind('focus', handleFocus);
$(this).bind('keydown', handleKeyDown);
if ($.browser.msie){
this.onpaste = function(){ setTimeout(handlePaste,0); };
}else if ($.browser.mozilla){
this.addEventListener('input', handlePaste, false);
}
/*---------------------------------------------------------------------
*
* Unmask Event
*
*---------------------------------------------------------------------
*
* Add the unmask event to be fired only once. This will remove all
* the mask associated data and event listeners from the field
*
*///------------------------------------------------------------------
$(this).one('unmask', function(){
/* Unbond Events */
$(this).unbind('blur', handleBlur);
$(this).unbind('keypress', handleKeyPress);
$(this).unbind('focus', handleFocus);
$(this).unbind('keydown', handleKeyDown);
/* Remove Buffer Data */
$(this).removeData("mask-buffer");
/* Remove Custom Paste Event */
if ($.browser.msie){
this.onpaste = null;
}else if ($.browser.mozilla){
this.removeEventListener('input',handlePaste,false);
}
});
/*---------------------------------------------------------------------
*
* Initialize Field
*
*---------------------------------------------------------------------
*
* Call the handlePaste event to intialize the field. This will
* handle any existing text that is there and set the inital value of
* the field.
*
*///------------------------------------------------------------------
handlePaste.call(this);
});
}
/*-----------------------------------------------------------------------------
*
* $.fn.unmask
*
*-----------------------------------------------------------------------------
*
* Remove any masks from the passed in fields.
*
*///--------------------------------------------------------------------------
$.fn.unmask = function(){
return this.trigger('unmask');
}
/*-----------------------------------------------------------------------------
*
* Default Options
*
*-----------------------------------------------------------------------------
*
* This map represents the global default options that should be used
* when applying constraints. They can be overridden via custom maps
* passed into the functions.
*
*///--------------------------------------------------------------------------
var defaultOptions = {
invalidHandler : function(el){},
placeholder : "_",
alwaysShowMask : true,
permitIncomplete : false,
selectOnFocus : true
};
/*-----------------------------------------------------------------------------
*
* Carat Object
*
*-----------------------------------------------------------------------------
*
* The Carat object encapsulates carat functionality such as setting and
* getting selections and postions.
*
* @constructor
*
*///--------------------------------------------------------------------------
var Carat = function(s,e){
this.start = s || 0;
this.end = e || s || 0;
}
Carat.prototype = {
/*-------------------------------------------------------------------------
*
* isSelection
*
*-------------------------------------------------------------------------
*
* Determines if the current carat position is a selection or not
*
*///----------------------------------------------------------------------
isSelection:function(){
return this.start < this.end;
},
start : this.start,
end : this.end
}
/*-----------------------------------------------------------------------------
*
* getCaratPosition
*
*-----------------------------------------------------------------------------
*
* Based on the passed in input field this function will return the current
* carat position as an object with a start and end property. This allows
* for both single carat positions and whole selection ranges
*
* @param el element to extract carat position from
*
*///--------------------------------------------------------------------------
Carat.getCaratPosition = function(el){
if (el.setSelectionRange){
return new Carat(el.selectionStart, el.selectionEnd);
}else if (document.selection && document.selection.createRange){
var range = document.selection.createRange();
var start = 0 - range.duplicate().moveStart('character', -100000);
return new Carat(start, start + range.text.length);
}
}
/*-----------------------------------------------------------------------------
*
* Set Carat Position
*
*-----------------------------------------------------------------------------
*
* Sets the postion of the carat on the passed in element. Can be a single
* postion of a selection.
*
* @param el element to set carat position omn
* @param from start position of carat
* @param to end position of carat (optional)
*
*///--------------------------------------------------------------------------
Carat.setCaratPosition = function(el, c){
if(el.setSelectionRange){
el.focus();
el.setSelectionRange(c.start,c.end);
}else if (el.createTextRange){
var range = el.createTextRange();
range.collapse(true);
range.moveEnd('character', c.end);
range.moveStart('character', c.start);
range.select();
}
}
/*-----------------------------------------------------------------------------
*
* Mask Buffer Class
*
*-----------------------------------------------------------------------------
*
* The Mask Buffer Class houses all the internal buffer mechanisms asnd
* provides a cleaner interface for working with buffers.
*
*///--------------------------------------------------------------------------
var MaskBuffer = function(m, p){
/*-------------------------------------------------------------------------
*
* isFixedCharacter
*
*-------------------------------------------------------------------------
*
* Determines if the postion within the passed in mask is a fixed
* character or if it is a mask character
*
* @param m - the mask
* @param postion - position to check
*
*///----------------------------------------------------------------------
this.isFixedCharacter = function(m, position){
return !availableMasks[m.charAt(position)];
}
/*-------------------------------------------------------------------------
*
* Generate RegExp
*
*-------------------------------------------------------------------------
*
* Build up a complete mask regualr expression to validate the enitre
* input upon blur and paste events.
*
*///----------------------------------------------------------------------
var parsedMask = $.map(m.split(""), function(it){
return availableMasks[it] || (/[A-Za-z0-9]/.test(it)?"":"\\") + it;
});
this.fullRegEx = new RegExp("^" + parsedMask.join("") + "$");
/*-------------------------------------------------------------------------
*
* Initialize Object
*
*-------------------------------------------------------------------------
*
* Build the initial buffer, find the first mask character position and
* store the values internall in this object
*
*///----------------------------------------------------------------------
this.start = m.length;
this.buffer = new Array(m.length);
for(var i = m.length-1; i >= 0; i--){
if(!this.isFixedCharacter(m,i)){
this.start = i;
this.buffer[i] = p;
}else{
this.buffer[i] = m.charAt(i);
}
}
this.initial = $.map(this.buffer, function(e){return e}),
this.mask = m;
}
/* Extend the object */
MaskBuffer.prototype = {
/*-------------------------------------------------------------------------
*
* getInitialMask
*
*-------------------------------------------------------------------------
*
* Returns a copy of the initial mask array that was used to create
* this buffer instance. A copy is returned to to prevent any pass by
* reference overwritting.
*
*///----------------------------------------------------------------------
getInitialMask: function(){
return $.map(this.initial, function(e){return e}); // clone
},
/*-------------------------------------------------------------------------
*
* getStartingMaskPosition
*
*-------------------------------------------------------------------------
*
* Returns the index of the first mask (i.e. non fixed) character in the
* mask
*
*///----------------------------------------------------------------------
getStartingMaskPosition: function(){
return this.start;
},
/*-------------------------------------------------------------------------
*
* nextMaskPostion
*
*-------------------------------------------------------------------------
*
* from the passed in index returns the postion of the next non fixed
* mask character.
*
*///----------------------------------------------------------------------
nextMaskPosition : function(i){
var target = i||0;
while(++target < this.mask.length){
if(!this.isFixedCharacter(this.mask,target)){
return target;
}
}
return this.mask.length;
},
/*-------------------------------------------------------------------------
*
* get
*
*-------------------------------------------------------------------------
*
* Returns, depending on the arguments passed, either the string value of
* the current buffer state of the character at the passed index of the
* buffer
*
*///----------------------------------------------------------------------
get: function(){
return (arguments.length === 0)?this.buffer.join(''):this.buffer[arguments[0]];
},
/*-------------------------------------------------------------------------
*
* getMaskValue
*
*-------------------------------------------------------------------------
*
* Returns the character of the mask at the current position
*
*///----------------------------------------------------------------------
getMaskValue: function(idx){
return this.mask.charAt(idx);
},
/*-------------------------------------------------------------------------
*
* size
*
*-------------------------------------------------------------------------
*
* Returns the length of the buffer/mask/initial mask etc
*
*///----------------------------------------------------------------------
size: function(){
return this.buffer.length;
},
/*-------------------------------------------------------------------------
*
* set
*
*-------------------------------------------------------------------------
*
* Sets either the enitre buffer or a specific character of the buffer.
*
* @param i Array|Number. The array to set the buffer to or the postion
* of the character to set the value of
* @param v Boolean|Character. If boolean then it makes determines if a
* clone of the array is to be used. If character it is the
* character to put in the current position of the buffer;
*
*///----------------------------------------------------------------------
set: function(i,v){
if(i.constructor === Array){
this.buffer = (v)?$.map(i, function(e){return e}):i;
}else{
this.buffer[i] = v;
}
},
/*-------------------------------------------------------------------------
*
* reset
*
*-------------------------------------------------------------------------
*
* Resets, returns back to the inital mask, all/some/one part of the
* current buffer depending on inputs
*
*///----------------------------------------------------------------------
reset: function(){
var start, end;
switch(arguments.length){
case 0 : start = 0; end = this.buffer.length; break;
case 1 : start = end = arguments[0]; break;
case 2 : start = arguments[0]; end = arguments[1]; break;
}
for(var i = start; i <= end; i++){
this.buffer[i] = this.initial[i];
}
},
/*-------------------------------------------------------------------------
*
* test
*
*-------------------------------------------------------------------------
*
* Test current buffer state against the complete RegExp of the field to
* determine if it is invliad/incomplete
*
*///----------------------------------------------------------------------
test: function(){
return this.fullRegEx.test(this.buffer.join(''));
}
}
/*-----------------------------------------------------------------------------
*
* Public API
*
*-----------------------------------------------------------------------------
*
* Extend the core jQuery object to allow access to the public functions
* for the plugin functionality
*
*///--------------------------------------------------------------------------
$.extend({
/* $.fn.mask
* $.fn.unmask
* $.applyMasks
*/
mask : {
//-- CONFIGURATION ACCESSORS ------------------------------------------
availableMasks : availableMasks,
options : defaultOptions,
/*---------------------------------------------------------------------
*
* Unistall plugin
*
*---------------------------------------------------------------------
*
* Unistall the entire plugin by deregistering all events and data
* caches in the document but also delete the objects from memory.
*
*///------------------------------------------------------------------
uninstall: function(){
/* UNMASK */
$.annotated("@Mask", document).unmask();
/* GARBAGE COLLECT */
delete(availableMasks);
delete($.applyMasks);
delete($.fn.mask);
delete($.fn.unmask);
delete(defaultOptions);
delete(Carat);
delete(MaskBuffer);
delete($.carat);
delete($.mask);
}
},
carat : {
get : Carat.getCaratPosition,
set : Carat.setCaratPosition
}
});
})(jQuery);
以上是关于JavaScript InputMask jQuery插件的主要内容,如果未能解决你的问题,请参考以下文章
RobinHerbots jquery.inputmask 日期范围