IMPR: Minor updates

This commit is contained in:
Tony Air 2020-07-25 01:13:25 +07:00
parent 4ffb65e014
commit 8040674c99
5 changed files with 177 additions and 146 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate", "name": "@a2nt/ss-bootstrap-ui-webpack-boilerplate",
"version": "2.3.4", "version": "2.3.5",
"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.",

View File

@ -12,7 +12,6 @@ const FormToggleUI = (($) => {
const FieldUI = 'jsFormFieldUI'; const FieldUI = 'jsFormFieldUI';
class FormToggleUI { class FormToggleUI {
constructor($el) { constructor($el) {
const ui = this; const ui = this;
ui.$el = $el; ui.$el = $el;
@ -24,7 +23,7 @@ const FormToggleUI = (($) => {
ui.toggle(); ui.toggle();
ui.$el.on(`change shown.${ FieldUI } hidden.${ FieldUI}`, (e) => { ui.$el.on(`change shown.${FieldUI} hidden.${FieldUI}`, (e) => {
ui.toggle(); ui.toggle();
}); });
@ -38,8 +37,10 @@ const FormToggleUI = (($) => {
const ui = this; const ui = this;
const $el = ui.$el; const $el = ui.$el;
return ($el.is('[type="radio"],[type="checkbox"]') && $el.parents('.optionset,.checkboxset').length) ? return $el.is('[type="radio"],[type="checkbox"]') &&
$el.parents('.optionset,.checkboxset') : $el; $el.parents('.optionset,.checkboxset').length
? $el.parents('.optionset,.checkboxset')
: $el;
} }
getCondition() { getCondition() {
@ -61,7 +62,7 @@ const FormToggleUI = (($) => {
} }
if ($el.attr('type') === 'radio') { 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(); return $el.val();
@ -94,8 +95,7 @@ const FormToggleUI = (($) => {
} }
getElement(target) { getElement(target) {
return target && target.length && $(target).length ? return target && target.length && $(target).length ? $(target) : false;
$(target) : false;
} }
toggle() { toggle() {
@ -112,15 +112,17 @@ const FormToggleUI = (($) => {
} }
// yes/no toggler // yes/no toggler
const yesNoVal = ( const yesNoVal =
(condition === true && val && val !== '' && val !== '0') || (condition === true && val && val !== '' && val !== '0') ||
condition === val condition === val
) ? true : false; ? true
: false;
const $yesTarget = ui.getTrueTarget(); const $yesTarget = ui.getTrueTarget();
const $noTarget = ui.getFalseTarget(); 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($yesTarget, false);
ui.toggleElement($noTarget, false); ui.toggleElement($noTarget, false);
@ -150,7 +152,7 @@ const FormToggleUI = (($) => {
$el.collapse(action); $el.collapse(action);
}); });
$el.trigger(`${action }.${ NAME}`); $el.trigger(`${action}.${NAME}`);
} }
dispose() { dispose() {
@ -180,8 +182,10 @@ const FormToggleUI = (($) => {
const $el = $(el); const $el = $(el);
const name = $el.attr('name'); const name = $el.attr('name');
if ($(`[name="${ name }"]`).length > 1) { if ($(`[name="${name}"]`).length > 1) {
console.warn(`${NAME }: Module malfunction duplicate "${ name }" elements found`); console.warn(
`${NAME}: Module malfunction duplicate "${name}" elements found`,
);
} }
}); });
} }
@ -190,13 +194,13 @@ const FormToggleUI = (($) => {
// jQuery interface // jQuery interface
$.fn[NAME] = FormToggleUI._jQueryInterface; $.fn[NAME] = FormToggleUI._jQueryInterface;
$.fn[NAME].Constructor = FormToggleUI; $.fn[NAME].Constructor = FormToggleUI;
$.fn[NAME].noConflict = function() { $.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT; $.fn[NAME] = JQUERY_NO_CONFLICT;
return FormToggleUI._jQueryInterface; return FormToggleUI._jQueryInterface;
}; };
// auto-apply // auto-apply
$(W).on(`${Events.AJAX} ${Events.LOADED}`, () => { $(W).on(`${Events.LODEDANDREADY}`, () => {
//FormToggleUI.validate(); //FormToggleUI.validate();
$(Events.FORM_FIELDS).filter('[data-value-toggle]').jsFormToggleUI(); $(Events.FORM_FIELDS).filter('[data-value-toggle]').jsFormToggleUI();

View File

@ -1,142 +1,165 @@
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 FormValidate = (($) => { const FormValidateField = (($) => {
// Constants // Constants
const NAME = 'jsFormValidate'; const NAME = 'jsFormValidateField';
const DATA_KEY = NAME; const DATA_KEY = NAME;
const $Html = $('html, body'); const $Html = $('html, body');
class FormValidate { const FieldUI = 'jsFormFieldUI';
constructor(element) {
class FormValidateField {
constructor(el) {
const ui = this; const ui = this;
const $element = $(element); const $el = $(el);
const $fields = $element.find('input,textarea,select');
ui._element = element; ui.$el = $el;
$element.data(DATA_KEY, this);
ui._fields = $fields; ui._actions = $el.parents('form').children('.btn-toolbar,.form-actions');
ui._stepped_form = $element.data('jsSteppedForm'); $el.data(DATA_KEY, this);
// prevent browsers checks (will do it using JS) // prevent browsers checks (will do it using JS)
$element.attr('novalidate', 'novalidate'); $el.attr('novalidate', 'novalidate');
$element.on(Events.FORM_INIT_STEPPED, () => { $el.on('change focusout', (e) => {
ui._stepped_form = $element.data('jsSteppedForm'); ui.validate(false);
}); });
// init fields validation $el.addClass(`${NAME}-active`);
$fields.each((i, el) => { $el.trigger(Events.FORM_INIT_VALIDATE_FIELD);
// 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 $element = $(this._element); const $el = ui.$el;
$element.removeClass(`${NAME}-active`); $el.removeClass(`${NAME}-active`);
$.removeData(this._element, DATA_KEY); $.removeData(ui.$el[0], DATA_KEY);
this._element = null; ui.$el = null;
} }
validate(scrollTo = true, badCallback = false) { validate(scrollTo = true) {
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;
ui._fields.each((i, el) => { const val = $el.val();
const $el = $(el);
const fieldUI = $el.data('jsFormValidateField');
if (fieldUI && !fieldUI.validate()) { // browser checks + required
SpinnerUI.hide(); if (
!ui.$el[0].checkValidity() ||
console.log('Invalid field data:'); ($el.hasClass('required') &&
console.log($el); (!val.length ||
!val.trim().length ||
if (badCallback) { (ui.isHtml(val) && !$(val).text().length)))
badCallback(); ) {
valid = false;
} }
// validate URL
if ($el.hasClass('url') && val.length && !this.valideURL(val)) {
valid = false; 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;
} }
});
return valid; 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() { static _jQueryInterface() {
return this.each(function() { return this.each(function () {
// attach functionality to element // attach functionality to el
const $element = $(this); const $el = $(this);
let data = $element.data(DATA_KEY); let data = $el.data(DATA_KEY);
if (!data) { if (!data) {
data = new FormValidate(this); data = new FormValidateField(this);
$element.data(DATA_KEY, data); $el.data(DATA_KEY, data);
} }
}); });
} }
} }
// jQuery interface // jQuery interface
$.fn[NAME] = FormValidate._jQueryInterface; $.fn[NAME] = FormValidateField._jQueryInterface;
$.fn[NAME].Constructor = FormValidate; $.fn[NAME].Constructor = FormValidateField;
$.fn[NAME].noConflict = function() { $.fn[NAME].noConflict = function () {
$.fn[NAME] = JQUERY_NO_CONFLICT; $.fn[NAME] = JQUERY_NO_CONFLICT;
return FormValidate._jQueryInterface; return FormValidateField._jQueryInterface;
}; };
// auto-apply return FormValidateField;
$(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 FormValidate; export default FormValidateField;

View File

@ -216,7 +216,9 @@ const MultiSlider = (($) => {
$(W).on(Events.LODEDANDREADY, () => { $(W).on(Events.LODEDANDREADY, () => {
console.log(`Initializing: ${NAME}`); console.log(`Initializing: ${NAME}`);
$(`.${NAME}`).jsMultiSlider(); $(`.${NAME}`).each((i,el) => {
$(el).jsMultiSlider();
});
}); });
return MultiSlider; return MultiSlider;

View File

@ -6,15 +6,26 @@ $grid-gutter-element-height: 2rem !default;
display: flex; display: flex;
margin-bottom: $grid-gutter-element-height/2; margin-bottom: $grid-gutter-element-height/2;
align-items: center;
justify-content: center;
min-width: 100%;
&-active { &-active {
margin-bottom: 0; margin-bottom: 0;
} }
&-container { .slide {
position: relative;
padding: 0 0.5rem;
}
}
.jsMultiSlider-container {
position: relative; position: relative;
margin-bottom: $grid-gutter-element-height/2; margin-bottom: $grid-gutter-element-height/2;
.slider-actions { .slider-actions {
font-size: 2rem;
.act { .act {
position: absolute; position: absolute;
top: 0; top: 0;
@ -32,22 +43,13 @@ $grid-gutter-element-height: 2rem !default;
} }
} }
} }
} }
&-slides-container { .jsMultiSlider-slides-container {
overflow: hidden; overflow: hidden;
margin: 0 2rem; margin: 0 2rem;
> .slider-nav { > .slider-nav {
position: relative; position: relative;
} }
}
.slide {
position: relative;
padding: 0 0.5rem;
}
.slider-actions {
font-size: 2rem;
}
} }