Last active
September 3, 2021 06:36
-
-
Save sertraline/4bde068c19d8b3a029958127b7ba814e to your computer and use it in GitHub Desktop.
Pure javascript phone mask. Supports backspacing as well as selection backspacing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class PhoneField { | |
constructor( | |
handler, | |
code = '+7', | |
mask = '(___)___-__-__', | |
placeholder = '_' | |
) { | |
this.handler = handler; | |
this.mask = code + mask; | |
this.code = code; | |
this.placeholder = placeholder; | |
this.setLength(); | |
this.setValue(); | |
this.start = this.placeHolderPosition() - 1; | |
this.handler.addEventListener('focusin', () => { | |
this.focused(); | |
}); | |
this.handler.addEventListener('keydown', (d) => { | |
this.input(d); | |
}); | |
} | |
focused() { | |
let a = this.placeHolderPosition(); | |
(this.handler.selectionStart = a), (this.handler.selectionEnd = a); | |
} | |
input(a) { | |
if ( | |
(this.isDirectionKey(a.key) || a.preventDefault(), | |
this.isNum(a.key)) | |
) | |
this.changeChar(a.key); | |
else if (this.isDeletionKey(a.key)) | |
if ('Backspace' === a.key) { | |
let text = this.getSelectionText(); | |
if (text.length === 0) { | |
this.changeChar(this.placeholder, -1, this.start); | |
} else { | |
this.clear(this.getSelectionText()); | |
} | |
} else this.changeChar(this.placeholder); | |
} | |
getSelectionText() { | |
let text = ''; | |
if (window.getSelection) { | |
text = window.getSelection().toString(); | |
} else if ( | |
document.selection && | |
document.selection.type !== 'Control' | |
) { | |
text = document.selection.createRange().text; | |
} | |
return text; | |
} | |
setLength() { | |
this.handler.maxLength = this.mask.length; | |
} | |
setValue() { | |
this.handler.value = this.mask; | |
} | |
isNum(a) { | |
return ( | |
!isNaN(a) && parseInt(+a) === parseInt(a) && !isNaN(parseInt(a, 10)) | |
); | |
} | |
isDeletionKey(a) { | |
return 'Delete' === a || 'Backspace' === a; | |
} | |
isDirectionKey(a) { | |
return ( | |
'ArrowUp' === a || | |
'ArrowDown' === a || | |
'ArrowRight' === a || | |
'ArrowLeft' === a || | |
'Tab' === a | |
); | |
} | |
isPlaceholder(a) { | |
return a === this.placeholder; | |
} | |
placeHolderPosition() { | |
return this.handler.value.indexOf(this.placeholder); | |
} | |
clear(text) { | |
let start = this.handler.selectionStart - this.code.length; | |
let value = this.handler.value; | |
value = value.slice(this.code.length); | |
let start_string = value.substring(0, start); | |
let replace_string = value.substring(start, start + text.length); | |
let end_string = value.substring(start + text.length, value.length); | |
replace_string = replace_string.split(''); | |
for (let i = 0; i < replace_string.length; i++) { | |
if (!isNaN(replace_string[i])) { | |
replace_string[i] = this.placeholder; | |
} | |
} | |
this.handler.value = | |
this.code + start_string + replace_string.join('') + end_string; | |
this.handler.selectionStart = start + this.code.length; | |
this.handler.selectionEnd = start + this.code.length; | |
if (this.handler.selectionEnd < 1) { | |
this.handler.selectionStart = this.code.length + 1; | |
this.handler.selectionEnd = this.code.length + 1; | |
} | |
} | |
changeChar(a, b = 1, len = this.mask.length) { | |
let value = this.handler.value; | |
let sel_start = | |
0 < b | |
? this.handler.selectionStart | |
: this.handler.selectionStart - 1; | |
let g = ''; | |
if (sel_start === len) return !1; | |
if (sel_start <= this.code.length - 1) return !1; | |
if ( | |
!this.isNum(value[sel_start]) && | |
!this.isPlaceholder(value[sel_start]) | |
) { | |
do | |
if (((sel_start += b), sel_start === len)) { | |
return !1; | |
} | |
while ( | |
!this.isNum(value[sel_start]) && | |
!this.isPlaceholder(value[sel_start]) | |
); | |
} | |
g = this.replaceAt(value, sel_start, a); | |
this.handler.value = g; | |
0 < b && (sel_start += b); | |
this.handler.selectionStart = sel_start; | |
this.handler.selectionEnd = sel_start; | |
} | |
replaceAt(a, b, c) { | |
return a.substring(0, b) + c + a.substring(++b); | |
} | |
} | |
// DOM | |
<input | |
type="tel" | |
name="tel[]" | |
class="masked-phone" | |
data-phonemask="(___)___-__-__" | |
data-code="+38" | |
/> | |
let a = document.getElementsByClassName('masked-phone'), | |
b = []; | |
for (let c = 0; c < a.length; c++) | |
b.push( | |
new PhoneField( | |
a[c], | |
a[c].dataset.code, | |
a[c].dataset.phonemask, | |
a[c].dataset.placeholder | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment