mirror of
https://github.com/tenrok/maska.git
synced 2026-06-17 19:21:21 +03:00
Initial commit
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import Maska from './maska'
|
||||
import { isString } from './utils'
|
||||
|
||||
function getOpts (mask) {
|
||||
const opts = {}
|
||||
|
||||
if (isString(mask)) {
|
||||
opts.mask = mask
|
||||
} else if (mask.mask) {
|
||||
opts.mask = mask.mask
|
||||
opts.tokens = mask.tokens ? mask.tokens : {}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
function needUpdate (mask) {
|
||||
if (isString(mask.value) && isString(mask.oldValue) && mask.value === mask.oldValue) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (mask.value && mask.oldValue && mask.value.mask === mask.oldValue.mask) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export default function directive (el, mask) {
|
||||
if (!mask.value) return
|
||||
|
||||
if (mask.value && needUpdate(mask)) {
|
||||
return new Maska(el, getOpts(mask.value))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import directive from './directive'
|
||||
import mask from './mask'
|
||||
import Maska from './maska'
|
||||
import tokens from './tokens'
|
||||
|
||||
function install (Vue) {
|
||||
Vue.directive('maska', directive)
|
||||
}
|
||||
// Install by default if included from script tag
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
window.Vue.use(install)
|
||||
}
|
||||
|
||||
function create (el, options) {
|
||||
return new Maska(el, options)
|
||||
}
|
||||
|
||||
export default install
|
||||
export {
|
||||
create,
|
||||
mask,
|
||||
directive as maska,
|
||||
tokens
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
export default function mask (value, mask, tokens, masked = true) {
|
||||
let im = 0
|
||||
let iv = 0
|
||||
let ret = ''
|
||||
let rest = ''
|
||||
|
||||
while (im < mask.length && iv < value.length) {
|
||||
let maskChar = mask[im]
|
||||
const valueChar = value[iv]
|
||||
const token = tokens[maskChar]
|
||||
|
||||
if (token && token.pattern) {
|
||||
if (token.pattern.test(valueChar)) {
|
||||
ret += tokenTransform(valueChar, token)
|
||||
im++
|
||||
}
|
||||
iv++
|
||||
} else if (token && token.repeat) {
|
||||
const maskCharPrev = mask[im - 1]
|
||||
const tokenPrev = tokens[maskCharPrev]
|
||||
if (token && token.repeat && tokenPrev && !tokenPrev.pattern.test(valueChar)) {
|
||||
im++
|
||||
} else {
|
||||
im--
|
||||
}
|
||||
} else {
|
||||
if (token && token.escape) {
|
||||
im++
|
||||
maskChar = mask[im]
|
||||
}
|
||||
if (masked) ret += maskChar
|
||||
if (valueChar === maskChar) iv++
|
||||
im++
|
||||
}
|
||||
}
|
||||
|
||||
// fix mask that ends with parentesis
|
||||
while (masked && im < mask.length) { // eslint-disable-line no-unmodified-loop-condition
|
||||
const maskCharRest = mask[im]
|
||||
if (tokens[maskCharRest] && !tokens[maskCharRest].repeat) {
|
||||
rest = ''
|
||||
break
|
||||
}
|
||||
if (!tokens[maskCharRest]) {
|
||||
rest += maskCharRest
|
||||
}
|
||||
im++
|
||||
}
|
||||
|
||||
return ret + rest
|
||||
}
|
||||
|
||||
function tokenTransform (value, token) {
|
||||
if (token.uppercase) {
|
||||
return value.toLocaleUpperCase()
|
||||
} else if (token.lowercase) {
|
||||
return value.toLocaleLowerCase()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import mask from './mask'
|
||||
import tokens from './tokens'
|
||||
import { event, findInputElement, fixInputSelection, isString } from './utils'
|
||||
|
||||
export default class Maska {
|
||||
constructor (el, opts = {}) {
|
||||
if (!el) throw new Error('Maska: no element for mask')
|
||||
|
||||
if (opts.tokens) {
|
||||
for (const i in opts.tokens) {
|
||||
opts.tokens[i] = { ...opts.tokens[i] }
|
||||
if (opts.tokens[i].pattern && isString(opts.tokens[i].pattern)) {
|
||||
opts.tokens[i].pattern = new RegExp(opts.tokens[i].pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._opts = {
|
||||
mask: opts.mask,
|
||||
tokens: { ...tokens, ...opts.tokens }
|
||||
}
|
||||
this._el = isString(el) ? document.querySelectorAll(el) : !el.length ? [el] : el
|
||||
|
||||
this.init()
|
||||
}
|
||||
|
||||
init () {
|
||||
for (let i = 0; i < this._el.length; i++) {
|
||||
const el = findInputElement(this._el[i])
|
||||
if (!el.dataset.mask && this._opts.mask) {
|
||||
el.dataset.mask = this._opts.mask
|
||||
}
|
||||
this.updateValue(el)
|
||||
el.addEventListener('input', evt => this.onInput(evt))
|
||||
}
|
||||
}
|
||||
|
||||
destroy () {
|
||||
for (let i = 0; i < this._el.length; i++) {
|
||||
const el = findInputElement(this._el[i])
|
||||
el.removeEventListener('input', evt => this.onInput(evt))
|
||||
delete el.dataset.mask
|
||||
}
|
||||
}
|
||||
|
||||
updateValue (el) {
|
||||
if (!el.value || !el.dataset.mask) return
|
||||
|
||||
const position = el.selectionEnd
|
||||
const digit = el.value[position - 1]
|
||||
el.value = mask(el.value, el.dataset.mask, this._opts.tokens)
|
||||
fixInputSelection(el, position, digit)
|
||||
el.dispatchEvent(event('input'))
|
||||
}
|
||||
|
||||
onInput (event) {
|
||||
if (event.isTrusted) {
|
||||
this.updateValue(event.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/* eslint quote-props: ["error", "consistent"] */
|
||||
export default {
|
||||
'#': { pattern: /[0-9]/ },
|
||||
'X': { pattern: /[0-9a-zA-Z]/ },
|
||||
'S': { pattern: /[a-zA-Z]/ },
|
||||
'A': { pattern: /[a-zA-Z]/, uppercase: true },
|
||||
'a': { pattern: /[a-zA-Z]/, lowercase: true },
|
||||
'!': { escape: true },
|
||||
'*': { repeat: true }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/* global HTMLInputElement */
|
||||
|
||||
function event (name) {
|
||||
const event = document.createEvent('Event')
|
||||
event.initEvent(name, true, true)
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
function findInputElement (el) {
|
||||
return (el instanceof HTMLInputElement) ? el : el.querySelector('input') || el
|
||||
}
|
||||
|
||||
function fixInputSelection (el, position, digit) {
|
||||
while (position < el.value.length && el.value.charAt(position - 1) !== digit) {
|
||||
position++
|
||||
}
|
||||
|
||||
if (el === document.activeElement) {
|
||||
el.setSelectionRange(position, position)
|
||||
setTimeout(function () {
|
||||
el.setSelectionRange(position, position)
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
|
||||
function isString (val) {
|
||||
return Object.prototype.toString.call(val) === '[object String]'
|
||||
}
|
||||
|
||||
export { event, findInputElement, fixInputSelection, isString }
|
||||
Reference in New Issue
Block a user