shido.forms.js
Version:
Utilities, formats and field validation rules
285 lines (218 loc) • 6.74 kB
JavaScript
import * as c from './console'
import './polyfill'
const secureKeys = [
'Backspace',
'Escape',
'Enter',
'ArrowUp',
'ArrowLeft',
'ArrowRight',
'ArrowDown',
' ',
'SPACE',
'Space',
'CapsLock',
'Shift',
'Meta',
'Alt',
'Control',
'Tab',
]
const formatBytes = (bytes, decimals) => {
if (bytes === 0)
return '0 Bytes'
const labels = [
'Bytes',
'KB',
'MB',
'GB',
'TB',
'PB',
'EB',
'ZB',
'YB'
]
const B = 1024
const dec = decimals <= 0 ? 0 : decimals || 2
const i = Math.floor(Math.log(bytes) / Math.log(B))
bytes = parseFloat((bytes / Math.pow(B, i)).toFixed(dec)) + ' ' + labels[i]
return bytes
}
const ifFieldIsEmpty = ($target, value, parentClass) => {
parentClass = '.' + parentClass
if (!$target.closest(parentClass))
return false
if ($target.value === "" || $target.value === null || $target.value === 'undefined') {
$target.closest(parentClass).classList.remove('filled')
$target.classList.remove('filled')
return false
}
$target.closest(parentClass).classList.add('filled')
$target.classList.add('filled')
}
const ifFocus = ($target, parentClass) => {
if (!$target.closest(parentClass))
return false
$target.closest(parentClass).classList.add('focus')
}
const ifBlur = ($target, parentClass) => {
if (!$target.closest(parentClass))
return false
$target.closest(parentClass).classList.remove('focus')
}
const ifFieldIsNumeric = (e, $target, key) => {
if (!$target.hasAttribute('numeric'))
return false
if (
e.metaKey && e.code == 'KeyC' || e.ctrlKey && e.code == 'KeyC' ||
e.metaKey && e.code == 'KeyV' || e.ctrlKey && e.code == 'KeyV' ||
e.metaKey && e.code == 'KeyX' || e.ctrlKey && e.code == 'KeyX'
)
return false
if (secureKeys.indexOf(key) >= 0)
return false
const validate = /^([0-9\.\,\-])$/.test(key)
if (!validate)
e.preventDefault()
}
const ifFieldIsDigits = (e, $target, key) => {
if (!$target.hasAttribute('digits'))
return false
if (
e.metaKey && e.code == 'KeyC' || e.ctrlKey && e.code == 'KeyC' ||
e.metaKey && e.code == 'KeyV' || e.ctrlKey && e.code == 'KeyV' ||
e.metaKey && e.code == 'KeyX' || e.ctrlKey && e.code == 'KeyX'
)
return false
if (secureKeys.indexOf(key) >= 0)
return false
const validate = /^([0-9])$/.test(key)
if (!validate)
e.preventDefault()
}
const ifFieldIsFile = ($target) => {
if ($target.getAttribute('type') !== 'file')
return false
const displayKeys = [
'name',
'size',
'type'
]
let display = $target.getAttribute('display') || 'name'
if (displayKeys.indexOf(display) <= -1) {
c.error('Forms', '"'+ display + '" is not a valid value')
return false
}
const $label = $target.previousElementSibling || $target.nextElementSibling
if ($target.value === '' || $target.value === null || $target.value === 'undefined' && $label !== null) {
($label.hasAttribute('default-label')) ? $label.innerHTML = $label.getAttribute('default-label') : null
return false
}
let displayLabel = $target.files[0][display]
if (display === 'size')
displayLabel = formatBytes(displayLabel, 0)
if ($target.hasAttribute('multiple'))
displayLabel = ifFieldIsFileMultiple($target, $label, display) || displayLabel
if (!$label.hasAttribute('default-label'))
$label.setAttribute('default-label', $label.innerHTML)
$label.innerHTML = displayLabel
}
const ifFieldIsFileMultiple = ($target, $label, display) => {
let displayLabel
const filesLength = $target.files.length
if (display === 'size') {
let sizes = 0
for (let i = 0; i < filesLength; i++) {
sizes = $target.files[i][display] + sizes
}
return formatBytes(sizes, 0)
}
if (filesLength > 1) {
const lang = document.querySelector('html').getAttribute('lang') || 'en'
let filesLabel = (lang === 'es') ? 'archivos' : 'files'
return filesLength + ' ' + filesLabel
}
return false
}
const ifFieldIsCurrency = (e = null, $target) => {
if (!$target.hasAttribute('currency'))
return false
if (e !== null && e.which === 110 || e !== null && e.which === 190)
return false
//Function
const format = (num) => String(num).replace(/\B(?=(\d{3})+(?!\d))/g, ',')
const string = parseFloat($target.value.replace(/\,/g,''), 10)
const parseCurrency = string.toLocaleString('es-MX')
if (parseCurrency === "NaN")
return false
$target.value = format(parseCurrency)
$target.dispatchEvent(new Event('change'))
}
const preventMultipleSubmit = (e, $form) => {
$form.querySelector('button[type="submit"]').setAttribute('disabled', '1')
setTimeout(() => {
$form.querySelector('button[type="submit"]').removeAttribute('disabled')
}, 2000)
}
const ifAutoSubmit = ($target) => {
if (!$target.hasAttribute('auto-submit'))
return false
let $parentForm = $target.parentNode
do {
$parentForm = $parentForm.parentNode
if ($parentForm.tagName === 'FORM') {
$parentForm.submit()
return true
}
}
while($parentForm.tagName !== 'FORM' && $parentForm.tagName !== 'HTML')
msg.error('Forms', 'Closest form missing')
return false
}
const ifAutoLink = ($target) => {
if (!$target.hasAttribute('auto-link'))
return false
window.location.href = $target.value
}
class forms {
process(parentClass) {
const $fields = document.querySelectorAll('input, select, textarea')
if ($fields.length <= 0 || $fields === null || typeof $fields === 'undefined')
return false
$fields.forEach(($item, i) => {
ifFieldIsCurrency(null, $item)
ifFieldIsEmpty($item, $item.value, parentClass)
ifFieldIsFile($item)
$fields[i].addEventListener('keydown', (e) => {
ifFieldIsNumeric(e, e.target, e.key)
ifFieldIsDigits(e, e.target, e.key)
})
$fields[i].addEventListener('keyup', (e) => {
ifFieldIsCurrency(e, e.target)
})
$fields[i].addEventListener('change', (e) => {
ifFieldIsFile(e.target)
ifFieldIsEmpty(e.target, e.target.value, parentClass)
ifAutoSubmit(e.target)
ifAutoLink(e.target)
})
$fields[i].addEventListener('focus', (e) => {
ifFocus(e.target, '.' + parentClass)
})
$fields[i].addEventListener('blur', (e) => {
ifBlur(e.target, '.' + parentClass)
})
})
document.querySelectorAll('form').forEach(($form) => {
$form.addEventListener('submit', (e) => {
preventMultipleSubmit(e, e.target)
})
})
}
init(parentClass = 'input-field') {
window.addEventListener('load', () => {
this.process(parentClass)
})
}
}
export default forms