Improvements to framework extras

- Form validation
- Button loader
- Flash messages
This commit is contained in:
Samuel Georges 2016-11-18 07:41:02 +11:00
parent 10326c2d63
commit 0a8f169cc3
5 changed files with 490 additions and 46 deletions

View File

@ -23,8 +23,8 @@ body.oc-loading * {
}
.stripe-loading-indicator .stripe {
width: 100%;
-webkit-animation: infinite-loader 60s linear;
animation: infinite-loader 60s linear;
-webkit-animation: oc-infinite-loader 60s linear;
animation: oc-infinite-loader 60s linear;
}
.stripe-loading-indicator .stripe-loaded {
width: 0;
@ -49,9 +49,150 @@ body.oc-loading * {
.stripe-loading-indicator.hide {
display: none;
}
@-moz-keyframes infinite-loader {
body > p.flash-message {
position: fixed;
width: 500px;
left: 50%;
top: 13px;
margin-left: -250px;
color: #ffffff;
font-size: 14px;
padding: 10px 30px 10px 15px;
z-index: 10300;
word-wrap: break-word;
text-shadow: 0 -1px 0px rgba(0, 0, 0, 0.15);
text-align: center;
-webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.24);
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.24);
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
body > p.flash-message.fade {
opacity: 0;
filter: alpha(opacity=0);
-webkit-transition: all 0.5s, width 0s;
transition: all 0.5s, width 0s;
-webkit-transform: scale(0.9);
-ms-transform: scale(0.9);
transform: scale(0.9);
}
body > p.flash-message.fade.in {
opacity: 1;
filter: alpha(opacity=100);
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
body > p.flash-message.success {
background: #8da85e;
}
body > p.flash-message.error {
background: #cc3300;
}
body > p.flash-message.warning {
background: #f0ad4e;
}
body > p.flash-message.info {
background: #5fb6f5;
}
body > p.flash-message button.close {
float: none;
position: absolute;
right: 10px;
top: 8px;
color: white;
font-size: 21px;
line-height: 1;
font-weight: bold;
opacity: 0.2;
filter: alpha(opacity=20);
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
outline: none;
}
body > p.flash-message button.close:hover,
body > p.flash-message button.close:focus {
color: white;
text-decoration: none;
cursor: pointer;
opacity: 0.5;
filter: alpha(opacity=50);
}
@media (max-width: 768px) {
body > p.flash-message {
left: 10px;
right: 10px;
top: 10px;
margin-left: 0;
width: auto;
}
}
[data-request][data-request-validate] [data-validate-for]:not(.visible),
[data-request][data-request-validate] [data-validate-error]:not(.visible) {
display: none;
}
a.oc-loading:after,
button.oc-loading:after {
content: '';
display: inline-block;
vertical-align: middle;
margin-left: .4em;
height: 1em;
width: 1em;
animation: oc-rotate-loader 0.8s infinite linear;
border: .2em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
opacity: 0.5;
filter: alpha(opacity=50);
}
@-moz-keyframes oc-rotate-loader {
0% {
width: 0%;
-moz-transform: rotate(0deg);
}
100% {
-moz-transform: rotate(360deg);
}
}
@-webkit-keyframes oc-rotate-loader {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@-o-keyframes oc-rotate-loader {
0% {
-o-transform: rotate(0deg);
}
100% {
-o-transform: rotate(360deg);
}
}
@-ms-keyframes oc-rotate-loader {
0% {
-ms-transform: rotate(0deg);
}
100% {
-ms-transform: rotate(360deg);
}
}
@keyframes oc-rotate-loader {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@-moz-keyframes oc-infinite-loader {
0% {
width: 0;
}
10% {
width: 42%;
@ -84,9 +225,9 @@ body.oc-loading * {
width: 99.9423761471391%;
}
}
@-webkit-keyframes infinite-loader {
@-webkit-keyframes oc-infinite-loader {
0% {
width: 0%;
width: 0;
}
10% {
width: 42%;
@ -119,9 +260,9 @@ body.oc-loading * {
width: 99.9423761471391%;
}
}
@-o-keyframes infinite-loader {
@-o-keyframes oc-infinite-loader {
0% {
width: 0%;
width: 0;
}
10% {
width: 42%;
@ -154,9 +295,9 @@ body.oc-loading * {
width: 99.9423761471391%;
}
}
@-ms-keyframes infinite-loader {
@-ms-keyframes oc-infinite-loader {
0% {
width: 0%;
width: 0;
}
10% {
width: 42%;
@ -189,9 +330,9 @@ body.oc-loading * {
width: 99.9423761471391%;
}
}
@keyframes infinite-loader {
@keyframes oc-infinite-loader {
0% {
width: 0%;
width: 0;
}
10% {
width: 42%;

View File

@ -5,23 +5,123 @@
* Copyright 2016 Alexey Bobkov, Samuel Georges
* ======================================================================== */
/*
* The stripe loading indicator.
*
* Displays the animated loading indicator stripe at the top of the page.
*
* JavaScript API:
* $.oc.stripeLoadIndicator.show(event)
* $.oc.stripeLoadIndicator.hide()
*
* By default if the show() method has been called several times, the hide() method should be
* called the same number of times in order to hide the stripe. Use hide(true) to hide the
* indicator forcibly.
*/
+function ($) { "use strict";
if ($.oc === undefined)
$.oc = {}
// @todo Provide an interface for configuration
// - Custom loader CSS class
// - Custom stripe loader color
var LOADER_CLASS = 'oc-loading';
// FLASH HANDLING
// ============================
$(document).on('ajaxError', '[data-request][data-request-flash]', function(event, context, message) {
if (!event.isDefaultPrevented() && message) {
$.oc.flashMsg({ text: message, class: 'error' })
event.preventDefault()
}
})
$(document).on('ajaxBeforeUpdate', '[data-request][data-request-flash]', function(event, context, data) {
if (data['X_OCTOBER_FLASH_MESSAGES']) {
$.each(data['X_OCTOBER_FLASH_MESSAGES'], function(type, message) {
$.oc.flashMsg({ text: message, class: type })
})
}
})
// FORM VALIDATION
// ============================
$(document).on('ajaxValidation', '[data-request][data-request-validate]', function(event, context, errorMsg, fields) {
var $this = $(this).closest('form'),
$container = $('[data-validate-error]', $this),
messages = [],
$field
$.each(fields, function(fieldName, fieldMessages) {
$field = $('[data-validate-for='+fieldName+']', $this)
messages = $.merge(messages, fieldMessages)
if (!!$field.length) {
if (!$field.text().length || $field.data('emptyMode') == true) {
$field
.data('emptyMode', true)
.text(fieldMessages.join(', '))
}
$field.addClass('visible')
}
})
if (!!$container.length) {
var $oldMessages = $('[data-message]', $container)
$container.addClass('visible')
if (!!$oldMessages.length) {
var $clone = $oldMessages.first()
$.each(messages, function(key, message) {
$clone.clone().text(message).insertAfter($clone)
})
$oldMessages.remove()
}
else {
$container.text(errorMsg)
}
}
$this.one('ajaxError', function(event){
event.preventDefault()
})
})
$(document).on('ajaxPromise', '[data-request][data-request-validate]', function() {
var $this = $(this).closest('form')
$('[data-validate-for]', $this).removeClass('visible')
$('[data-validate-error]', $this).removeClass('visible')
})
// LOADING BUTTONS
// ============================
$(document)
.on('ajaxPromise', '[data-request]', function() {
var $target = $(this)
if ($target.data('attach-loading') !== undefined) {
$target
.addClass(LOADER_CLASS)
.prop('disabled', true)
}
if ($target.is('form')) {
$('[data-attach-loading]', $target)
.addClass(LOADER_CLASS)
.prop('disabled', true)
}
})
.on('ajaxFail ajaxDone', '[data-request]', function() {
var $target = $(this)
if ($target.data('attach-loading') !== undefined) {
$target
.removeClass(LOADER_CLASS)
.prop('disabled', false)
}
if ($target.is('form')) {
$('[data-attach-loading]', $target)
.removeClass(LOADER_CLASS)
.prop('disabled', false)
}
})
// STRIPE LOAD INDICATOR
// ============================
var StripeLoadIndicator = function() {
var self = this
this.counter = 0
@ -41,8 +141,9 @@
// Restart the animation
this.stripe.after(this.stripe = this.stripe.clone()).remove()
if (this.counter > 1)
if (this.counter > 1) {
return
}
this.indicator.removeClass('loaded')
$(document.body).addClass('oc-loading')
@ -50,8 +151,10 @@
StripeLoadIndicator.prototype.hide = function(force) {
this.counter--
if (force !== undefined && force)
if (force !== undefined && force) {
this.counter = 0
}
if (this.counter <= 0) {
this.indicator.addClass('loaded')
@ -62,7 +165,7 @@
$.oc.stripeLoadIndicator = new StripeLoadIndicator()
// STRIPE LOAD INDICATOR DATA-API
// ==============
// ============================
$(document)
.on('ajaxPromise', '[data-request]', function(event) {
@ -79,9 +182,75 @@
if ($el.closest('html').length === 0)
$.oc.stripeLoadIndicator.hide()
})
}).on('ajaxFail ajaxDone', '[data-request]', function(event) {
})
.on('ajaxFail ajaxDone', '[data-request]', function(event) {
event.stopPropagation()
$.oc.stripeLoadIndicator.hide()
})
// FLASH MESSAGE
// ============================
var FlashMessage = function (options, el) {
var
options = $.extend({}, FlashMessage.DEFAULTS, options),
$element = $(el)
$('body > p.flash-message').remove()
if ($element.length == 0) {
$element = $('<p />').addClass(options.class).html(options.text)
}
$element
.addClass('flash-message fade')
.attr('data-control', null)
.on('click', 'button', remove)
.on('click', remove)
.append('<button type="button" class="close" aria-hidden="true">&times;</button>')
$(document.body).append($element)
setTimeout(function() {
$element.addClass('in')
}, 100)
var timer = window.setTimeout(remove, options.interval * 1000)
function removeElement() {
$element.remove()
}
function remove() {
window.clearInterval(timer)
$element.removeClass('in')
$.support.transition && $element.hasClass('fade')
? $element
.one($.support.transition.end, removeElement)
.emulateTransitionEnd(500)
: removeElement()
}
}
FlashMessage.DEFAULTS = {
class: 'success',
text: 'Default text',
interval: 2
}
if ($.oc === undefined)
$.oc = {}
$.oc.flashMsg = FlashMessage
// FLASH MESSAGE DATA-API
// ===============
$(document).render(function(){
$('[data-control=flash-message]').each(function(){
$.oc.flashMsg($(this).data(), this)
})
})
}(window.jQuery);

View File

@ -10,6 +10,7 @@ body.oc-loading, body.oc-loading * {
@stripe-loader-color: #0090c0;
@stripe-loader-height: 5px;
.stripe-loading-indicator {
height: @stripe-loader-height;
@ -31,7 +32,7 @@ body.oc-loading, body.oc-loading * {
.stripe {
width: 100%;
.animation(infinite-loader 60s linear);
.animation(oc-infinite-loader 60s linear);
}
.stripe-loaded {
@ -55,6 +56,138 @@ body.oc-loading, body.oc-loading * {
}
}
//
// Flash Messages
// --------------------------------------------------
@color-flash-success-bg: #8da85e;
@color-flash-error-bg: #cc3300;
@color-flash-warning-bg: #f0ad4e;
@color-flash-info-bg: #5fb6f5;
@color-flash-text: #ffffff;
body > p.flash-message {
position: fixed;
width: 500px;
left: 50%;
top: 13px;
margin-left: -250px;
color: @color-flash-text;
font-size: 14px;
padding: 10px 30px 10px 15px;
z-index: @zindex-flashmessage;
word-wrap: break-word;
text-shadow: 0 -1px 0px rgba(0,0,0,.15);
text-align: center;
.box-shadow(@overlay-box-shadow);
.border-radius(@border-radius-base);
&.fade {
.opacity(0);
.transition(~'all 0.5s, width 0s');
.transform(~'scale(0.9)');
}
&.fade.in {
.opacity(1);
.transform( ~'scale(1)');
}
&.success { background: @color-flash-success-bg; }
&.error { background: @color-flash-error-bg; }
&.warning { background: @color-flash-warning-bg; }
&.info { background: @color-flash-info-bg; }
button.close {
float: none;
position: absolute;
right: 10px;
top: 8px;
color: white;
font-size: 21px;
line-height: 1;
font-weight: bold;
.opacity(.2);
padding: 0;
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
outline: none;
&:hover,
&:focus {
color: white;
text-decoration: none;
cursor: pointer;
.opacity(.5);
}
}
}
@media (max-width: @screen-sm) {
body > p.flash-message {
left: 10px;
right: 10px;
top: 10px;
margin-left: 0;
width: auto;
}
}
//
// Form Validation
// --------------------------------------------------
[data-request][data-request-validate] [data-validate-for],
[data-request][data-request-validate] [data-validate-error] {
&:not(.visible) {
display: none;
}
}
//
// Element Loader
// --------------------------------------------------
a.oc-loading, button.oc-loading {
&:after {
content: '';
display: inline-block;
vertical-align: middle;
margin-left: .4em;
height: 1em;
width: 1em;
animation: oc-rotate-loader 0.8s infinite linear;
border: .2em solid currentColor;
border-right-color: transparent;
border-radius: 50%;
.opacity(.5);
}
}
@-moz-keyframes oc-rotate-loader {
0% { -moz-transform: rotate(0deg); }
100% { -moz-transform: rotate(360deg); }
}
@-webkit-keyframes oc-rotate-loader {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@-o-keyframes oc-rotate-loader {
0% { -o-transform: rotate(0deg); }
100% { -o-transform: rotate(360deg); }
}
@-ms-keyframes oc-rotate-loader {
0% { -ms-transform: rotate(0deg); }
100% { -ms-transform: rotate(360deg); }
}
@keyframes oc-rotate-loader {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
//
// Infinite loading animation
// --------------------------------------------------
@ -62,6 +195,7 @@ body.oc-loading, body.oc-loading * {
@startCount: 1;
@startVal: 28%;
@start: 0;
.infinite-class (@index, @val, @count) when (@index = 0) {
@tmpSelector: ~"@{index}%";
@{tmpSelector} { width: 0; }
@ -73,18 +207,18 @@ body.oc-loading, body.oc-loading * {
.infinite-class(@index + 10, @val + (@val / @count), @count * 2);
}
@-moz-keyframes infinite-loader {
@-moz-keyframes oc-infinite-loader {
.infinite-class(@start, @startVal, @startCount);
}
@-webkit-keyframes infinite-loader {
@-webkit-keyframes oc-infinite-loader {
.infinite-class(@start, @startVal, @startCount);
}
@-o-keyframes infinite-loader {
@-o-keyframes oc-infinite-loader {
.infinite-class(@start, @startVal, @startCount);
}
@-ms-keyframes infinite-loader {
@-ms-keyframes oc-infinite-loader {
.infinite-class(@start, @startVal, @startCount);
}
@keyframes infinite-loader {
@keyframes oc-infinite-loader {
.infinite-class(@start, @startVal, @startCount);
}

View File

@ -16,7 +16,7 @@
$('body > p.flash-message').remove()
if ($element.length == 0) {
$element = $('<p/>').addClass(options.class).html(options.text)
$element = $('<p />').addClass(options.class).html(options.text)
}
$element.addClass('flash-message fade')
@ -29,9 +29,9 @@
setTimeout(function() {
$element.addClass('in')
}, 1)
}, 100)
var timer = window.setTimeout(remove, options.interval*1000)
var timer = window.setTimeout(remove, options.interval * 1000)
function removeElement() {
$element.remove()
@ -41,11 +41,11 @@
window.clearInterval(timer)
$element.removeClass('in')
$.support.transition && $element.hasClass('fade') ?
$element
$.support.transition && $element.hasClass('fade')
? $element
.one($.support.transition.end, removeElement)
.emulateTransitionEnd(500) :
removeElement()
.emulateTransitionEnd(500)
: removeElement()
}
}
@ -72,4 +72,4 @@
})
})
}(window.jQuery);
}(window.jQuery);

File diff suppressed because one or more lines are too long