A lot of improvements

This commit is contained in:
Tony Air 2018-09-19 12:20:43 +07:00
parent 61d6df132f
commit 843e457e78
8 changed files with 105 additions and 60 deletions

View File

@ -8,50 +8,66 @@ const FormStorage = (($) => {
const STORAGE = window.localStorage;
class FormStorage {
// Constructor
constructor(element) {
this._element = element;
const $element = $(this._element);
const $elements = $element.find('input,textarea');
const ui = this;
const $element = $(element);
const $elements = $element.find('input, textarea, select');
const setRangeValues = function(el) {
let $el = $(el);
$el.siblings('.value').text($el.val());
};
ui._element = element;
$element.data(DATA_KEY, this);
$element.addClass(`${NAME}-active`);
// restore form data from localStorage
$elements.each(function() {
const id = $(this).attr('id');
const type = $(this).attr('type');
$elements.each((i, el) => {
const $el = $(el);
const id = $el.attr('id');
const type = $el.attr('type');
const val = STORAGE.getItem(NAME + id);
if (id && val && type) {
if (type && (type === 'checkbox' || type === 'radio')) {
$(this).prop('checked', val);
$el.prop('checked', val);
} else {
$(this).val(val);
$el.val(val);
}
}
$el.trigger(Events.RESTORE_FIELD);
});
// range fields
$('input[type="range"]').each(function() {
setRangeValues(this);
$('input[type="range"]').each((i, el) => {
setRangeValues(el);
});
$('input[type="range"]').change(function() {
setRangeValues(this);
$element.trigger(Events.RESTORE_FIELD);
$('input[type="range"]').on('change', (e) => {
setRangeValues(e.currentTarget);
});
// store form data into localStorage
$elements.change(function() {
const id = $(this).attr('id');
const type = $(this).attr('type');
let val = $(this).val();
$elements.on('change', (e) => {
const $el = $(e.currentTarget);
const id = $el.attr('id');
const type = $el.attr('type');
// skip some elements
if ($el.hasClass('no-storage')) {
return true;
}
let val = $el.val();
if (type && (type === 'checkbox' || type === 'radio')) {
val = !!$(this).is(':checked');
val = !!$el.is(':checked');
}
if (id && type && type !== 'password') {
@ -59,13 +75,16 @@ const FormStorage = (($) => {
}
});
$element.submit(() => {
$element.on('submit', () => {
$element.data(DATA_KEY).clear();
});
$element.find('button,[type="submit"],[type="clear"]').click(() => {
$element.find('button,[type="submit"],[type="clear"]').on('click', () => {
$element.data(DATA_KEY).clear();
});
$element.addClass(`${NAME}-active`);
$element.trigger(Events.FORM_INIT_STORAGE);
}
// Public methods
@ -107,7 +126,16 @@ const FormStorage = (($) => {
// auto-apply
$(window).on(`${Events.AJAX} ${Events.LOADED}`, () => {
$('form').jsFormStorage();
$('form').each((i, el) => {
const $el = $(el);
// skip some forms
if ($el.hasClass('no-storage')) {
return true;
}
$el.jsFormStorage();
});
});
return FormStorage;

View File

@ -3,6 +3,11 @@
*/
module.exports = {
AJAX: 'ajax-load',
LOADED: 'load',
AJAX: 'ajax-load',
LOADED: 'load',
RESTORE_FIELD: 'restore-field',
FORM_INIT_STEPPED: 'form-init-stepped',
FORM_INIT_VALIDATE: 'form-init-validate',
FORM_INIT_STORAGE: 'form-init-storage',
FORM_VALIDATION_FAILED: 'form-validation-failed',
};

View File

@ -2,10 +2,9 @@ import $ from 'jquery';
import Events from './_events';
import Spinner from './_components/_ui.spinner';
import FormDatetime from './_components/_ui.form.datetime';
import FormStepped from './_components/_ui.form.stepped';
// your custom components
import 'bootstrap-datepicker/dist/js/bootstrap-datepicker.js';
import 'bootstrap-timepicker/js/bootstrap-timepicker.js';
const LayoutUI = (($) => {
// Constants
@ -31,28 +30,6 @@ const LayoutUI = (($) => {
console.log(`Initializing: ${NAME}`);
// your custom UI
const $dateFields = $Body.find('input.date');
const $timeFields = $Body.find('input.time');
// datepicker
$dateFields.each((i, e) => {
const $e = $(e);
const defaultDate = ($e.attr('name').toLowerCase().indexOf('end') !== -1) ?
'+4d' :
'+3d';
$e.attr('readonly', 'true');
$e.datepicker($.extend(datepickerOptions, {
defaultViewDate: defaultDate
}));
});
// timepicker
$timeFields.each((i, e) => {
const $e = $(e);
$e.attr('readonly', 'true');
$e.timepicker();
});
}
static dispose() {

View File

@ -144,6 +144,27 @@ const MainUI = (($) => {
// mark external links
$('a.external,a[rel="external"]').attr('target', '_blank');
// data-set links
$('[data-set-target]').on('click', (e) => {
const $el = $(e.currentTarget);
const $target = $($el.data('set-target'));
if (!$target.length) {
return;
}
$target.each((i, targetEl) => {
const $targetEl = $(targetEl);
const tag = $targetEl.prop('tagName').toLowerCase();
if (tag === 'input' || tag === 'select') {
$targetEl.val($el.data('set-val'));
} else if (!$targetEl.hasClass('field')) {
$targetEl.text($el.data('set-val'));
}
});
});
// show encoded emails
/*$(D).find('.obm').each(function () {
if ($(this).attr('data-val') !== undefined) {

View File

@ -9,22 +9,28 @@ img {
}
a:hover,
a:focus {
a:focus,
button:hover,
button:focus {
opacity: .8;
.fas,
.fab,
.far,
&.fas,
&.fab {
transform: rotate(-180deg);
&.fab,
&.far {
transform: scale(-1, 1);
}
}
// transactions
.transition,
a, a img,
a .fas, a .fab,
a.fas, a.fab,
a .fas, a .fab, a .far,
a.fas, a.fab, a.far,
button .fas, button .fab, button .far,
button.fas, button.fab, button.far,
button, input, optgroup, select, textarea,
.btn,
.alert,
@ -43,6 +49,10 @@ button, input, optgroup, select, textarea,
.field {
margin: ($grid-gutter-height / 4) 0;
&:first-child {
margin-top: 0;
}
}
// stick navbar to top using mobile layout

View File

@ -1,3 +1,6 @@
@import "~bootstrap-datepicker/dist/css/bootstrap-datepicker.css";
@import "~bootstrap-timepicker/css/bootstrap-timepicker.css";
// Your custom variables
@import "_variables";

View File

@ -50,19 +50,19 @@ class DeferedRequirements implements TemplateGlobalProvider
}
// App libs
if (!$config['nofontawesome']) {
DeferedRequirements::loadCSS('//use.fontawesome.com/releases/v5.0.13/css/all.css');
DeferedRequirements::loadCSS('//use.fontawesome.com/releases/v5.3.1/css/all.css');
}
DeferedRequirements::loadCSS('app.css');
DeferedRequirements::loadJS('app.js');
// Class libs
$class = get_class(Controller::curr());
if(isset($config['custom_requirements'][$class])){
if (isset($config['custom_requirements'][$class])) {
foreach ($config['custom_requirements'][$class] as $file) {
if(strpos($file,'.css')){
if (strpos($file, '.css')) {
DeferedRequirements::loadCSS($file);
}
if(strpos($file,'.js')){
if (strpos($file, '.js')) {
DeferedRequirements::loadJS($file);
}
}
@ -78,7 +78,7 @@ class DeferedRequirements implements TemplateGlobalProvider
);
if (file_exists(Path::join($dir, 'css', $class . '.css'))) {
DeferedRequirements::loadCSS( $class . '.css');
DeferedRequirements::loadCSS($class . '.css');
}
if (file_exists(Path::join($dir, 'js', $class . '.js'))) {

View File

@ -31,7 +31,8 @@
"a2nt/silverstripe-font-awesome-field": "dev-master",
"stevie-mayhew/silverstripe-svg": "^2.1",
"betterbrief/silverstripe-googlemapfield": "^2.1",
"innoweb/silverstripe-sitemap": "^2.0"
"innoweb/silverstripe-sitemap": "^2.0",
"silverstripe/multiuser-editing-alert": "^2.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7",