@@ -2283,58 +2283,141 @@ var datetimepickerFactory = function ($) {
22832283 setCaretPos ( input [ 0 ] , 0 ) ;
22842284 }
22852285
2286- input . on ( 'keydown.xdsoft' , function ( event ) {
2287- var val = this . value ,
2288- key = event . which ,
2289- pos ,
2290- digit ;
2291-
2292- if ( ( ( key >= KEY0 && key <= KEY9 ) || ( key >= _KEY0 && key <= _KEY9 ) ) || ( key === BACKSPACE || key === DEL ) ) {
2293- pos = getCaretPos ( this ) ;
2294- digit = ( key !== BACKSPACE && key !== DEL ) ? String . fromCharCode ( ( _KEY0 <= key && key <= _KEY9 ) ? key - KEY0 : key ) : '_' ;
2295-
2296- if ( ( key === BACKSPACE || key === DEL ) && pos ) {
2297- pos -= 1 ;
2298- digit = '_' ;
2299- }
2286+ input . on ( 'paste.xdsoft' , function ( event ) {
2287+ // couple options here
2288+ // 1. return false - tell them they can't paste
2289+ // 2. insert over current characters - minimal validation
2290+ // 3. full fledged parsing and validation
2291+ // let's go option 2 for now
2292+
2293+ // fires multiple times for some reason
2294+
2295+ // https://stackoverflow.com/a/30496488/1366033
2296+ var clipboardData = event . clipboardData || event . originalEvent . clipboardData || window . clipboardData ,
2297+ pastedData = clipboardData . getData ( 'text' ) ,
2298+ val = this . value ,
2299+ pos = this . selectionStart
2300+
2301+ var valueBeforeCursor = val . substr ( 0 , pos ) ;
2302+ var valueAfterPaste = val . substr ( pos + pastedData . length ) ;
2303+
2304+ val = valueBeforeCursor + pastedData + valueAfterPaste ;
2305+ pos += pastedData . length ;
2306+
2307+ if ( isValidValue ( options . mask , val ) ) {
2308+ this . value = val ;
2309+ setCaretPos ( this , pos ) ;
2310+ } else if ( $ . trim ( val ) === '' ) {
2311+ this . value = options . mask . replace ( / [ 0 - 9 ] / g, '_' ) ;
2312+ } else {
2313+ input . trigger ( 'error_input.xdsoft' ) ;
2314+ }
2315+
2316+ event . preventDefault ( ) ;
2317+ return false ;
2318+ } ) ;
2319+
2320+ input . on ( 'keydown.xdsoft' , function ( event ) {
2321+ var val = this . value ,
2322+ key = event . which ,
2323+ pos = this . selectionStart ,
2324+ selEnd = this . selectionEnd ,
2325+ hasSel = pos !== selEnd ,
2326+ digit ;
2327+
2328+ // only alow these characters
2329+ if ( ( ( key >= KEY0 && key <= KEY9 ) ||
2330+ ( key >= _KEY0 && key <= _KEY9 ) ) ||
2331+ ( key === BACKSPACE || key === DEL ) ) {
2332+
2333+ // get char to insert which is new character or placeholder ('_')
2334+ digit = ( key === BACKSPACE || key === DEL ) ? '_' :
2335+ String . fromCharCode ( ( _KEY0 <= key && key <= _KEY9 ) ? key - KEY0 : key ) ;
2336+
2337+ // we're deleting something, we're not at the start, and have normal cursor, move back one
2338+ // if we have a selection length, cursor actually sits behind deletable char, not in front
2339+ if ( key === BACKSPACE && pos && ! hasSel ) {
2340+ pos -= 1 ;
2341+ }
23002342
2301- while ( / [ ^ 0 - 9 _ ] / . test ( options . mask . substr ( pos , 1 ) ) && pos < options . mask . length && pos > 0 ) {
2302- pos += ( key === BACKSPACE || key === DEL ) ? - 1 : 1 ;
2303- }
2343+ // don't stop on a separator, continue whatever direction you were going
2344+ // value char - keep incrementing position while on separator char and we still have room
2345+ // del char - keep decrementing position while on separator char and we still have room
2346+ while ( true ) {
2347+ var maskValueAtCurPos = options . mask . substr ( pos , 1 ) ;
2348+ var posShorterThanMaskLength = pos < options . mask . length ;
2349+ var posGreaterThanZero = pos > 0 ;
2350+ var notNumberOrPlaceholder = / [ ^ 0 - 9 _ ] / ;
2351+ var curPosOnSep = notNumberOrPlaceholder . test ( maskValueAtCurPos ) ;
2352+ var continueMovingPosition = curPosOnSep && posShorterThanMaskLength && posGreaterThanZero
23042353
2305- val = val . substr ( 0 , pos ) + digit + val . substr ( pos + 1 ) ;
2354+ // if we hit a real char, stay where we are
2355+ if ( ! continueMovingPosition ) break ;
23062356
2307- if ( $ . trim ( val ) === '' ) {
2308- val = options . mask . replace ( / [ 0 - 9 ] / g, '_' ) ;
2309- } else {
2310- if ( pos === options . mask . length ) {
2311- event . preventDefault ( ) ;
2312- return false ;
2313- }
2314- }
2357+ // hitting backspace in a selection, you can possibly go back any further - go forward
2358+ pos += ( key === BACKSPACE && ! hasSel ) ? - 1 : 1 ;
23152359
2316- pos += ( key === BACKSPACE || key === DEL ) ? 0 : 1 ;
2317- while ( / [ ^ 0 - 9 _ ] / . test ( options . mask . substr ( pos , 1 ) ) && pos < options . mask . length && pos > 0 ) {
2318- pos += ( key === BACKSPACE || key === DEL ) ? - 1 : 1 ;
2319- }
2360+ }
2361+
2362+
2363+ if ( hasSel ) {
2364+ // pos might have moved so re-calc length
2365+ var selLength = selEnd - pos
2366+
2367+ // if we have a selection length we will wipe out entire selection and replace with default template for that range
2368+ var defaultBlank = options . mask . replace ( / [ 0 - 9 ] / g, '_' ) ;
2369+ var defaultBlankSelectionReplacement = defaultBlank . substr ( pos , selLength ) ;
2370+ var selReplacementRemainder = defaultBlankSelectionReplacement . substr ( 1 ) // might be empty
2371+
2372+ var valueBeforeSel = val . substr ( 0 , pos ) ;
2373+ var insertChars = digit + selReplacementRemainder ;
2374+ var charsAfterSelection = val . substr ( pos + selLength ) ;
2375+
2376+ val = valueBeforeSel + insertChars + charsAfterSelection
23202377
2321- if ( isValidValue ( options . mask , val ) ) {
2322- this . value = val ;
2323- setCaretPos ( this , pos ) ;
2324- } else if ( $ . trim ( val ) === '' ) {
2325- this . value = options . mask . replace ( / [ 0 - 9 ] / g, '_' ) ;
2326- } else {
2327- input . trigger ( 'error_input.xdsoft' ) ;
2328- }
23292378 } else {
2330- if ( ( [ AKEY , CKEY , VKEY , ZKEY , YKEY ] . indexOf ( key ) !== - 1 && ctrlDown ) || [ ESC , ARROWUP , ARROWDOWN , ARROWLEFT , ARROWRIGHT , F5 , CTRLKEY , TAB , ENTER ] . indexOf ( key ) !== - 1 ) {
2331- return true ;
2332- }
2379+ var valueBeforeCursor = val . substr ( 0 , pos ) ;
2380+ var insertChar = digit ;
2381+ var valueAfterNextChar = val . substr ( pos + 1 ) ;
2382+
2383+ val = valueBeforeCursor + insertChar + valueAfterNextChar
23332384 }
23342385
2335- event . preventDefault ( ) ;
2336- return false ;
2337- } ) ;
2386+ if ( $ . trim ( val ) === '' ) {
2387+ // if empty, set to default
2388+ val = defaultBlank
2389+ } else {
2390+ // if at the last character don't need to do anything
2391+ if ( pos === options . mask . length ) {
2392+ event . preventDefault ( ) ;
2393+ return false ;
2394+ }
2395+ }
2396+
2397+ // resume cursor location
2398+ pos += ( key === BACKSPACE ) ? 0 : 1 ;
2399+ // don't stop on a separator, continue whatever direction you were going
2400+ while ( / [ ^ 0 - 9 _ ] / . test ( options . mask . substr ( pos , 1 ) ) && pos < options . mask . length && pos > 0 ) {
2401+ pos += ( key === BACKSPACE ) ? 0 : 1 ;
2402+ }
2403+
2404+ if ( isValidValue ( options . mask , val ) ) {
2405+ this . value = val ;
2406+ setCaretPos ( this , pos ) ;
2407+ } else if ( $ . trim ( val ) === '' ) {
2408+ this . value = options . mask . replace ( / [ 0 - 9 ] / g, '_' ) ;
2409+ } else {
2410+ input . trigger ( 'error_input.xdsoft' ) ;
2411+ }
2412+ } else {
2413+ if ( ( [ AKEY , CKEY , VKEY , ZKEY , YKEY ] . indexOf ( key ) !== - 1 && ctrlDown ) || [ ESC , ARROWUP , ARROWDOWN , ARROWLEFT , ARROWRIGHT , F5 , CTRLKEY , TAB , ENTER ] . indexOf ( key ) !== - 1 ) {
2414+ return true ;
2415+ }
2416+ }
2417+
2418+ event . preventDefault ( ) ;
2419+ return false ;
2420+ } ) ;
23382421 }
23392422 }
23402423
0 commit comments