Files
SkinbaseNova/public/legacy/assets/plugins/parsley/extra/plugin/remote.js
2026-02-07 08:23:18 +01:00

254 lines
7.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// `window.ParsleyExtend`, like `ParsleyAbstract`, is inherited by `ParsleyField` and `ParsleyForm`
// That way, we could add new methods or redefine some for these both classes. In particular case
// We are adding async validation methods that returns promises, bind them properly to triggered
// Events like onkeyup when field is invalid or on form submit. These validation methods adds an
// Extra `remote` validator which could not be simply added like other `ParsleyExtra` validators
// Because returns promises instead of booleans.
window.ParsleyExtend = window.ParsleyExtend || {};
window.ParsleyExtend = $.extend(window.ParsleyExtend, {
asyncSupport: true,
asyncValidators: $.extend({
default: {
fn: function (xhr) {
return 'resolved' === xhr.state();
},
url: false
},
reverse: {
fn: function (xhr) {
// If reverse option is set, a failing ajax request is considered successful
return 'rejected' === xhr.state();
},
url: false
}
}, window.ParsleyExtend.asyncValidators),
addAsyncValidator: function (name, fn, url) {
this.asyncValidators[name.toLowerCase()] = {
fn: fn,
url: url || false
};
return this;
},
asyncValidate: function () {
if ('ParsleyForm' === this.__class__)
return this._asyncValidateForm.apply(this, arguments);
return this._asyncValidateField.apply(this, arguments);
},
asyncIsValid: function () {
if ('ParsleyField' === this.__class__)
return this._asyncIsValidField.apply(this, arguments);
return this._asyncIsValidForm.apply(this, arguments);
},
onSubmitValidate: function (event) {
var that = this;
// This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
if (true === event.parsley)
return;
// Clone the event object
this.submitEvent = $.extend(true, {}, event);
// Prevent form submit and immediately stop its event propagation
if (event instanceof $.Event) {
event.stopImmediatePropagation();
event.preventDefault();
}
return this._asyncValidateForm(undefined, event)
.done(function () {
// If user do not have prevented the event, re-submit form
if (!that.submitEvent.isDefaultPrevented())
that.$element.trigger($.extend($.Event('submit'), { parsley: true }));
});
},
eventValidate: function (event) {
// For keyup, keypress, keydown.. events that could be a little bit obstrusive
// do not validate if val length < min threshold on first validation. Once field have been validated once and info
// about success or failure have been displayed, always validate with this trigger to reflect every yalidation change.
if (new RegExp('key').test(event.type))
if (!this._ui.validationInformationVisible && this.getValue().length <= this.options.validationThreshold)
return;
this._ui.validatedOnce = true;
this.asyncValidate();
},
// Returns Promise
_asyncValidateForm: function (group, event) {
var
that = this,
promises = [];
this._refreshFields();
$.emit('parsley:form:validate', this);
for (var i = 0; i < this.fields.length; i++) {
// do not validate a field if not the same as given validation group
if (group && group !== this.fields[i].options.group)
continue;
promises.push(this.fields[i]._asyncValidateField());
}
return $.when.apply($, promises)
.always(function () {
$.emit('parsley:form:validated', that);
});
},
_asyncIsValidForm: function (group, force) {
var promises = [];
this._refreshFields();
for (var i = 0; i < this.fields.length; i++) {
// do not validate a field if not the same as given validation group
if (group && group !== this.fields[i].options.group)
continue;
promises.push(this.fields[i]._asyncIsValidField(force));
}
return $.when.apply($, promises);
},
_asyncValidateField: function (force) {
var that = this;
$.emit('parsley:field:validate', this);
return this._asyncIsValidField(force)
.done(function () {
$.emit('parsley:field:success', that);
})
.fail(function () {
$.emit('parsley:field:error', that);
})
.always(function () {
$.emit('parsley:field:validated', that);
});
},
_asyncIsValidField: function (force, value) {
var
deferred = $.Deferred(),
remoteConstraintIndex;
// If regular isValid (matching regular constraints) returns `false`, no need to go further
// Directly reject promise, do not run remote validator and save server load
if (false === this.isValid(force, value))
deferred.rejectWith(this);
// If regular constraints are valid, and there is a remote validator registered, run it
else if ('undefined' !== typeof this.constraintsByName.remote)
this._remote(deferred);
// Otherwise all is good, resolve promise
else
deferred.resolveWith(this);
// Return promise
return deferred.promise();
},
_remote: function (deferred) {
var
that = this,
data = {},
ajaxOptions,
csr,
validator = this.options.remoteValidator || (true === this.options.remoteReverse ? 'reverse' : 'default');
validator = validator.toLowerCase();
if ('undefined' === typeof this.asyncValidators[validator])
throw new Error('Calling an undefined async validator: `' + validator + '`');
// Fill data with current value
data[this.$element.attr('name') || this.$element.attr('id')] = this.getValue();
// All `$.ajax(options)` could be overridden or extended directly from DOM in `data-parsley-remote-options`
ajaxOptions = $.extend(true, {}, {
url: this.asyncValidators[validator].url || this.options.remote,
data: data,
type: 'GET'
}, this.options.remoteOptions || {});
// Generate store key based on ajax options
csr = $.param(ajaxOptions);
// Initialise querry cache
if ('undefined' === typeof this._remoteCache)
this._remoteCache = {};
// Try to retrieve stored xhr
if (!this._remoteCache[csr]) {
// Prevent multi burst xhr queries
if (this._xhr && 'pending' === this._xhr.state())
this._xhr.abort();
// Make ajax call
this._xhr = $.ajax(ajaxOptions)
// Store remote call result to avoid next calls with exact same parameters
this._remoteCache[csr] = this._xhr;
}
this._remoteCache[csr]
.done(function (data, textStatus, xhr) {
that._handleRemoteResult(validator, xhr, deferred);
})
.fail(function (xhr, status, message) {
// If we aborted the query, do not handle nothing for this value
if ('abort' === status)
return;
that._handleRemoteResult(validator, xhr, deferred);
});
},
_handleRemoteResult: function (validator, xhr, deferred) {
// If true, simply resolve and exit
if ('function' === typeof this.asyncValidators[validator].fn && this.asyncValidators[validator].fn(xhr)) {
deferred.resolveWith(this);
return;
}
// Else, create a proper remote validation Violation to trigger right UI
this.validationResult = [
new window.ParsleyValidator.Validator.Violation(
this.constraintsByName.remote,
this.getValue(),
null
)
];
deferred.rejectWith(this);
}
});
// Remote validator is just an always true sync validator with lowest (-1) priority possible
// It will be overloaded in `validateThroughValidator()` that will do the heavy async work
// This 'hack' is needed not to mess up too much with error messages and stuff in `ParsleyUI`
window.ParsleyConfig = window.ParsleyConfig || {};
window.ParsleyConfig.validators = window.ParsleyConfig.validators || {};
window.ParsleyConfig.validators.remote = {
fn: function () {
return true;
},
priority: -1
};