/* ======================================================================== * OctoberCMS: front-end JavaScript framework * http://octobercms.com * ======================================================================== * Copyright 2017 Alexey Bobkov, Samuel Georges * ======================================================================== */ /* October CMS JSON Parser */ "use strict";!function(){function a(e,r,n){for(var t="",o=r;o 0) { var _event = jQuery.Event('ajaxInvalidField') $(window).trigger(_event, [fieldElement.get(0), fieldName, fieldMessages, isFirstInvalidField]) if (isFirstInvalidField) { if (!_event.isDefaultPrevented()) fieldElement.focus() isFirstInvalidField = false } } }) }, /* * Custom function, display a flash message to the user */ handleFlashMessage: function(message, type) {}, /* * Custom function, redirect the browser to another location */ handleRedirectResponse: function(url) { window.location.href = url }, /* * Custom function, handle any application specific response values * Using a promisary object here in case injected assets need time to load */ handleUpdateResponse: function(data, textStatus, jqXHR) { /* * Update partials and finish request */ var updatePromise = $.Deferred().done(function() { for (var partial in data) { /* * If a partial has been supplied on the client side that matches the server supplied key, look up * it's selector and use that. If not, we assume it is an explicit selector reference. */ var selector = (options.update[partial]) ? options.update[partial] : partial if ($.type(selector) == 'string' && selector.charAt(0) == '@') { $(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) } else if ($.type(selector) == 'string' && selector.charAt(0) == '^') { $(selector.substring(1)).prepend(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) } else { $(selector).trigger('ajaxBeforeReplace') $(selector).html(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR]) } } /* * Wait for .html() method to finish rendering from partial updates */ setTimeout(function() { $(window) .trigger('ajaxUpdateComplete', [context, data, textStatus, jqXHR]) .trigger('resize') }, 0) }) /* * Handle redirect */ if (data['X_OCTOBER_REDIRECT']) { options.redirect = data['X_OCTOBER_REDIRECT'] isRedirect = true } if (isRedirect) { requestOptions.handleRedirectResponse(options.redirect) } /* * Handle validation */ if (data['X_OCTOBER_ERROR_FIELDS']) { requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'], data['X_OCTOBER_ERROR_FIELDS']) } /* * Handle asset injection */ if (data['X_OCTOBER_ASSETS']) { assetManager.load(data['X_OCTOBER_ASSETS'], $.proxy(updatePromise.resolve, updatePromise)) } else { updatePromise.resolve() } return updatePromise } } if (useFiles) { requestOptions.processData = requestOptions.contentType = false } /* * Allow default business logic to be called from user functions */ context.success = requestOptions.success context.error = requestOptions.error context.complete = requestOptions.complete requestOptions = $.extend(requestOptions, options) requestOptions.data = requestData /* * Initiate request */ if (options.confirm && !requestOptions.handleConfirmMessage(options.confirm)) { return } if (loading) loading.show() $(window).trigger('ajaxBeforeSend', [context]) $el.trigger('ajaxPromise', [context]) return $.ajax(requestOptions) .fail(function(jqXHR, textStatus, errorThrown) { if (!isRedirect) { $el.trigger('ajaxFail', [context, textStatus, jqXHR]) } if (loading) loading.hide() }) .done(function(data, textStatus, jqXHR) { if (!isRedirect) { $el.trigger('ajaxDone', [context, data, textStatus, jqXHR]) } if (loading) loading.hide() }) .always(function(dataOrXhr, textStatus, xhrOrError) { $el.trigger('ajaxAlways', [context, dataOrXhr, textStatus, xhrOrError]) }) } Request.DEFAULTS = { update: {}, type : 'POST', beforeUpdate: function(data, textStatus, jqXHR) {}, evalBeforeUpdate: null, evalSuccess: null, evalError: null, evalComplete: null, ajaxGlobal: false } /* * Internal function, build a string of partials and their update elements. */ Request.prototype.extractPartials = function(update) { var result = [] for (var partial in update) result.push(partial) return result.join('&') } // REQUEST PLUGIN DEFINITION // ============================ var old = $.fn.request $.fn.request = function(handler, option) { var args = arguments var $this = $(this).first() var data = { evalBeforeUpdate: $this.data('request-before-update'), evalSuccess: $this.data('request-success'), evalError: $this.data('request-error'), evalComplete: $this.data('request-complete'), ajaxGlobal: $this.data('request-ajax-global'), confirm: $this.data('request-confirm'), redirect: $this.data('request-redirect'), loading: $this.data('request-loading'), flash: $this.data('request-flash'), files: $this.data('request-files'), form: $this.data('request-form'), url: $this.data('request-url'), update: paramToObj('data-request-update', $this.data('request-update')), data: paramToObj('data-request-data', $this.data('request-data')) } if (!handler) handler = $this.data('request') var options = $.extend(true, {}, Request.DEFAULTS, data, typeof option == 'object' && option) return new Request($this, handler, options) } $.fn.request.Constructor = Request $.request = function(handler, option) { return $(document).request(handler, option) } // REQUEST NO CONFLICT // ================= $.fn.request.noConflict = function() { $.fn.request = old return this } // REQUEST DATA-API // ============== function paramToObj(name, value) { if (value === undefined) value = '' if (typeof value == 'object') return value try { return $.oc.JSON("{" + value + "}") } catch (e) { throw new Error('Error parsing the '+name+' attribute value. '+e) } } $(document).on('change', 'select[data-request], input[type=radio][data-request], input[type=checkbox][data-request], input[type=file][data-request]', function documentOnChange() { $(this).request() }) $(document).on('click', 'a[data-request], button[data-request], input[type=button][data-request], input[type=submit][data-request]', function documentOnClick(e) { e.preventDefault() $(this).request() if ($(this).is('[type=submit]')) return false }) $(document).on('keydown', 'input[type=text][data-request], input[type=submit][data-request], input[type=password][data-request]', function documentOnKeydown(e) { if (e.key === 'Enter') { if (this.dataTrackInputTimer !== undefined) window.clearTimeout(this.dataTrackInputTimer) $(this).request() return false } }) $(document).on('input', 'input[data-request][data-track-input]', function documentOnKeyup(e) { var $el = $(this), lastValue = $el.data('oc.lastvalue') if (!$el.is('[type=email],[type=number],[type=password],[type=search],[type=text]')) return if (lastValue !== undefined && lastValue == this.value) return $el.data('oc.lastvalue', this.value) if (this.dataTrackInputTimer !== undefined) window.clearTimeout(this.dataTrackInputTimer) var interval = $(this).data('track-input') if (!interval) interval = 300 var self = this this.dataTrackInputTimer = window.setTimeout(function() { if (self.lastDataTrackInputRequest) { self.lastDataTrackInputRequest.abort(); } self.lastDataTrackInputRequest = $(self).request(); }, interval) }) $(document).on('submit', '[data-request]', function documentOnSubmit() { $(this).request() return false }) $(window).on('beforeunload', function documentOnBeforeUnload() { window.ocUnloading = true }) /* * Invent our own event that unifies document.ready with window.ajaxUpdateComplete * * $(document).render(function() { }) * $(document).on('render', function() { }) */ $(document).ready(function triggerRenderOnReady() { $(document).trigger('render') }) $(window).on('ajaxUpdateComplete', function triggerRenderOnAjaxUpdateComplete() { $(document).trigger('render') }) $.fn.render = function(callback) { $(document).on('render', callback) } }(window.jQuery);