lk.zachem.info/resources/js/phone-format.js

81 lines
3.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function initPhoneMask(selector = 'input[type="tel"]') {
const format = (digits) => {
// Пример маски: +7 (999) 123-45-67
const d = digits.slice(0, 11); // ограничим 11 цифрами (под РФ)
if (!d.length) return '';
// если начали вводить с 8/7 — приведём к +7
let rest = d;
let prefix = '+7';
if (d[0] === '8') rest = '7' + d.slice(1);
if (rest[0] === '7') rest = rest.slice(1);
else {
// если первая цифра не 7, считаем что пользователь вводит локально, но всё равно показываем +7
// (при желании можно тут менять логику)
}
const a = rest.slice(0, 3);
const b = rest.slice(3, 6);
const c = rest.slice(6, 8);
const e = rest.slice(8, 10);
let out = prefix;
if (a) out += ` (${a}`;
if (a && a.length === 3) out += `)`;
if (b) out += ` ${b}`;
if (c) out += `-${c}`;
if (e) out += `-${e}`;
return out;
};
const applyToInput = (input) => {
if (input.dataset.phoneMasked === '1') return;
input.dataset.phoneMasked = '1';
// Подсказки браузеру: tel-поле и события input/change поддерживаются стандартно [web:2]
input.autocomplete = input.autocomplete || 'tel';
input.inputMode = input.inputMode || 'tel'; // подсказка клавиатуры, особенно на мобилках [web:12]
const handler = () => {
const digits = input.value.replace(/\D/g, '');
input.value = format(digits);
};
input.addEventListener('input', handler); // события input/change для tel описаны в MDN [web:2]
input.addEventListener('change', handler); // [web:2]
};
// 1) применяем ко всем уже существующим
document.querySelectorAll(selector).forEach(applyToInput);
// 2) применяем к добавляемым динамически
const mo = new MutationObserver((mutations) => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (!(node instanceof Element)) continue;
if (node.matches?.(selector)) applyToInput(node);
node.querySelectorAll?.(selector).forEach(applyToInput);
}
}
});
mo.observe(document.documentElement, { childList: true, subtree: true });
return () => mo.disconnect();
}
// запуск
initPhoneMask();
function runOnDomUpdate(fn, root = document.documentElement) {
const observer = new MutationObserver((mutations) => {
// если важно “не дергать” лишний раз — фильтруем
if (mutations.some(m => m.type === 'childList' && (m.addedNodes.length || m.removedNodes.length))) {
fn();
}
});
observer.observe(root, { childList: true, subtree: true }); // childList/subtree — ключевые опции [web:16]
return () => observer.disconnect();
}
// пример: заново применить маску к новым инпутам
const stop = runOnDomUpdate(() => initPhoneMask());