2025-09-24 06:24:52 +00:00
/ *
* Input Mask Core
* http : //github.com/RobinHerbots/jquery.inputmask
* Copyright ( c ) Robin Herbots
* Licensed under the MIT license
* /
2025-10-03 11:00:05 +00:00
import { mask } from "./mask" ;
2025-09-24 06:24:52 +00:00
import $ from "./dependencyLibs/inputmask.dependencyLib" ;
import window from "./global/window" ;
2025-10-03 11:00:05 +00:00
import { generateMaskSet , analyseMask } from "./mask-lexer" ;
import { getMaskTemplate } from "./validation-tests" ;
import { determineLastRequiredPosition , getBuffer , getBufferTemplate , isMask } from "./positioning" ;
import { isComplete } from "./validation" ;
import { checkVal , unmaskedvalue } from "./inputHandling" ;
import { EventRuler } from "./eventruler" ;
import definitions from "./definitions" ;
import defaults from "./defaults" ;
import canUseDOM from "./canUseDOM" ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
const document = window . document , dataKey = "_inputmask_opts" ;
2025-09-24 06:24:52 +00:00
function Inputmask ( alias , options , internal ) {
2025-10-03 11:00:05 +00:00
if ( ! canUseDOM ) {
return ;
}
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
//allow instanciating without new
if ( ! ( this instanceof Inputmask ) ) {
return new Inputmask ( alias , options , internal ) ;
}
this . dependencyLib = $ ;
this . el = undefined ;
this . events = { } ;
this . maskset = undefined ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
if ( internal !== true ) {
//init options
if ( Object . prototype . toString . call ( alias ) === "[object Object]" ) {
options = alias ;
} else {
options = options || { } ;
if ( alias ) options . alias = alias ;
}
this . opts = $ . extend ( true , { } , this . defaults , options ) ;
this . noMasksCache = options && options . definitions !== undefined ;
this . userOptions = options || { } ; //user passed options
resolveAlias ( this . opts . alias , options , this . opts ) ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
//maskscope properties
this . refreshValue = false ; //indicate a refresh from the inputvalue is needed (form.reset)
this . undoValue = undefined ;
this . $el = undefined ;
this . skipInputEvent = false ; //skip when triggered from within inputmask
this . validationEvent = false ;
this . ignorable = false ;
this . maxLength ;
this . mouseEnter = false ;
this . clicked = 0 ;
this . originalPlaceholder = undefined ; //needed for FF
this . isComposing = false , //keydowncode == 229 compositionevent fallback
this . hasAlternator = false ;
2025-09-24 06:24:52 +00:00
}
Inputmask . prototype = {
2025-10-03 11:00:05 +00:00
dataAttribute : "data-inputmask" , //data attribute prefix used for attribute binding
//options default
defaults : defaults ,
definitions : definitions ,
aliases : { } , //aliases definitions
masksCache : { } ,
get isRTL ( ) {
return this . opts . isRTL || this . opts . numericInput ;
} ,
mask : function ( elems ) {
var that = this ;
if ( typeof elems === "string" ) {
elems = ( document . getElementById ( elems ) || document . querySelectorAll ( elems ) ) ;
}
elems = elems . nodeName ? [ elems ] : ( Array . isArray ( elems ) ? elems : [ ] . slice . call ( elems ) ) ; //[].slice as alternate for Array.from (Yandex browser)
elems . forEach ( function ( el , ndx ) {
var scopedOpts = $ . extend ( true , { } , that . opts ) ;
if ( importAttributeOptions ( el , scopedOpts , $ . extend ( true , { } , that . userOptions ) , that . dataAttribute ) ) {
var maskset = generateMaskSet ( scopedOpts , that . noMasksCache ) ;
if ( maskset !== undefined ) {
if ( el . inputmask !== undefined ) {
el . inputmask . opts . autoUnmask = true ; //force autounmasking when remasking
el . inputmask . remove ( ) ;
}
//store inputmask instance on the input with element reference
el . inputmask = new Inputmask ( undefined , undefined , true ) ;
el . inputmask . opts = scopedOpts ;
el . inputmask . noMasksCache = that . noMasksCache ;
el . inputmask . userOptions = $ . extend ( true , { } , that . userOptions ) ;
// el.inputmask.isRTL = scopedOpts.isRTL || scopedOpts.numericInput;
el . inputmask . el = el ;
el . inputmask . $el = $ ( el ) ;
el . inputmask . maskset = maskset ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
$ . data ( el , dataKey , that . userOptions ) ;
mask . call ( el . inputmask ) ;
}
}
} ) ;
return elems && elems [ 0 ] ? ( elems [ 0 ] . inputmask || this ) : this ;
} ,
option : function ( options , noremask ) { //set extra options || retrieve value of a current option
if ( typeof options === "string" ) {
return this . opts [ options ] ;
} else if ( typeof options === "object" ) {
$ . extend ( this . userOptions , options ) ; //user passed options
//remask
if ( this . el && noremask !== true ) {
this . mask ( this . el ) ;
}
return this ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
} ,
unmaskedvalue : function ( value ) {
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
if ( this . el === undefined || value !== undefined ) {
var valueBuffer = ( typeof this . opts . onBeforeMask === "function" ? ( this . opts . onBeforeMask . call ( this , value , this . opts ) || value ) : value ) . split ( "" ) ;
checkVal . call ( this , undefined , false , false , valueBuffer ) ;
if ( typeof this . opts . onBeforeWrite === "function" ) this . opts . onBeforeWrite . call ( this , undefined , getBuffer . call ( this ) , 0 , this . opts ) ;
}
return unmaskedvalue . call ( this , this . el ) ;
} ,
remove : function ( ) {
if ( this . el ) {
$ . data ( this . el , dataKey , null ) ; //invalidate
//writeout the value
var cv = this . opts . autoUnmask ? unmaskedvalue ( this . el ) : this . _valueGet ( this . opts . autoUnmask ) ;
if ( cv !== getBufferTemplate . call ( this ) . join ( "" ) ) this . _valueSet ( cv , this . opts . autoUnmask ) ; else this . _valueSet ( "" ) ;
//unbind all events
EventRuler . off ( this . el ) ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
//restore the value property
var valueProperty ;
if ( Object . getOwnPropertyDescriptor && Object . getPrototypeOf ) {
valueProperty = Object . getOwnPropertyDescriptor ( Object . getPrototypeOf ( this . el ) , "value" ) ;
if ( valueProperty ) {
if ( this . _ _valueGet ) {
Object . defineProperty ( this . el , "value" , {
get : this . _ _valueGet ,
set : this . _ _valueSet ,
configurable : true
} ) ;
}
}
} else if ( document . _ _lookupGetter _ _ && this . el . _ _lookupGetter _ _ ( "value" ) ) {
if ( this . _ _valueGet ) {
this . el . _ _defineGetter _ _ ( "value" , this . _ _valueGet ) ;
this . el . _ _defineSetter _ _ ( "value" , this . _ _valueSet ) ;
}
}
//clear data
this . el . inputmask = undefined ;
}
return this . el ;
} ,
getemptymask : function ( ) { //return the default (empty) mask value, usefull for setting the default value in validation
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
return ( this . isRTL ? getBufferTemplate . call ( this ) . reverse ( ) : getBufferTemplate . call ( this ) ) . join ( "" ) ;
} ,
hasMaskedValue : function ( ) { //check wheter the returned value is masked or not; currently only works reliable when using jquery.val fn to retrieve the value
return ! this . opts . autoUnmask ;
} ,
isComplete : function ( ) {
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
return isComplete . call ( this , getBuffer . call ( this ) ) ;
} ,
getmetadata : function ( ) { //return mask metadata if exists
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
if ( Array . isArray ( this . maskset . metadata ) ) {
var maskTarget = getMaskTemplate . call ( this , true , 0 , false ) . join ( "" ) ;
this . maskset . metadata . forEach ( function ( mtdt ) {
if ( mtdt . mask === maskTarget ) {
maskTarget = mtdt ;
return false ;
}
return true ;
2025-09-24 06:24:52 +00:00
} ) ;
2025-10-03 11:00:05 +00:00
return maskTarget ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
return this . maskset . metadata ;
} ,
isValid : function ( value ) {
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
if ( value ) {
var valueBuffer = ( typeof this . opts . onBeforeMask === "function" ? ( this . opts . onBeforeMask . call ( this , value , this . opts ) || value ) : value ) . split ( "" ) ;
checkVal . call ( this , undefined , true , false , valueBuffer ) ;
} else {
value = this . isRTL ? getBuffer . call ( this ) . slice ( ) . reverse ( ) . join ( "" ) : getBuffer . call ( this ) . join ( "" ) ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
var buffer = getBuffer . call ( this ) ;
var rl = determineLastRequiredPosition . call ( this ) ,
lmib = buffer . length - 1 ;
for ( ; lmib > rl ; lmib -- ) {
if ( isMask . call ( this , lmib ) ) break ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
buffer . splice ( rl , lmib + 1 - rl ) ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
return isComplete . call ( this , buffer ) && value === ( this . isRTL ? getBuffer . call ( this ) . slice ( ) . reverse ( ) . join ( "" ) : getBuffer . call ( this ) . join ( "" ) ) ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
} ,
format : function ( value , metadata ) {
this . maskset = this . maskset || generateMaskSet ( this . opts , this . noMasksCache ) ;
let valueBuffer = ( typeof this . opts . onBeforeMask === "function" ? ( this . opts . onBeforeMask . call ( this , value , this . opts ) || value ) : value ) . split ( "" ) ;
checkVal . call ( this , undefined , true , false , valueBuffer ) ;
let formattedValue = this . isRTL ? getBuffer . call ( this ) . slice ( ) . reverse ( ) . join ( "" ) : getBuffer . call ( this ) . join ( "" ) ;
return metadata ? {
value : formattedValue ,
metadata : this . getmetadata ( )
} : formattedValue ;
} ,
setValue : function ( value ) {
if ( this . el ) {
$ ( this . el ) . trigger ( "setvalue" , [ value ] ) ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
} ,
analyseMask : analyseMask
2025-09-24 06:24:52 +00:00
} ;
function resolveAlias ( aliasStr , options , opts ) {
2025-10-03 11:00:05 +00:00
var aliasDefinition = Inputmask . prototype . aliases [ aliasStr ] ;
if ( aliasDefinition ) {
if ( aliasDefinition . alias ) resolveAlias ( aliasDefinition . alias , undefined , opts ) ; //alias is another alias
$ . extend ( true , opts , aliasDefinition ) ; //merge alias definition in the options
$ . extend ( true , opts , options ) ; //reapply extra given options
return true ;
} else //alias not found - try as mask
if ( opts . mask === null ) {
opts . mask = aliasStr ;
}
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
return false ;
2025-09-24 06:24:52 +00:00
}
function importAttributeOptions ( npt , opts , userOptions , dataAttribute ) {
2025-10-03 11:00:05 +00:00
function importOption ( option , optionData ) {
const attrOption = dataAttribute === "" ? option : dataAttribute + "-" + option ;
optionData = optionData !== undefined ? optionData : npt . getAttribute ( attrOption ) ;
if ( optionData !== null ) {
if ( typeof optionData === "string" ) {
if ( option . indexOf ( "on" ) === 0 ) {
optionData = window [ optionData ] ;
} //get function definition
else if ( optionData === "false" ) {
optionData = false ;
} else if ( optionData === "true" ) optionData = true ;
}
userOptions [ option ] = optionData ;
}
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
if ( opts . importDataAttributes === true ) {
var attrOptions = npt . getAttribute ( dataAttribute ) , option , dataoptions , optionData , p ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
if ( attrOptions && attrOptions !== "" ) {
attrOptions = attrOptions . replace ( /'/g , "\"" ) ;
dataoptions = JSON . parse ( "{" + attrOptions + "}" ) ;
}
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
//resolve aliases
if ( dataoptions ) { //pickup alias from dataAttribute
optionData = undefined ;
for ( p in dataoptions ) {
if ( p . toLowerCase ( ) === "alias" ) {
optionData = dataoptions [ p ] ;
break ;
}
}
}
importOption ( "alias" , optionData ) ; //pickup alias from dataAttribute-alias
if ( userOptions . alias ) {
resolveAlias ( userOptions . alias , userOptions , opts ) ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
for ( option in opts ) {
if ( dataoptions ) {
optionData = undefined ;
for ( p in dataoptions ) {
if ( p . toLowerCase ( ) === option . toLowerCase ( ) ) {
optionData = dataoptions [ p ] ;
break ;
}
}
}
importOption ( option , optionData ) ;
2025-09-24 06:24:52 +00:00
}
}
2025-10-03 11:00:05 +00:00
$ . extend ( true , opts , userOptions ) ;
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
//handle dir=rtl
if ( npt . dir === "rtl" || opts . rightAlign ) {
npt . style . textAlign = "right" ;
}
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
if ( npt . dir === "rtl" || opts . numericInput ) {
npt . dir = "ltr" ;
npt . removeAttribute ( "dir" ) ;
opts . isRTL = true ;
}
2025-09-24 06:24:52 +00:00
2025-10-03 11:00:05 +00:00
return Object . keys ( userOptions ) . length ;
2025-09-24 06:24:52 +00:00
}
2025-10-03 11:00:05 +00:00
//apply defaults, definitions, aliases
2025-09-24 06:24:52 +00:00
Inputmask . extendDefaults = function ( options ) {
2025-10-03 11:00:05 +00:00
$ . extend ( true , Inputmask . prototype . defaults , options ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . extendDefinitions = function ( definition ) {
2025-10-03 11:00:05 +00:00
$ . extend ( true , Inputmask . prototype . definitions , definition ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . extendAliases = function ( alias ) {
2025-10-03 11:00:05 +00:00
$ . extend ( true , Inputmask . prototype . aliases , alias ) ;
2025-09-24 06:24:52 +00:00
} ;
2025-10-03 11:00:05 +00:00
//static fn on inputmask
2025-09-24 06:24:52 +00:00
Inputmask . format = function ( value , options , metadata ) {
2025-10-03 11:00:05 +00:00
return Inputmask ( options ) . format ( value , metadata ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . unmask = function ( value , options ) {
2025-10-03 11:00:05 +00:00
return Inputmask ( options ) . unmaskedvalue ( value ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . isValid = function ( value , options ) {
2025-10-03 11:00:05 +00:00
return Inputmask ( options ) . isValid ( value ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . remove = function ( elems ) {
2025-10-03 11:00:05 +00:00
if ( typeof elems === "string" ) {
elems = document . getElementById ( elems ) || document . querySelectorAll ( elems ) ;
}
elems = elems . nodeName ? [ elems ] : elems ;
elems . forEach ( function ( el ) {
if ( el . inputmask ) el . inputmask . remove ( ) ;
} ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . setValue = function ( elems , value ) {
2025-10-03 11:00:05 +00:00
if ( typeof elems === "string" ) {
elems = document . getElementById ( elems ) || document . querySelectorAll ( elems ) ;
}
elems = elems . nodeName ? [ elems ] : elems ;
elems . forEach ( function ( el ) {
if ( el . inputmask ) el . inputmask . setValue ( value ) ; else $ ( el ) . trigger ( "setvalue" , [ value ] ) ;
} ) ;
2025-09-24 06:24:52 +00:00
} ;
Inputmask . dependencyLib = $ ;
2025-10-03 11:00:05 +00:00
//make inputmask available
2025-09-24 06:24:52 +00:00
window . Inputmask = Inputmask ;
export default Inputmask ;