A lot of improvements

This commit is contained in:
Tony Air 2018-09-19 12:20:51 +07:00
parent 843e457e78
commit d638843f92
6 changed files with 502 additions and 0 deletions

View File

@ -0,0 +1,86 @@
import $ from 'jquery';
import Events from '../_events';
import 'bootstrap-datepicker/dist/js/bootstrap-datepicker.js';
import 'bootstrap-timepicker/js/bootstrap-timepicker.js';
const DatetimeUI = (($) => {
// Constants
const W = window;
const D = document;
const $Body = $('body');
const NAME = 'jsDatetimeUI';
const DATA_KEY = NAME;
const datepickerOptions = {
autoclose: true,
startDate: 0,
//todayBtn: true,
todayHighlight: true,
clearBtn: true,
};
class DatetimeUI {
constructor(element) {
const ui = this;
const $element = $(element);
$element.data(DATA_KEY, this);
ui._element = element;
// datepicker
if ($element.hasClass('date')) {
const defaultDate = ($element.attr('name').toLowerCase().indexOf('end') !== -1) ?
'+4d' :
'+3d';
$element.attr('readonly', 'true');
$element.datepicker($.extend(datepickerOptions, {
defaultViewDate: defaultDate
}));
} else
// timepicker
if ($element.hasClass('time')) {
$element.attr('readonly', 'true');
$element.timepicker();
}
}
static dispose() {
console.log(`Destroying: ${NAME}`);
}
static _jQueryInterface() {
return this.each(function() {
// attach functionality to element
const $elementement = $(this);
let data = $elementement.data(DATA_KEY);
if (!data) {
data = new DatetimeUI(this);
$elementement.data(DATA_KEY, data);
}
});
}
}
// jQuery interface
$.fn[NAME] = DatetimeUI._jQueryInterface;
$.fn[NAME].Constructor = DatetimeUI;
$.fn[NAME].noConflict = function() {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return DatetimeUI._jQueryInterface;
};
// auto-apply
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
$('input.date, input.time').jsDatetimeUI();
});
return DatetimeUI;
})($);
export default DatetimeUI;

View File

@ -0,0 +1,86 @@
"use strict";
import $ from 'jquery';
import Events from '../_events';
import Spinner from '../_components/_ui.spinner';
import FormValidate from './_ui.form.validate';
import '../../thirdparty/jquery-te/jquery-te.js';
const JqteUI = (($) => {
const NAME = 'jsJqteUI';
const DATA_KEY = NAME;
const jqteOptions = {
color: false,
fsize: false,
funit: 'em',
format: false,
rule: false,
source: false,
sub: false,
sup: false,
};
class JqteUI {
constructor(element) {
const ui = this;
const $element = $(element);
const $jqteFields = $element.find('textarea.jqte-field');
const validationUI = $element.parents('form').data('jsFormValidate');
$element.data(DATA_KEY, this);
ui._element = element;
$element.jqte(jqteOptions);
// dynamic error control
$element.parents('.jqte').find('.jqte_editor').on('change', (e) => {
const $field = $(e.target);
const $container = $field.closest('.field');
if (!$field.text().length && $container.hasClass('required')) {
validationUI.setError($container);
} else {
validationUI.removeError($container);
}
});
}
static dispose() {
console.log(`Destroying: ${NAME}`);
}
static _jQueryInterface() {
return this.each(function() {
// attach functionality to element
const $element = $(this);
let data = $element.data(DATA_KEY);
if (!data) {
data = new JqteUI(this);
$element.data(DATA_KEY, data);
}
});
}
}
// jQuery interface
$.fn[NAME] = JqteUI._jQueryInterface;
$.fn[NAME].Constructor = JqteUI;
$.fn[NAME].noConflict = function() {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return JqteUI._jQueryInterface;
};
// auto-apply
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
$('textarea.jqte-field').jsJqteUI();
});
return JqteUI;
})($);
export default JqteUI;

View File

@ -0,0 +1,154 @@
import $ from 'jquery';
import Events from '../_events';
import LANG from '../lang/_en';
import FormValidate from './_ui.form.validate';
const SteppedForm = (($) => {
// Constants
const NAME = 'jsSteppedForm';
const DATA_KEY = NAME;
class SteppedForm {
constructor(element) {
const ui = this;
const $element = $(element);
$element.data(DATA_KEY, this);
if (!$element.find('.steps-counter').length) {
$element.prepend(LANG['en'][NAME]['STEPCOUNTER']);
}
if (!$element.find('.steps-buttons').length) {
$element.append(LANG['en'][NAME]['STEPBUTTONS']);
}
ui._currentStepCounter = $element.find('.steps-counter .current-step');
ui._totalStepsCounter = $element.find('.steps-counter .total-steps');
ui._steps = $element.find('.step');
ui._stepNext = $element.find('.step-next');
ui._stepPrev = $element.find('.step-prev');
ui._actions = $element.children('.btn-toolbar,.form-actions');
ui._element = element;
ui._currentStep = 1;
ui._totalSteps = ui._steps.length;
ui._stepsOrder = [];
ui._totalStepsCounter.text(ui._totalSteps);
ui.step('.step[data-step="' + ui._currentStep + '"]');
ui._stepNext.on('click', (e) => {
e.preventDefault();
ui.next();
});
ui._stepPrev.on('click', (e) => {
e.preventDefault();
ui.prev();
});
$element.find('.step-toggle').on('click', (e) => {
const $el = $(e.currentTarget);
e.preventDefault();
ui.step($el.data('target'));
});
$element.addClass(`${NAME}-active`);
$element.trigger(Events.FORM_INIT_STEPPED);
}
// Public methods
dispose() {
const ui = this;
const $element = $(ui._element);
$element.removeClass(`${NAME}-active`);
$.removeData(ui._element, DATA_KEY);
ui._element = null;
}
next() {
const ui = this;
if (ui._currentStep >= ui._totalSteps) {
return;
}
ui._currentStep++;
ui.step('.step[data-step="' + ui._currentStep + '"]');
}
prev() {
const ui = this;
if (ui._currentStep <= 1) {
return;
}
ui._currentStep--;
ui.step(ui._stepsOrder[ui._currentStep]);
}
step(target) {
const ui = this;
const $element = $(ui._element);
const $target = $element.find(target);
if (parseInt($target.data('step')) <= '1') {
ui._stepPrev.hide();
} else {
ui._stepPrev.show();
}
if (parseInt($target.data('step')) >= ui._totalSteps) {
ui._stepNext.hide();
ui._actions.show();
} else {
ui._stepNext.show();
ui._actions.hide();
}
ui._currentStep = parseInt($target.data('step'));
ui._stepsOrder[ui._currentStep] = $target;
ui._steps.removeClass('active');
$target.addClass('active');
ui._currentStepCounter.text(ui._currentStep);
}
static _jQueryInterface() {
return this.each(function() {
// attach functionality to element
const $element = $(this);
let data = $element.data(DATA_KEY);
if (!data) {
data = new SteppedForm(this);
$element.data(DATA_KEY, data);
}
});
}
}
// jQuery interface
$.fn[NAME] = SteppedForm._jQueryInterface;
$.fn[NAME].Constructor = SteppedForm;
$.fn[NAME].noConflict = function() {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return SteppedForm._jQueryInterface;
};
// auto-apply
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
$('.form-stepped').jsSteppedForm();
});
return SteppedForm;
})($);
export default SteppedForm;

View File

@ -0,0 +1,152 @@
import $ from 'jquery';
import Events from "../_events";
const FormValidate = (($) => {
// Constants
const NAME = 'jsFormValidate';
const DATA_KEY = NAME;
const $Html = $('html, body');
class FormValidate {
constructor(element) {
const ui = this;
const $element = $(element);
const $fields = $element.find('input,textarea,select');
ui._element = element;
$element.data(DATA_KEY, this);
ui._fields = $fields;
ui._stepped_form = $element.data('jsSteppedForm');
$element.on(Events.FORM_INIT_STEPPED, () => {
ui._stepped_form = $element.data('jsSteppedForm');
});
// prevent browsers checks (will do it using JS)
$element.attr('novalidate', 'novalidate');
$fields.each((i, el) => {
el.required = false;
});
$fields.on('change', (e) => {
ui.validateField($(e.target), false);
});
// check form
$element.on('submit', (e) => {
ui.validateForm($element, 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.trigger(Events.FORM_VALIDATION_FAILED);
});
});
$element.addClass(`${NAME}-active`);
$element.trigger(Events.FORM_INIT_VALIDATE);
}
// Public methods
dispose() {
const $element = $(this._element);
$element.removeClass(`${NAME}-active`);
$.removeData(this._element, DATA_KEY);
this._element = null;
}
validateForm($form, scrollTo = true, badCallback = false) {
console.log('Checking the form ...');
const ui = this;
ui._fields.each(function(i, el) {
const $el = $(el);
if (!ui.validateField($el)) {
if (badCallback) {
badCallback();
}
return false;
}
});
}
validateField($el, scrollTo = true) {
const $field = $el.closest('.field');
if (!$el[0].checkValidity() ||
($el.hasClass('required') && !$el.val().trim().length)
) {
this.setError($field, scrollTo);
return false;
} else {
this.removeError($field);
}
return true;
}
setError($field, scrollTo = true) {
const pos = $field.offset().top;
$field.addClass('error');
if (scrollTo) {
$field.focus();
$Html.scrollTop(pos - 100);
}
}
removeError($field) {
$field.removeClass('error');
}
static _jQueryInterface() {
return this.each(function() {
// attach functionality to element
const $element = $(this);
let data = $element.data(DATA_KEY);
if (!data) {
data = new FormValidate(this);
$element.data(DATA_KEY, data);
}
});
}
}
// jQuery interface
$.fn[NAME] = FormValidate._jQueryInterface;
$.fn[NAME].Constructor = FormValidate;
$.fn[NAME].noConflict = function() {
$.fn[NAME] = JQUERY_NO_CONFLICT;
return FormValidate._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;
})($);
export default FormValidate;

View File

@ -0,0 +1,15 @@
/**
* Add your global events here
*/
module.exports = {
en: {
jsSteppedForm: {
STEPCOUNTER: '<div class="steps-counter">Step <b class="current-step"></b> of <b class="total-steps"></b></div>',
STEPBUTTONS: '<div class="steps-buttons">' +
'<a href="#" class="step-ctrl step-prev"><i class="fas fa-chevron-left"></i> Prev</a>' +
' <a href="#" class="step-ctrl step-next">Next <i class="fas fa-chevron-right"></i></a>' +
'</div>',
},
},
};

View File

@ -0,0 +1,9 @@
.form-stepped {
.step {
display: none;
&.active {
display: block;
}
}
}