mirror of
https://github.com/a2nt/webpack-bootstrap-ui-kit.git
synced 2024-10-22 11:05:45 +02:00
UI: Form validation improvements
This commit is contained in:
parent
5730c9bbff
commit
513a5f1774
2
dist/js/app.js
vendored
2
dist/js/app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/js/app.js.map
vendored
2
dist/js/app.js.map
vendored
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate",
|
"name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate",
|
||||||
"version": "2.0.3",
|
"version": "2.0.4",
|
||||||
"author": "Tony Air <tony@twma.pro>",
|
"author": "Tony Air <tony@twma.pro>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "This UI Kit allows you to build Bootstrap 4 webapp with some extra UI features. It's easy to extend and easy to convert HTML templates to CMS templates.",
|
"description": "This UI Kit allows you to build Bootstrap 4 webapp with some extra UI features. It's easy to extend and easy to convert HTML templates to CMS templates.",
|
||||||
|
@ -77,7 +77,11 @@ const FormBasics = (($) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$el.on('submit', (e) => {
|
$el.on('submit', (e) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!$el.find('.error').length) {
|
||||||
SpinnerUI.show();
|
SpinnerUI.show();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
|
|
||||||
$el.addClass(`${NAME}-active`);
|
$el.addClass(`${NAME}-active`);
|
||||||
|
@ -1,158 +1,142 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import Events from "../_events";
|
import Events from '../_events';
|
||||||
|
import FormValidateField from './_ui.form.validate.field';
|
||||||
|
import SpinnerUI from './_ui.spinner';
|
||||||
|
|
||||||
const FormValidateField = (($) => {
|
const FormValidate = (($) => {
|
||||||
// Constants
|
// Constants
|
||||||
const NAME = 'jsFormValidateField';
|
const NAME = 'jsFormValidate';
|
||||||
const DATA_KEY = NAME;
|
const DATA_KEY = NAME;
|
||||||
const $Html = $('html, body');
|
const $Html = $('html, body');
|
||||||
|
|
||||||
const FieldUI = 'jsFormFieldUI';
|
class FormValidate {
|
||||||
|
constructor(element) {
|
||||||
class FormValidateField {
|
|
||||||
|
|
||||||
constructor(el) {
|
|
||||||
const ui = this;
|
const ui = this;
|
||||||
const $el = $(el);
|
const $element = $(element);
|
||||||
|
const $fields = $element.find('input,textarea,select');
|
||||||
|
|
||||||
ui.$el = $el;
|
ui._element = element;
|
||||||
|
$element.data(DATA_KEY, this);
|
||||||
|
|
||||||
ui._actions = $el.parents('form').children('.btn-toolbar,.form-actions');
|
ui._fields = $fields;
|
||||||
$el.data(DATA_KEY, this);
|
ui._stepped_form = $element.data('jsSteppedForm');
|
||||||
|
|
||||||
// prevent browsers checks (will do it using JS)
|
// prevent browsers checks (will do it using JS)
|
||||||
$el.attr('novalidate', 'novalidate');
|
$element.attr('novalidate', 'novalidate');
|
||||||
|
|
||||||
$el.on('change focusout', (e) => {
|
$element.on(Events.FORM_INIT_STEPPED, () => {
|
||||||
ui.validate(false);
|
ui._stepped_form = $element.data('jsSteppedForm');
|
||||||
});
|
});
|
||||||
|
|
||||||
$el.addClass(`${NAME}-active`);
|
// init fields validation
|
||||||
$el.trigger(Events.FORM_INIT_VALIDATE_FIELD);
|
$fields.each((i, el) => {
|
||||||
|
// skip some fields here
|
||||||
|
if ($(el).attr('role') === 'combobox') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new FormValidateField(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
$element.removeClass('error');
|
||||||
|
// check form
|
||||||
|
$element.on('submit', (e) => {
|
||||||
|
ui.validate(true, () => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
// switch to step
|
||||||
|
if (ui._stepped_form) {
|
||||||
|
const $el = $element.find('.error').first();
|
||||||
|
|
||||||
|
if ($el.length) {
|
||||||
|
ui._stepped_form.step($el.parents('.step'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$element.addClass('error');
|
||||||
|
SpinnerUI.hide();
|
||||||
|
|
||||||
|
$element.trigger(Events.FORM_VALIDATION_FAILED);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$element.addClass(`${NAME}-active`);
|
||||||
|
$element.trigger(Events.FORM_INIT_VALIDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public methods
|
// Public methods
|
||||||
dispose() {
|
dispose() {
|
||||||
const $el = ui.$el;
|
const $element = $(this._element);
|
||||||
|
|
||||||
$el.removeClass(`${NAME}-active`);
|
$element.removeClass(`${NAME}-active`);
|
||||||
$.removeData(ui.$el[0], DATA_KEY);
|
$.removeData(this._element, DATA_KEY);
|
||||||
ui.$el = null;
|
this._element = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(scrollTo = true) {
|
validate(scrollTo = true, badCallback = false) {
|
||||||
|
console.log('Checking the field ...');
|
||||||
const ui = this;
|
const ui = this;
|
||||||
const $el = ui.$el;
|
|
||||||
|
|
||||||
const $field = $el.closest('.field');
|
|
||||||
const extraChecks = $el.data(`${NAME}-extra`);
|
|
||||||
let valid = true;
|
let valid = true;
|
||||||
let msg = null;
|
|
||||||
|
|
||||||
const val = $el.val();
|
ui._fields.each((i, el) => {
|
||||||
|
const $el = $(el);
|
||||||
|
const fieldUI = $el.data('jsFormValidateField');
|
||||||
|
|
||||||
|
if (fieldUI && !fieldUI.validate()) {
|
||||||
|
SpinnerUI.hide();
|
||||||
|
|
||||||
|
console.log('Invalid field data:');
|
||||||
|
console.log($el);
|
||||||
|
|
||||||
|
if (badCallback) {
|
||||||
|
badCallback();
|
||||||
|
}
|
||||||
|
|
||||||
// browser checks + required
|
|
||||||
if (!ui.$el[0].checkValidity() ||
|
|
||||||
($el.hasClass('required') && (!val.length || !val.trim().length ||
|
|
||||||
ui.isHtml(val) && !$(val).text().length
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
|
||||||
|
|
||||||
// validate URL
|
|
||||||
if ($el.hasClass('url') && val.length && !this.valideURL(val)) {
|
|
||||||
valid = false;
|
|
||||||
msg = 'URL must start with http:// or https://. For example: https://your-domain.com/';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeError();
|
|
||||||
|
|
||||||
// extra checks
|
|
||||||
if (extraChecks) {
|
|
||||||
extraChecks.forEach((check) => {
|
|
||||||
valid = valid && check();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valid) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setError(scrollTo, msg);
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
isHtml(str) {
|
return valid;
|
||||||
const doc = new DOMParser().parseFromString(str, "text/html");
|
|
||||||
return Array.from(doc.body.childNodes).some((node) => node.nodeType === 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
valideURL(str) {
|
|
||||||
const pattern = new RegExp('^(https?:\\/\\/){1}' + // protocol
|
|
||||||
'((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.?)+[a-z]{2,}|' + // domain name
|
|
||||||
'((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address
|
|
||||||
'(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path
|
|
||||||
'(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
|
|
||||||
'(\\#[-a-z\\d_]*)?$', 'i'); // fragment locator
|
|
||||||
return pattern.test(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
setError(scrollTo = true, msg = null) {
|
|
||||||
const ui = this;
|
|
||||||
const fieldUI = ui.$el.data(FieldUI);
|
|
||||||
|
|
||||||
const $field = ui.$el.closest('.field');
|
|
||||||
const pos = $field.offset().top;
|
|
||||||
|
|
||||||
ui.removeError();
|
|
||||||
|
|
||||||
$field.addClass('error');
|
|
||||||
if (msg) {
|
|
||||||
fieldUI.addMessage(msg, 'alert-error alert-danger', scrollTo);
|
|
||||||
} else if (scrollTo) {
|
|
||||||
$field.focus();
|
|
||||||
$Html.scrollTop(pos - 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
static _jQueryInterface() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
// attach functionality to el
|
// attach functionality to element
|
||||||
const $el = $(this);
|
const $element = $(this);
|
||||||
let data = $el.data(DATA_KEY);
|
let data = $element.data(DATA_KEY);
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
data = new FormValidateField(this);
|
data = new FormValidate(this);
|
||||||
$el.data(DATA_KEY, data);
|
$element.data(DATA_KEY, data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// jQuery interface
|
// jQuery interface
|
||||||
$.fn[NAME] = FormValidateField._jQueryInterface;
|
$.fn[NAME] = FormValidate._jQueryInterface;
|
||||||
$.fn[NAME].Constructor = FormValidateField;
|
$.fn[NAME].Constructor = FormValidate;
|
||||||
$.fn[NAME].noConflict = function() {
|
$.fn[NAME].noConflict = function() {
|
||||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||||
return FormValidateField._jQueryInterface;
|
return FormValidate._jQueryInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
return FormValidateField;
|
// auto-apply
|
||||||
|
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||||
|
$('form').each((i, el) => {
|
||||||
|
const $el = $(el);
|
||||||
|
|
||||||
|
// skip some forms
|
||||||
|
if ($el.hasClass('no-validation')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$el.jsFormValidate();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return FormValidate;
|
||||||
})($);
|
})($);
|
||||||
|
|
||||||
export default FormValidateField;
|
export default FormValidate;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import Events from "../_events";
|
import Events from '../_events';
|
||||||
import FormValidateField from "./_ui.form.validate.field";
|
|
||||||
|
import FormBasics from './_ui.form.basics';
|
||||||
|
import FormValidateField from './_ui.form.validate.field';
|
||||||
import SpinnerUI from './_ui.spinner';
|
import SpinnerUI from './_ui.spinner';
|
||||||
|
|
||||||
const FormValidate = (($) => {
|
const FormValidate = (($) => {
|
||||||
@ -10,13 +12,13 @@ const FormValidate = (($) => {
|
|||||||
const $Html = $('html, body');
|
const $Html = $('html, body');
|
||||||
|
|
||||||
class FormValidate {
|
class FormValidate {
|
||||||
|
|
||||||
constructor(element) {
|
constructor(element) {
|
||||||
const ui = this;
|
const ui = this;
|
||||||
const $element = $(element);
|
const $element = $(element);
|
||||||
const $fields = $element.find('input,textarea,select');
|
const $fields = $element.find('input,textarea,select');
|
||||||
|
|
||||||
ui._element = element;
|
ui._element = element;
|
||||||
|
ui.$element = $element;
|
||||||
$element.data(DATA_KEY, this);
|
$element.data(DATA_KEY, this);
|
||||||
|
|
||||||
ui._fields = $fields;
|
ui._fields = $fields;
|
||||||
@ -80,14 +82,16 @@ const FormValidate = (($) => {
|
|||||||
const fieldUI = $el.data('jsFormValidateField');
|
const fieldUI = $el.data('jsFormValidateField');
|
||||||
|
|
||||||
if (fieldUI && !fieldUI.validate()) {
|
if (fieldUI && !fieldUI.validate()) {
|
||||||
|
SpinnerUI.hide();
|
||||||
|
|
||||||
|
ui.$element.addClass('error');
|
||||||
|
console.log('Invalid form data:');
|
||||||
|
console.log($el);
|
||||||
|
|
||||||
if (badCallback) {
|
if (badCallback) {
|
||||||
badCallback();
|
badCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Invalid form data:');
|
|
||||||
console.log($el);
|
|
||||||
|
|
||||||
SpinnerUI.hide();
|
|
||||||
valid = false;
|
valid = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,9 @@ const HeaderUI = (($) => {
|
|||||||
const ui = this;
|
const ui = this;
|
||||||
ui.dispose();
|
ui.dispose();
|
||||||
|
|
||||||
if (!$(`.${CLASSNAME}`).length) {
|
//console.log(`Initializing: ${NAME}`);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Initializing: ${NAME}`);
|
const $header = $(`#Header,.js${NAME}`);
|
||||||
|
|
||||||
const $header = $('#Header,.jsHeaderUI');
|
|
||||||
const updateHeader = () => {
|
const updateHeader = () => {
|
||||||
const h = $header.height();
|
const h = $header.height();
|
||||||
const s = $Body.scrollTop();
|
const s = $Body.scrollTop();
|
||||||
|
Loading…
Reference in New Issue
Block a user