Current File : /home/tradevaly/www/node_modules/parsleyjs/src/parsley/form.js |
import $ from 'jquery';
import Base from './base';
import Utils from './utils';
var Form = function (element, domOptions, options) {
this.__class__ = 'Form';
this.element = element;
this.$element = $(element);
this.domOptions = domOptions;
this.options = options;
this.parent = window.Parsley;
this.fields = [];
this.validationResult = null;
};
var statusMapping = {pending: null, resolved: true, rejected: false};
Form.prototype = {
onSubmitValidate: function (event) {
// This is a Parsley generated submit event, do not validate, do not prevent, simply exit and keep normal behavior
if (true === event.parsley)
return;
// If we didn't come here through a submit button, use the first one in the form
var submitSource = this._submitSource || this.$element.find(Utils._SubmitSelector)[0];
this._submitSource = null;
this.$element.find('.parsley-synthetic-submit-button').prop('disabled', true);
if (submitSource && null !== submitSource.getAttribute('formnovalidate'))
return;
window.Parsley._remoteCache = {};
var promise = this.whenValidate({event});
if ('resolved' === promise.state() && false !== this._trigger('submit')) {
// All good, let event go through. We make this distinction because browsers
// differ in their handling of `submit` being called from inside a submit event [#1047]
} else {
// Rejected or pending: cancel this submit
event.stopImmediatePropagation();
event.preventDefault();
if ('pending' === promise.state())
promise.done(() => { this._submit(submitSource); });
}
},
onSubmitButton: function(event) {
this._submitSource = event.currentTarget;
},
// internal
// _submit submits the form, this time without going through the validations.
// Care must be taken to "fake" the actual submit button being clicked.
_submit: function (submitSource) {
if (false === this._trigger('submit'))
return;
// Add submit button's data
if (submitSource) {
var $synthetic = this.$element.find('.parsley-synthetic-submit-button').prop('disabled', false);
if (0 === $synthetic.length)
$synthetic = $('<input class="parsley-synthetic-submit-button" type="hidden">').appendTo(this.$element);
$synthetic.attr({
name: submitSource.getAttribute('name'),
value: submitSource.getAttribute('value')
});
}
this.$element.trigger(Object.assign($.Event('submit'), {parsley: true}));
},
// Performs validation on fields while triggering events.
// @returns `true` if all validations succeeds, `false`
// if a failure is immediately detected, or `null`
// if dependant on a promise.
// Consider using `whenValidate` instead.
validate: function (options) {
if (arguments.length >= 1 && !$.isPlainObject(options)) {
Utils.warnOnce('Calling validate on a parsley form without passing arguments as an object is deprecated.');
var [group, force, event] = arguments;
options = {group, force, event};
}
return statusMapping[ this.whenValidate(options).state() ];
},
whenValidate: function ({group, force, event} = {}) {
this.submitEvent = event;
if (event) {
this.submitEvent = Object.assign({}, event, {preventDefault: () => {
Utils.warnOnce("Using `this.submitEvent.preventDefault()` is deprecated; instead, call `this.validationResult = false`");
this.validationResult = false;
}});
}
this.validationResult = true;
// fire validate event to eventually modify things before every validation
this._trigger('validate');
// Refresh form DOM options and form's fields that could have changed
this._refreshFields();
var promises = this._withoutReactualizingFormOptions(() => {
return $.map(this.fields, field => field.whenValidate({force, group}));
});
return Utils.all(promises)
.done( () => { this._trigger('success'); })
.fail( () => {
this.validationResult = false;
this.focus();
this._trigger('error');
})
.always(() => { this._trigger('validated'); })
.pipe(...this._pipeAccordingToValidationResult());
},
// Iterate over refreshed fields, and stop on first failure.
// Returns `true` if all fields are valid, `false` if a failure is detected
// or `null` if the result depends on an unresolved promise.
// Prefer using `whenValid` instead.
isValid: function (options) {
if (arguments.length >= 1 && !$.isPlainObject(options)) {
Utils.warnOnce('Calling isValid on a parsley form without passing arguments as an object is deprecated.');
var [group, force] = arguments;
options = {group, force};
}
return statusMapping[ this.whenValid(options).state() ];
},
// Iterate over refreshed fields and validate them.
// Returns a promise.
// A validation that immediately fails will interrupt the validations.
whenValid: function ({group, force} = {}) {
this._refreshFields();
var promises = this._withoutReactualizingFormOptions(() => {
return $.map(this.fields, field => field.whenValid({group, force}));
});
return Utils.all(promises);
},
refresh: function() {
this._refreshFields();
return this;
},
// Reset UI
reset: function () {
// Form case: emit a reset event for each field
for (var i = 0; i < this.fields.length; i++)
this.fields[i].reset();
this._trigger('reset');
},
// Destroy Parsley instance (+ UI)
destroy: function () {
// Field case: emit destroy event to clean UI and then destroy stored instance
this._destroyUI();
// Form case: destroy all its fields and then destroy stored instance
for (var i = 0; i < this.fields.length; i++)
this.fields[i].destroy();
this.$element.removeData('Parsley');
this._trigger('destroy');
},
_refreshFields: function () {
return this.actualizeOptions()._bindFields();
},
_bindFields: function () {
var oldFields = this.fields;
this.fields = [];
this.fieldsMappedById = {};
this._withoutReactualizingFormOptions(() => {
this.$element
.find(this.options.inputs)
.not(this.options.excluded)
.not(`[${this.options.namespace}excluded=true]`)
.each((_, element) => {
var fieldInstance = new window.Parsley.Factory(element, {}, this);
// Only add valid and not excluded `Field` and `FieldMultiple` children
if ('Field' === fieldInstance.__class__ || 'FieldMultiple' === fieldInstance.__class__) {
let uniqueId = fieldInstance.__class__ + '-' + fieldInstance.__id__;
if ('undefined' === typeof this.fieldsMappedById[uniqueId]) {
this.fieldsMappedById[uniqueId] = fieldInstance;
this.fields.push(fieldInstance);
}
}
});
$.each(Utils.difference(oldFields, this.fields), (_, field) => {
field.reset();
});
});
return this;
},
// Internal only.
// Looping on a form's fields to do validation or similar
// will trigger reactualizing options on all of them, which
// in turn will reactualize the form's options.
// To avoid calling actualizeOptions so many times on the form
// for nothing, _withoutReactualizingFormOptions temporarily disables
// the method actualizeOptions on this form while `fn` is called.
_withoutReactualizingFormOptions: function (fn) {
var oldActualizeOptions = this.actualizeOptions;
this.actualizeOptions = function () { return this; };
var result = fn();
this.actualizeOptions = oldActualizeOptions;
return result;
},
// Internal only.
// Shortcut to trigger an event
// Returns true iff event is not interrupted and default not prevented.
_trigger: function (eventName) {
return this.trigger('form:' + eventName);
}
};
export default Form;