--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_skin/resources/js/myams-form.js Thu Feb 13 11:43:31 2020 +0100
@@ -0,0 +1,765 @@
+/**
+ * MyAMS forms management
+ */
+(function($, globals) {
+
+ var ams = globals.MyAMS;
+
+ ams.form = {
+
+ /**
+ * Init forms to activate form change listeners
+ *
+ * @param element: the parent element
+ */
+ init: function(element) {
+
+ $('FORM', element).each(function() {
+ var form = $(this);
+ // Store value of hidden inputs
+ $('INPUT.select2[type="hidden"]', form).each(function() {
+ var input = $(this);
+ input.data('ams-select2-input-value', input.val());
+ });
+ });
+
+ // Activate form changes if required
+ var forms;
+ if (ams.warnOnFormChange) {
+ forms = $('FORM[data-ams-warn-on-change!="false"]', element);
+ } else {
+ forms = $('FORM[data-ams-warn-on-change="true"]', element);
+ }
+ forms.each(function() {
+ var form = $(this),
+ formChangedCallback = form.data('ams-form-changed-callback') ||
+ ams.formChangedCallback;
+ $('INPUT[type="text"], ' +
+ 'INPUT[type="checkbox"], ' +
+ 'INPUT[type="radio"], ' +
+ 'SELECT, ' +
+ 'TEXTAREA, ' +
+ '[data-ams-changed-event]', form).each(function() {
+ var source = $(this);
+ if (source.data('ams-ignore-change') !== true) {
+ var event = source.data('ams-changed-event') || 'change';
+ source.on(event, function () {
+ ams.form.setChanged(form);
+ ams.executeFunctionByName(formChangedCallback, form, source);
+ });
+ }
+ });
+ form.on('reset', function() {
+ ams.form.resetChanged($(this));
+ });
+ });
+ },
+
+ /**
+ * Set focus to first container input
+ */
+ setFocus: function(container) {
+ var focused = $('[data-ams-focus-target]', container).first();
+ if (!focused.exists()) {
+ focused = $('input, select', container).first();
+ }
+ if (focused.exists()) {
+ if (focused.hasClass('select2-input')) {
+ focused = focused.parents('.select2');
+ }
+ if (focused.hasClass('select2')) {
+ setTimeout(function() {
+ focused.select2('focus');
+ if (focused.data('ams-focus-open') === true) {
+ focused.select2('open');
+ }
+ }, 100);
+ } else {
+ focused.focus();
+ }
+ }
+ },
+
+ /**
+ * Check for modified forms before exiting
+ */
+ checkBeforeUnload: function() {
+ var forms = $('FORM[data-ams-form-changed="true"]');
+ if (forms.exists()) {
+ return ams.i18n.FORM_CHANGED_WARNING;
+ }
+ },
+
+ /**
+ * Check for modified forms before loading new inner content
+ */
+ confirmChangedForm: function(element, callback, cancelCallback) {
+ if (typeof(element) === 'function') {
+ callback = element;
+ element = undefined;
+ }
+ var forms = $('FORM[data-ams-form-changed="true"]', element);
+ if (forms.exists()) {
+ if (cancelCallback) {
+ if (globals.confirm(ams.i18n.FORM_CHANGED_WARNING, ams.i18n.WARNING)) {
+ callback.call(element);
+ } else {
+ cancelCallback.call(element);
+ }
+ } else {
+ ams.skin && ams.skin.bigBox({
+ title: ams.i18n.WARNING,
+ content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i> ' + ams.i18n.FORM_CHANGED_WARNING,
+ buttons: ams.i18n.BTN_OK_CANCEL
+ }, function(button) {
+ if (button === ams.i18n.BTN_OK) {
+ callback.call(element);
+ }
+ });
+ }
+ } else {
+ callback.call(element);
+ }
+ },
+
+ /**
+ * Update form "chenged" status flag
+ */
+ setChanged: function(form) {
+ form.attr('data-ams-form-changed', true);
+ },
+
+ /**
+ * Reset form changed flag
+ */
+ resetChanged: function(form) {
+ if (form !== undefined) {
+ $(form).removeAttr('data-ams-form-changed');
+ }
+ },
+
+ /**
+ * Submit given form
+ */
+ submit: function(form, handler, submitOptions) {
+ // Check params
+ form = $(form);
+ if (!form.exists()) {
+ return false;
+ }
+ if (typeof(handler) === 'object') {
+ submitOptions = handler;
+ handler = undefined;
+ }
+ // Prevent multiple submits of the same form
+ if (form.data('submitted')) {
+ if (!form.data('ams-form-hide-submitted')) {
+ ams.skin && ams.skin.messageBox('warning', {
+ title: ams.i18n.WAIT,
+ content: ams.i18n.FORM_SUBMITTED,
+ icon: 'fa fa-save shake animated',
+ timeout: form.data('ams-form-alert-timeout') || 5000
+ });
+ }
+ return false;
+ }
+ // Check submit validators
+ if (ams.form && !ams.form._checkSubmitValidators(form)) {
+ return false;
+ }
+ // Remove remaining status messages
+ $('.alert-danger, SPAN.state-error', form).not('.persistent').remove();
+ $('.state-error', form).removeClassPrefix('state-');
+ // Check submit button
+ var button = $(form.data('ams-submit-button'));
+ if (button && !button.data('ams-form-hide-loading')) {
+ button.data('ams-progress-content', button.html());
+ button.button('loading');
+ }
+ ams.ajax && ams.ajax.check($.fn.ajaxSubmit,
+ ams.baseURL + 'ext/jquery-form-3.49' + ams.devext + '.js',
+ function() {
+
+ function _submitAjaxForm(form, options) {
+
+ var button,
+ buttonData,
+ buttonTarget,
+ data = form.data(),
+ formOptions = data.amsFormOptions,
+ formData,
+ formDataCallback;
+
+ var progressHandler,
+ progressInterval,
+ progressCallback,
+ progressEndCallback;
+
+ // Inner progress status handler
+ function _getProgress(handler, progress_id) {
+
+ var timeout;
+
+ function _clearProgressStatus() {
+ clearTimeout(timeout);
+ ams.form.resetAfterSubmit(form, button);
+ button.html(button.data('ams-progress-content'));
+ ams.executeFunctionByName(progressEndCallback, form, button);
+ ams.form.resetChanged(form);
+ }
+
+ function _getProgressStatus() {
+ ams.ajax && ams.ajax.post(handler,
+ {progress_id: progress_id},
+ {error: _clearProgressStatus},
+ ams.getFunctionByName(progressCallback) || function(result, status) {
+ if (status === 'success') {
+ if (result.status === 'running') {
+ if (result.message) {
+ button.text(result.message);
+ } else {
+ var text = button.data('ams-progress-text') || ams.i18n.PROGRESS;
+ if (result.current) {
+ text += ': ' + result.current + '/ ' + (result.length || 100);
+ } else {
+ text += '...';
+ }
+ button.text(text);
+ }
+ timeout = setTimeout(_getProgressStatus, progressInterval);
+ } else if (result.status === 'finished') {
+ _clearProgressStatus();
+ }
+ } else {
+ _clearProgressStatus();
+ }
+ });
+ }
+
+ button.button('loading');
+ timeout = setTimeout(_getProgressStatus, progressInterval);
+ }
+
+ // Initialize form data
+ if (submitOptions) {
+ formDataCallback = submitOptions.formDataInitCallback;
+ }
+ if (formDataCallback) {
+ delete submitOptions.formDataInitCallback;
+ } else {
+ formDataCallback = data.amsFormDataInitCallback;
+ }
+ if (formDataCallback) {
+ var veto = {};
+ formData = ams.executeFunctionByName(formDataCallback, form, veto);
+ if (veto.veto) {
+ button = form.data('ams-submit-button');
+ if (button) {
+ button.button('reset');
+ }
+ ams.form.finalizeSubmitFooter.call(form);
+ return false;
+ }
+ } else {
+ formData = data.amsFormData || {};
+ }
+
+ // Check submit button for custom action handler and target
+ button = $(form.data('ams-submit-button'));
+ if (button && button.exists()) {
+ buttonData = button.data();
+ buttonTarget = buttonData.amsFormSubmitTarget;
+ } else {
+ buttonData = {};
+ }
+
+ // Check action URL
+ var url;
+ var formHandler = handler || buttonData.amsFormHandler || data.amsFormHandler || '';
+ if (formHandler.startsWith(window.location.protocol)) {
+ url = formHandler;
+ } else {
+ var action = buttonData.amsFormAction || form.attr('action').replace(/#/, '');
+ if (action.startsWith(window.location.protocol)) {
+ url = action;
+ } else {
+ url = ams.ajax && (ams.ajax.getAddr() + action);
+ }
+ url += formHandler;
+ }
+ progressHandler = buttonData.amsProgressHandler || data.amsProgressHandler || '';
+ progressInterval = buttonData.amsProgressInterval || data.amsProgressInterval || 1000;
+ progressCallback = buttonData.amsProgressCallback || data.amsProgressCallback;
+ progressEndCallback = buttonData.amsProgressEndCallback || data.amsProgressEndCallback;
+
+ // Initialize submit target with AJAX indicator
+ var target = null;
+ if (submitOptions && submitOptions.initSubmitTarget) {
+ ams.executeFunctionByName(submitOptions.initSubmitTarget, form);
+ } else {
+ if (data.amsFormInitSubmitTarget) {
+ target = $(buttonTarget || data.amsFormSubmitTarget || '#content');
+ ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmit', form, target);
+ } else if (!data.amsFormHideSubmitFooter) {
+ ams.executeFunctionByName(data.amsFormInitSubmit || 'MyAMS.form.initSubmitFooter', form);
+ }
+ }
+
+ // Complete form data
+ if (submitOptions) {
+ formData = $.extend({}, formData, submitOptions.form_data);
+ }
+
+ // Check progress handler
+ var hasUpload;
+ if (progressHandler) {
+ formData.progress_id = ams.generateUUID();
+ } else {
+ // Check progress meter via Apache progress module
+ hasUpload = typeof (options.uuid) !== 'undefined';
+ if (hasUpload) {
+ if (url.indexOf('X-Progress-ID') < 0) {
+ url += "?X-Progress-ID=" + options.uuid;
+ }
+ delete options.uuid;
+ }
+ }
+
+ // Initialize default AJAX settings
+ var defaults = {
+ url: url,
+ type: 'post',
+ cache: false,
+ data: formData,
+ dataType: data.amsFormDatatype,
+ beforeSerialize: function(/*form, options*/) {
+ form.trigger('myams.form.before-serialize');
+ if (typeof (globals.tinyMCE) !== 'undefined') {
+ globals.tinyMCE.triggerSave();
+ }
+ },
+ beforeSubmit: function(data, form /*, options*/) {
+ form.trigger('myams.form.before-submit', [data]);
+ form.data('submitted', true);
+ if (form.data('ams-form-reset-before-submit')) {
+ setTimeout(function() {
+ ams.form.resetAfterSubmit(form);
+ }, 250);
+ }
+ },
+ error: function(request, status, error, form) {
+ form.trigger('myams.form.submit-error', [request, status, error]);
+ if (target) {
+ ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target);
+ }
+ ams.form.resetAfterSubmit(form);
+ },
+ iframe: hasUpload
+ };
+
+ // Initialize IFrame for custom download target
+ var downloadTarget = (submitOptions && submitOptions.downloadTarget) || data.amsFormDownloadTarget;
+ if (downloadTarget) {
+ var iframe = $('iframe[name="' + downloadTarget + '"]');
+ if (!iframe.exists()) {
+ iframe = $('<iframe></iframe>').hide()
+ .attr('name', downloadTarget)
+ .appendTo($('body'));
+ }
+ defaults = $.extend({}, defaults, {
+ iframe: true,
+ iframeTarget: iframe,
+ success: function(result, status, request, form) {
+ form.trigger('myams.form.after-submit', [result, status, request]);
+ var modal = $(form).parents('.modal-dialog');
+ if (modal.exists()) {
+ ams.dialog && ams.dialog.close(form);
+ } else {
+ var callback,
+ button = form.data('ams-submit-button');
+ if (button) {
+ callback = button.data('ams-form-submit-callback');
+ }
+ if (!callback) {
+ callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
+ }
+ try {
+ callback.call(form, result, status, request, form);
+ } finally {
+ ams.form.resetAfterSubmit(form);
+ ams.form.resetChanged(form);
+ }
+ }
+ }
+ });
+ } else {
+ defaults = $.extend({}, defaults, {
+ error: function(request, status, error, form) {
+ if (target) {
+ ams.executeFunctionByName(data.amsFormSubmitError || 'MyAMS.form.finalizeSubmitOnError', form, target);
+ }
+ ams.form.resetAfterSubmit(form);
+ },
+ success: function(result, status, request, form) {
+ form.trigger('myams.form.after-submit', [result, status, request]);
+ var callback,
+ button = form.data('ams-submit-button');
+ if (button) {
+ callback = button.data('ams-form-submit-callback');
+ }
+ if (!callback) {
+ callback = ams.getFunctionByName(data.amsFormSubmitCallback) || ams.form._submitCallback;
+ }
+ try {
+ callback.call(form, result, status, request, form);
+ } finally {
+ ams.form.resetAfterSubmit(form);
+ ams.form.resetChanged(form);
+ }
+ },
+ iframe: hasUpload
+ });
+ }
+ var settings = $.extend({}, defaults, options, formOptions, submitOptions);
+
+ // Initialize progress handler
+ if (progressHandler) {
+ _getProgress(progressHandler, formData.progress_id);
+ }
+
+ // Submit form
+ $(form).ajaxSubmit(settings);
+
+ // If external download target is specified, reset form submit button and footer
+ if (downloadTarget) {
+ var modal = $(form).parents('.modal-dialog');
+ var keepModal = modal.exists() && button.exists() && button.data('ams-keep-modal');
+ if (modal.exists() && (keepModal !== true)) {
+ ams.dialog && ams.dialog.close(form);
+ } else {
+ if (!progressHandler) {
+ setTimeout(function() {
+ ams.form.resetAfterSubmit(form, button);
+ ams.form.resetChanged(form);
+ }, button.data('ams-form-reset-timeout') || 2000);
+ }
+ }
+ }
+ }
+
+ var hasUpload = (form.data('ams-form-ignore-uploads') !== true) &&
+ ($('INPUT[type="file"]', form).length > 0);
+ if (hasUpload) {
+ // JQuery-progressbar plug-in must be loaded synchronously!!
+ // Otherwise, hidden input fields created by jquery-validate plug-in
+ // and matching named buttons will be deleted (on first form submit)
+ // before JQuery-form plug-in can get them when submitting the form...
+ ams.ajax && ams.ajax.check($.progressBar,
+ ams.baseURL + 'ext/jquery-progressbar' + ams.devext + '.js');
+ var settings = $.extend({}, {
+ uuid: $.progressBar.submit(form)
+ });
+ _submitAjaxForm(form, settings);
+ } else {
+ _submitAjaxForm(form, {});
+ }
+ });
+ return false;
+ },
+
+ /**
+ * Initialize AJAX submit call
+ *
+ * @param this: the submitted form
+ * @param target: the form submit container target
+ * @param message: the optional message
+ */
+ initSubmit: function(target, message) {
+ var form = $(this),
+ spin = '<i class="fa fa-3x fa-gear fa-spin"></i>';
+ if (!message) {
+ message = form.data('ams-form-submit-message');
+ }
+ if (message) {
+ spin += '<strong>' + message + '</strong>';
+ }
+ $(target).html('<div class="row margin-20"><div class="text-center">' + spin + '</div></div>');
+ $(target).parents('.hidden').removeClass('hidden');
+ },
+
+ /**
+ * Reset form status after submit
+ *
+ * @param form: the submitted form
+ */
+ resetAfterSubmit: function(form) {
+ if (form.data('submitted')) {
+ if (form.is(':visible')) {
+ var button = form.data('ams-submit-button');
+ if (button) {
+ button.button('reset');
+ }
+ ams.form.finalizeSubmitFooter.call(form);
+ }
+ form.data('submitted', false);
+ form.removeData('ams-submit-button');
+ form.trigger('myams.form.after-reset');
+ }
+ },
+
+ /**
+ * Finalize AJAX submit call
+ *
+ * @param target: the form submit container target
+ */
+ finalizeSubmitOnError: function(target) {
+ $('i', target).removeClass('fa-spin')
+ .removeClass('fa-gear')
+ .addClass('fa-ambulance');
+ },
+
+ /**
+ * Initialize AJAX submit call in form footer
+ *
+ * @param this: the submitted form
+ * @param message: the optional submit message
+ */
+ initSubmitFooter: function(message) {
+ var form = $(this),
+ spin = '<i class="fa fa-3x fa-gear fa-spin"></i>';
+ if (!message) {
+ message = $(this).data('ams-form-submit-message');
+ }
+ if (message) {
+ spin += '<strong class="submit-message align-top padding-left-10 margin-top-10">' + message + '</strong>';
+ }
+ var footer = $('footer', form);
+ $('button', footer).hide();
+ footer.append('<div class="row"><div class="text-center">' + spin + '</div></div>');
+ },
+
+ /**
+ * Finalize AJAX submit call
+ *
+ * @param this: the submitted form
+ * @param target: the form submit container target
+ */
+ finalizeSubmitFooter: function(/*target*/) {
+ var form = $(this),
+ footer = $('footer', form);
+ if (footer) {
+ $('.row', footer).remove();
+ $('button', footer).show();
+ }
+ },
+
+ /**
+ * Handle AJAX submit results
+ *
+ * Submit results are auto-detected via response content type, except when this content type
+ * is specified into form's data attributes.
+ * Submit response can be of several content types:
+ * - html or text: the response is directly included into a "target" container (#content by default)
+ * - json: a "status" attribute indicates how the request was handled and how the response should be
+ * treated:
+ * - error: indicates that an error occured; other response attributes indicate error messages
+ * - success: basic success, no other action is requested
+ * - callback: only call given function to handle the result
+ * - callbacks: only call given set of functions to handle the result
+ * - reload: page's body should be reloaded from a given URL
+ * - redirect: redirect browser to given URL
+ * Each JSON response can also specify an HTML content, a message and a callback (
+ */
+ _submitCallback: function(result, status, request, form) {
+
+ var button;
+ if (form.is(':visible')) {
+ ams.form.finalizeSubmitFooter.call(form);
+ button = form.data('ams-submit-button');
+ if (button) {
+ button.button('reset');
+ }
+ }
+
+ var data = form.data(),
+ dataType;
+ if (data.amsFormDatatype) {
+ dataType = data.amsFormDatatype;
+ } else {
+ var response = ams.ajax && ams.ajax.getResponse(request);
+ if (response) {
+ dataType = response.contentType;
+ result = response.data;
+ }
+ }
+
+ var target;
+ if (button) {
+ target = $(button.data('ams-form-submit-target') || data.amsFormSubmitTarget || '#content');
+ } else {
+ target = $(data.amsFormSubmitTarget || '#content');
+ }
+
+ switch (dataType) {
+ case 'json':
+ ams.ajax && ams.ajax.handleJSON(result, form, target);
+ break;
+ case 'script':
+ break;
+ case 'xml':
+ break;
+ case 'html':
+ /* falls through */
+ case 'text':
+ /* falls through */
+ default:
+ ams.form.resetChanged(form);
+ if (button && (button.data('ams-keep-modal') !== true)) {
+ ams.dialog && ams.dialog.close(form);
+ }
+ if (!target.exists()) {
+ target = $('body');
+ }
+ target.parents('.hidden').removeClass('hidden');
+ $('.alert', target.parents('.alerts-container')).remove();
+ target.css({opacity: '0.0'})
+ .html(result)
+ .delay(50)
+ .animate({opacity: '1.0'}, 300);
+ ams.initContent && ams.initContent(target);
+ ams.form.setFocus(target);
+ }
+ var callback = request.getResponseHeader('X-AMS-Callback');
+ if (callback) {
+ var options = request.getResponseHeader('X-AMS-Callback-Options');
+ ams.executeFunctionByName(callback, form, options === undefined ? {} : JSON.parse(options), request);
+ }
+ },
+
+ /**
+ * Get list of custom validators called before submit
+ */
+ _getSubmitValidators: function(form) {
+ var validators = [];
+ var formValidator = form.data('ams-form-validator');
+ if (formValidator) {
+ validators.push([form, formValidator]);
+ }
+ $('[data-ams-form-validator]', form).each(function() {
+ var source = $(this);
+ validators.push([source, source.data('ams-form-validator')]);
+ });
+ return validators;
+ },
+
+ /**
+ * Call list of custom validators before submit
+ *
+ * Each validator can return:
+ * - a boolean 'false' value to just specify that an error occured
+ * - a string value containing an error message
+ * - an array containing a list of string error messages
+ * Any other value (undefined, null, True...) will lead to a successful submit.
+ */
+ _checkSubmitValidators: function(form) {
+ var validators = ams.form._getSubmitValidators(form);
+ if (!validators.length) {
+ return true;
+ }
+ var output = [],
+ result = true;
+ for (var index=0; index < validators.length; index++) {
+ var validator = validators[index],
+ source = validator[0],
+ handler = validator[1],
+ validatorResult = ams.executeFunctionByName(handler, form, source);
+ if (validatorResult === false) {
+ result = false;
+ } else if (typeof(validatorResult) === 'string') {
+ output.push(validatorResult);
+ } else if (result.length && (result.length > 0)) {
+ output = output.concat(result);
+ }
+ }
+ if (output.length > 0) {
+ var header = output.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED;
+ ams.skin && ams.skin.alert(form, 'danger', header, output);
+ return false;
+ } else {
+ return result;
+ }
+ },
+
+ /**
+ * Display JSON errors
+ * JSON errors should be defined in an object as is:
+ * {status: 'error',
+ * error_message: "Main error message",
+ * messages: ["Message 1", "Message 2",...]
+ * widgets: [{label: "First widget name",
+ * name: "field-name-1",
+ * message: "Error message"},
+ * {label: "Second widget name",
+ * name: "field-name-2",
+ * message: "Second error message"},...]}
+ */
+ showErrors: function(form, errors) {
+ var header;
+ if (typeof(errors) === 'string') {
+ ams.skin && ams.skin.alert(form, 'error', ams.i18n.ERROR_OCCURED, errors);
+ } else if (errors instanceof Array) {
+ header = errors.length === 1 ? ams.i18n.ERROR_OCCURED : ams.i18n.ERRORS_OCCURED;
+ ams.skin && ams.skin.alert(form, 'error', header, errors);
+ } else {
+ $('.state-error', form).removeClass('state-error');
+ header = errors.error_header ||
+ (errors.widgets && (errors.widgets.length > 1) ? ams.i18n.ERRORS_OCCURED : ams.i18n.ERROR_OCCURED);
+ var message = [];
+ var index;
+ if (errors.messages) {
+ for (index = 0; index < errors.messages.length; index++) {
+ var msg = errors.messages[index];
+ if (msg.header) {
+ message.push('<strong>' + msg.header + '</strong><br />' + msg.message);
+ } else {
+ message.push(msg.message || msg);
+ }
+ }
+ }
+ if (errors.widgets) {
+ for (index = 0; index < errors.widgets.length; index++) {
+ // set widget status message
+ var widgetData = errors.widgets[index];
+ var widget = $('[name="' + widgetData.name + '"]', form);
+ if (!widget.exists()) {
+ widget = $('[name="' + widgetData.name + ':list"]', form);
+ }
+ if (widget.exists()) {
+ // Update widget state
+ widget.parents('label, .input')
+ .first()
+ .removeClassPrefix('state-')
+ .addClass('state-error')
+ .after('<span for="name" class="state-error">' + widgetData.message + '</span>');
+ } else {
+ // complete form alert message
+ if (widgetData.label) {
+ message.push(widgetData.label + ' : ' + widgetData.message);
+ }
+ }
+ // mark parent tab (if any) with error status
+ var tabIndex = widget.parents('.tab-pane').index() + 1;
+ if (tabIndex > 0) {
+ var navTabs = $('.nav-tabs', $(widget).parents('.tabforms'));
+ $('li:nth-child(' + tabIndex + ')', navTabs).removeClassPrefix('state-')
+ .addClass('state-error');
+ $('li.state-error:first a', form).click();
+ }
+ }
+ }
+ ams.skin && ams.skin.alert($('.form-group:first', form), errors.error_level || 'error', header, message, errors.error_message);
+ }
+ }
+ };
+
+})(jQuery, this);