1/* ======================================================================== 2 * OctoberCMS: front-end JavaScript extras 3 * http://octobercms.com 4 * ======================================================================== 5 * Copyright 2016-2020 Alexey Bobkov, Samuel Georges 6 * ======================================================================== */ 7 8+function ($) { "use strict"; 9 if ($.oc === undefined) 10 $.oc = {} 11 12 // @todo Provide an interface for configuration 13 // - Custom loader CSS class 14 // - Custom stripe loader color 15 // - Flash message interval 16 17 var LOADER_CLASS = 'oc-loading'; 18 19 // FLASH HANDLING 20 // ============================ 21 22 $(document).on('ajaxSetup', '[data-request][data-request-flash]', function(event, context) { 23 context.options.handleErrorMessage = function(message) { 24 $.oc.flashMsg({ text: message, class: 'error' }) 25 } 26 27 context.options.handleFlashMessage = function(message, type) { 28 $.oc.flashMsg({ text: message, class: type }) 29 } 30 }) 31 32 // FORM VALIDATION 33 // ============================ 34 35 $(document).on('ajaxValidation', '[data-request][data-request-validate]', function(event, context, errorMsg, fields) { 36 var $this = $(this).closest('form'), 37 $container = $('[data-validate-error]', $this), 38 messages = [], 39 $field 40 41 $.each(fields, function(fieldName, fieldMessages) { 42 $field = $('[data-validate-for="'+fieldName+'"]', $this) 43 messages = $.merge(messages, fieldMessages) 44 if (!!$field.length) { 45 if (!$field.text().length || $field.data('emptyMode') == true) { 46 $field 47 .data('emptyMode', true) 48 .text(fieldMessages.join(', ')) 49 } 50 $field.addClass('visible') 51 } 52 }) 53 54 if (!!$container.length) { 55 $container = $('[data-validate-error]', $this) 56 } 57 58 if (!!$container.length) { 59 var $oldMessages = $('[data-message]', $container) 60 $container.addClass('visible') 61 62 if (!!$oldMessages.length) { 63 var $clone = $oldMessages.first() 64 65 $.each(messages, function(key, message) { 66 $clone.clone().text(message).insertAfter($clone) 67 }) 68 69 $oldMessages.remove() 70 } 71 else { 72 $container.text(errorMsg) 73 } 74 } 75 76 $this.one('ajaxError', function(event){ 77 event.preventDefault() 78 }) 79 }) 80 81 $(document).on('ajaxPromise', '[data-request][data-request-validate]', function() { 82 var $this = $(this).closest('form') 83 $('[data-validate-for]', $this).removeClass('visible') 84 $('[data-validate-error]', $this).removeClass('visible') 85 }) 86 87 // LOADING BUTTONS 88 // ============================ 89 90 $(document) 91 .on('ajaxPromise', '[data-request]', function() { 92 var $target = $(this) 93 94 if ($target.data('attach-loading') !== undefined) { 95 $target 96 .addClass(LOADER_CLASS) 97 .prop('disabled', true) 98 } 99 100 if ($target.is('form')) { 101 $('[data-attach-loading]', $target) 102 .addClass(LOADER_CLASS) 103 .prop('disabled', true) 104 } 105 }) 106 .on('ajaxFail ajaxDone', '[data-request]', function() { 107 var $target = $(this) 108 109 if ($target.data('attach-loading') !== undefined) { 110 $target 111 .removeClass(LOADER_CLASS) 112 .prop('disabled', false) 113 } 114 115 if ($target.is('form')) { 116 $('[data-attach-loading]', $target) 117 .removeClass(LOADER_CLASS) 118 .prop('disabled', false) 119 } 120 }) 121 122 // STRIPE LOAD INDICATOR 123 // ============================ 124 125 var StripeLoadIndicator = function() { 126 var self = this 127 this.counter = 0 128 this.indicator = $('<div/>').addClass('stripe-loading-indicator loaded') 129 .append($('<div />').addClass('stripe')) 130 .append($('<div />').addClass('stripe-loaded')) 131 this.stripe = this.indicator.find('.stripe') 132 133 $(document).ready(function() { 134 $(document.body).append(self.indicator) 135 }) 136 } 137 138 StripeLoadIndicator.prototype.show = function() { 139 this.counter++ 140 141 // Restart the animation 142 this.stripe.after(this.stripe = this.stripe.clone()).remove() 143 144 if (this.counter > 1) { 145 return 146 } 147 148 this.indicator.removeClass('loaded') 149 $(document.body).addClass('oc-loading') 150 } 151 152 StripeLoadIndicator.prototype.hide = function(force) { 153 this.counter-- 154 155 if (force !== undefined && force) { 156 this.counter = 0 157 } 158 159 if (this.counter <= 0) { 160 this.indicator.addClass('loaded') 161 $(document.body).removeClass('oc-loading') 162 } 163 } 164 165 $.oc.stripeLoadIndicator = new StripeLoadIndicator() 166 167 // STRIPE LOAD INDICATOR DATA-API 168 // ============================ 169 170 $(document) 171 .on('ajaxPromise', '[data-request]', function(event) { 172 // Prevent this event from bubbling up to a non-related data-request 173 // element, for example a <form> tag wrapping a <button> tag 174 event.stopPropagation() 175 176 $.oc.stripeLoadIndicator.show() 177
178 // This code will cover instances where the element has been removed 179 // from the DOM, making the resolution event below an orphan. 180 var $el = $(this) 181 $(window).one('ajaxUpdateComplete', function() { 182 if ($el.closest('html').length === 0) 183 $.oc.stripeLoadIndicator.hide() 184 }) 185 }) 186 .on('ajaxFail ajaxDone', '[data-request]', function(event) { 187 event.stopPropagation() 188 $.oc.stripeLoadIndicator.hide() 189 }) 190 191 // FLASH MESSAGE 192 // ============================ 193 194 var FlashMessage = function (options, el) { 195 var 196 options = $.extend({}, FlashMessage.DEFAULTS, options), 197 $element = $(el) 198 199 $('body > p.flash-message').remove() 200 201 if ($element.length == 0) { 202 $element = $('<p />').addClass(options.class).html(options.text) 203 } 204 205 $element 206 .addClass('flash-message fade') 207 .attr('data-control', null) 208 .on('click', 'button', remove) 209 .on('click', remove) 210 .append('<button type="button" class="close" aria-hidden="true">×</button>') 211 212 $(document.body).append($element) 213 214 setTimeout(function() { 215 $element.addClass('in') 216 }, 100) 217 218 var timer = window.setTimeout(remove, options.interval * 1000) 219 220 function removeElement() { 221 $element.remove() 222 } 223 224 function remove() { 225 window.clearInterval(timer) 226 227 $element.removeClass('in') 228 $.support.transition && $element.hasClass('fade') 229 ? $element 230 .one($.support.transition.end, removeElement) 231 .emulateTransitionEnd(500) 232 : removeElement() 233 } 234 } 235 236 FlashMessage.DEFAULTS = { 237 class: 'success', 238 text: 'Default text', 239 interval: 5 240 } 241 242 if ($.oc === undefined) 243 $.oc = {} 244 245 $.oc.flashMsg = FlashMessage 246 247 // FLASH MESSAGE DATA-API 248 // =============== 249 250 $(document).render(function(){ 251 $('[data-control=flash-message]').each(function(){ 252 $.oc.flashMsg($(this).data(), this) 253 }) 254 }) 255 256}(window.jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.