'use strict' import $ from 'jquery' import Events from '../_events' const FormValidateField = (($) => { // Constants const NAME = 'jsFormValidateField' const DATA_KEY = NAME const $Body = $('body') const FieldUI = 'jsFormFieldUI' class FormValidateField { constructor (el) { const ui = this const $el = $(el) ui.$el = $el ui._actions = $el.parents('form').children('.btn-toolbar,.form-actions') $el.data(DATA_KEY, this) // prevent browsers checks (will do it using JS) $el.attr('novalidate', 'novalidate') $el.on('change focusout', (e) => { ui.validate(false) }) $el.addClass(`${NAME}-active`) $el.trigger(Events.FORM_INIT_VALIDATE_FIELD) } // Public methods dispose () { const $el = ui.$el $el.removeClass(`${NAME}-active`) $.removeData(ui.$el[0], DATA_KEY) ui.$el = null } validate (scrollTo = true) { const ui = this const $el = ui.$el const $field = $el.closest('.field') const extraChecks = $el.data(`${NAME}-extra`) let valid = true let msg = null const val = $el.val() // browser checks if (!ui.$el[0].checkValidity()) { valid = false console.warn( `${NAME}: Browser check validity is failed #${$el.attr('id')}` ) } let unmaskedVal = val if (typeof $el.inputmask === 'function') { unmaskedVal = $el.inputmask('unmaskedvalue') } // required if ( $el.hasClass('required') && (!unmaskedVal.length || !unmaskedVal.trim().length || (ui.isHtml(val) && !$(unmaskedVal).text().length)) ) { valid = false console.warn(`${NAME}: Required field is missing #${$el.attr('id')}`) } // validate URL if ( $el.hasClass('url') && unmaskedVal.length && !ui.valideURL(unmaskedVal) ) { valid = false msg = 'Invalid URL: URL must start with http:// or https://. For example: https://your-domain.com/bla-bla/?p1=b&p2=a#tag' console.warn(`${NAME}: Wrong URL #${$el.attr('id')}`) } // maxlength const maxLength = $el.attr('maxlength') if (unmaskedVal.length && maxLength && maxLength.length) { if (unmaskedVal.length > maxLength) { valid = false msg = `The value is limited to ${maxLength} chars` console.warn(`${NAME}: Too long value #${$el.attr('id')}`) } } // minlength const minLength = $el.attr('minlength') if (unmaskedVal.length && minLength && minLength.length) { if (unmaskedVal.length < minLength) { valid = false msg = `The value should contain more than ${minLength} chars` console.warn(`${NAME}: Too short value #${$el.attr('id')}`) } } this.removeError() // extra checks if (extraChecks) { extraChecks.forEach((check) => { const result = check($el) valid = valid && result if (!result) { console.log(check) console.warn(`${NAME}: Extra check is failed #${$el.attr('id')}`) } }) } if (valid) { return true } this.setError(scrollTo, msg) return false } isHtml (str) { const doc = new DOMParser().parseFromString(str, 'text/html') return Array.from(doc.body.childNodes).some( (node) => node.nodeType === 1 ) } valideURL (str) { let url try { url = new URL(str) } catch (_) { return false } return url.protocol === 'http:' || url.protocol === 'https:' } setError (scrollTo = true, msg = null) { const ui = this const fieldUI = ui.$el.data(FieldUI) const $field = ui.$el.closest('.field') const bodyScroll = $Body.scrollTop() const pos = $field[0].getBoundingClientRect().top // $field.offset().top; const rowCorrection = parseInt($field.css('font-size')) * 4 ui.removeError() $field.addClass('error') if (msg) { fieldUI.addMessage(msg, 'alert-error alert-danger', scrollTo) } else if (pos && scrollTo) { $field.focus() $Body.scrollTop(bodyScroll + pos - rowCorrection) } } removeError () { const ui = this const fieldUI = ui.$el.data(FieldUI) const $field = ui.$el.closest('.field') $field.removeClass('error') $field.removeClass('holder-error') $field.removeClass('holder-validation') $field.find('.alert-error').remove() } static _jQueryInterface () { return this.each(function () { // attach functionality to el const $el = $(this) let data = $el.data(DATA_KEY) if (!data) { data = new FormValidateField(this) $el.data(DATA_KEY, data) } }) } } // jQuery interface $.fn[NAME] = FormValidateField._jQueryInterface $.fn[NAME].Constructor = FormValidateField $.fn[NAME].noConflict = function () { $.fn[NAME] = JQUERY_NO_CONFLICT return FormValidateField._jQueryInterface } return FormValidateField })($) export default FormValidateField