mirror of
https://github.com/a2nt/webpack-bootstrap-ui-kit.git
synced 2024-10-22 11:05:45 +02:00
IMPR: Minor updates
This commit is contained in:
parent
4ffb65e014
commit
8040674c99
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate",
|
||||
"version": "2.3.4",
|
||||
"version": "2.3.5",
|
||||
"author": "Tony Air <tony@twma.pro>",
|
||||
"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.",
|
||||
|
@ -12,7 +12,6 @@ const FormToggleUI = (($) => {
|
||||
const FieldUI = 'jsFormFieldUI';
|
||||
|
||||
class FormToggleUI {
|
||||
|
||||
constructor($el) {
|
||||
const ui = this;
|
||||
ui.$el = $el;
|
||||
@ -24,7 +23,7 @@ const FormToggleUI = (($) => {
|
||||
|
||||
ui.toggle();
|
||||
|
||||
ui.$el.on(`change shown.${ FieldUI } hidden.${ FieldUI}`, (e) => {
|
||||
ui.$el.on(`change shown.${FieldUI} hidden.${FieldUI}`, (e) => {
|
||||
ui.toggle();
|
||||
});
|
||||
|
||||
@ -38,8 +37,10 @@ const FormToggleUI = (($) => {
|
||||
const ui = this;
|
||||
const $el = ui.$el;
|
||||
|
||||
return ($el.is('[type="radio"],[type="checkbox"]') && $el.parents('.optionset,.checkboxset').length) ?
|
||||
$el.parents('.optionset,.checkboxset') : $el;
|
||||
return $el.is('[type="radio"],[type="checkbox"]') &&
|
||||
$el.parents('.optionset,.checkboxset').length
|
||||
? $el.parents('.optionset,.checkboxset')
|
||||
: $el;
|
||||
}
|
||||
|
||||
getCondition() {
|
||||
@ -61,7 +62,7 @@ const FormToggleUI = (($) => {
|
||||
}
|
||||
|
||||
if ($el.attr('type') === 'radio') {
|
||||
return $Html.find(`[name="${ $el.attr('name') }"]:checked`).val();
|
||||
return $Html.find(`[name="${$el.attr('name')}"]:checked`).val();
|
||||
}
|
||||
|
||||
return $el.val();
|
||||
@ -94,8 +95,7 @@ const FormToggleUI = (($) => {
|
||||
}
|
||||
|
||||
getElement(target) {
|
||||
return target && target.length && $(target).length ?
|
||||
$(target) : false;
|
||||
return target && target.length && $(target).length ? $(target) : false;
|
||||
}
|
||||
|
||||
toggle() {
|
||||
@ -112,15 +112,17 @@ const FormToggleUI = (($) => {
|
||||
}
|
||||
|
||||
// yes/no toggler
|
||||
const yesNoVal = (
|
||||
const yesNoVal =
|
||||
(condition === true && val && val !== '' && val !== '0') ||
|
||||
condition === val
|
||||
) ? true : false;
|
||||
? true
|
||||
: false;
|
||||
|
||||
const $yesTarget = ui.getTrueTarget();
|
||||
const $noTarget = ui.getFalseTarget();
|
||||
const elUI = $el.data(FieldUI);
|
||||
|
||||
if (!$el.data(FieldUI).shown || typeof val === 'undefined') {
|
||||
if ((elUI && !elUI.shown) || typeof val === 'undefined') {
|
||||
ui.toggleElement($yesTarget, false);
|
||||
ui.toggleElement($noTarget, false);
|
||||
|
||||
@ -150,7 +152,7 @@ const FormToggleUI = (($) => {
|
||||
$el.collapse(action);
|
||||
});
|
||||
|
||||
$el.trigger(`${action }.${ NAME}`);
|
||||
$el.trigger(`${action}.${NAME}`);
|
||||
}
|
||||
|
||||
dispose() {
|
||||
@ -180,8 +182,10 @@ const FormToggleUI = (($) => {
|
||||
const $el = $(el);
|
||||
const name = $el.attr('name');
|
||||
|
||||
if ($(`[name="${ name }"]`).length > 1) {
|
||||
console.warn(`${NAME }: Module malfunction duplicate "${ name }" elements found`);
|
||||
if ($(`[name="${name}"]`).length > 1) {
|
||||
console.warn(
|
||||
`${NAME}: Module malfunction duplicate "${name}" elements found`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -190,13 +194,13 @@ const FormToggleUI = (($) => {
|
||||
// jQuery interface
|
||||
$.fn[NAME] = FormToggleUI._jQueryInterface;
|
||||
$.fn[NAME].Constructor = FormToggleUI;
|
||||
$.fn[NAME].noConflict = function() {
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return FormToggleUI._jQueryInterface;
|
||||
};
|
||||
|
||||
// auto-apply
|
||||
$(W).on(`${Events.AJAX} ${Events.LOADED}`, () => {
|
||||
$(W).on(`${Events.LODEDANDREADY}`, () => {
|
||||
//FormToggleUI.validate();
|
||||
$(Events.FORM_FIELDS).filter('[data-value-toggle]').jsFormToggleUI();
|
||||
|
||||
|
@ -1,142 +1,165 @@
|
||||
import $ from 'jquery';
|
||||
import Events from '../_events';
|
||||
import FormValidateField from './_ui.form.validate.field';
|
||||
import SpinnerUI from './_ui.spinner';
|
||||
|
||||
const FormValidate = (($) => {
|
||||
const FormValidateField = (($) => {
|
||||
// Constants
|
||||
const NAME = 'jsFormValidate';
|
||||
const NAME = 'jsFormValidateField';
|
||||
const DATA_KEY = NAME;
|
||||
const $Html = $('html, body');
|
||||
|
||||
class FormValidate {
|
||||
constructor(element) {
|
||||
const FieldUI = 'jsFormFieldUI';
|
||||
|
||||
class FormValidateField {
|
||||
constructor(el) {
|
||||
const ui = this;
|
||||
const $element = $(element);
|
||||
const $fields = $element.find('input,textarea,select');
|
||||
const $el = $(el);
|
||||
|
||||
ui._element = element;
|
||||
$element.data(DATA_KEY, this);
|
||||
ui.$el = $el;
|
||||
|
||||
ui._fields = $fields;
|
||||
ui._stepped_form = $element.data('jsSteppedForm');
|
||||
ui._actions = $el.parents('form').children('.btn-toolbar,.form-actions');
|
||||
$el.data(DATA_KEY, this);
|
||||
|
||||
// prevent browsers checks (will do it using JS)
|
||||
$element.attr('novalidate', 'novalidate');
|
||||
$el.attr('novalidate', 'novalidate');
|
||||
|
||||
$element.on(Events.FORM_INIT_STEPPED, () => {
|
||||
ui._stepped_form = $element.data('jsSteppedForm');
|
||||
$el.on('change focusout', (e) => {
|
||||
ui.validate(false);
|
||||
});
|
||||
|
||||
// init fields validation
|
||||
$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);
|
||||
$el.addClass(`${NAME}-active`);
|
||||
$el.trigger(Events.FORM_INIT_VALIDATE_FIELD);
|
||||
}
|
||||
|
||||
// Public methods
|
||||
dispose() {
|
||||
const $element = $(this._element);
|
||||
const $el = ui.$el;
|
||||
|
||||
$element.removeClass(`${NAME}-active`);
|
||||
$.removeData(this._element, DATA_KEY);
|
||||
this._element = null;
|
||||
$el.removeClass(`${NAME}-active`);
|
||||
$.removeData(ui.$el[0], DATA_KEY);
|
||||
ui.$el = null;
|
||||
}
|
||||
|
||||
validate(scrollTo = true, badCallback = false) {
|
||||
console.log('Checking the field ...');
|
||||
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;
|
||||
|
||||
ui._fields.each((i, el) => {
|
||||
const $el = $(el);
|
||||
const fieldUI = $el.data('jsFormValidateField');
|
||||
const val = $el.val();
|
||||
|
||||
if (fieldUI && !fieldUI.validate()) {
|
||||
SpinnerUI.hide();
|
||||
// browser checks + required
|
||||
if (
|
||||
!ui.$el[0].checkValidity() ||
|
||||
($el.hasClass('required') &&
|
||||
(!val.length ||
|
||||
!val.trim().length ||
|
||||
(ui.isHtml(val) && !$(val).text().length)))
|
||||
) {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
console.log('Invalid field data:');
|
||||
console.log($el);
|
||||
// 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/';
|
||||
}
|
||||
|
||||
if (badCallback) {
|
||||
badCallback();
|
||||
}
|
||||
this.removeError();
|
||||
|
||||
valid = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// extra checks
|
||||
if (extraChecks) {
|
||||
extraChecks.forEach((check) => {
|
||||
valid = valid && check();
|
||||
});
|
||||
}
|
||||
|
||||
return valid;
|
||||
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) {
|
||||
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() {
|
||||
return this.each(function() {
|
||||
// attach functionality to element
|
||||
const $element = $(this);
|
||||
let data = $element.data(DATA_KEY);
|
||||
return this.each(function () {
|
||||
// attach functionality to el
|
||||
const $el = $(this);
|
||||
let data = $el.data(DATA_KEY);
|
||||
|
||||
if (!data) {
|
||||
data = new FormValidate(this);
|
||||
$element.data(DATA_KEY, data);
|
||||
data = new FormValidateField(this);
|
||||
$el.data(DATA_KEY, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// jQuery interface
|
||||
$.fn[NAME] = FormValidate._jQueryInterface;
|
||||
$.fn[NAME].Constructor = FormValidate;
|
||||
$.fn[NAME].noConflict = function() {
|
||||
$.fn[NAME] = FormValidateField._jQueryInterface;
|
||||
$.fn[NAME].Constructor = FormValidateField;
|
||||
$.fn[NAME].noConflict = function () {
|
||||
$.fn[NAME] = JQUERY_NO_CONFLICT;
|
||||
return FormValidate._jQueryInterface;
|
||||
return FormValidateField._jQueryInterface;
|
||||
};
|
||||
|
||||
// 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;
|
||||
return FormValidateField;
|
||||
})($);
|
||||
|
||||
export default FormValidate;
|
||||
export default FormValidateField;
|
||||
|
@ -216,7 +216,9 @@ const MultiSlider = (($) => {
|
||||
$(W).on(Events.LODEDANDREADY, () => {
|
||||
console.log(`Initializing: ${NAME}`);
|
||||
|
||||
$(`.${NAME}`).jsMultiSlider();
|
||||
$(`.${NAME}`).each((i,el) => {
|
||||
$(el).jsMultiSlider();
|
||||
});
|
||||
});
|
||||
|
||||
return MultiSlider;
|
||||
|
@ -6,48 +6,50 @@ $grid-gutter-element-height: 2rem !default;
|
||||
display: flex;
|
||||
margin-bottom: $grid-gutter-element-height/2;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 100%;
|
||||
|
||||
&-active {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&-container {
|
||||
position: relative;
|
||||
margin-bottom: $grid-gutter-element-height/2;
|
||||
|
||||
.slider-actions {
|
||||
.act {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
&-slider-prev {
|
||||
}
|
||||
&-slider-next {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-slides-container {
|
||||
overflow: hidden;
|
||||
margin: 0 2rem;
|
||||
|
||||
> .slider-nav {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.slide {
|
||||
position: relative;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.jsMultiSlider-container {
|
||||
position: relative;
|
||||
margin-bottom: $grid-gutter-element-height/2;
|
||||
|
||||
.slider-actions {
|
||||
font-size: 2rem;
|
||||
.act {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-decoration: none;
|
||||
&-slider-prev {
|
||||
}
|
||||
&-slider-next {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.jsMultiSlider-slides-container {
|
||||
overflow: hidden;
|
||||
margin: 0 2rem;
|
||||
|
||||
> .slider-nav {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user