189 lines
4.9 KiB
JavaScript
189 lines
4.9 KiB
JavaScript
import EventEmitter from 'eventemitter3'
|
|
|
|
const any = function(obj, pred) {
|
|
for (let name in obj) {
|
|
if (pred(obj[name])) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
export class Validator extends EventEmitter {
|
|
constructor(originalObj, validations, onModifiedChanged) {
|
|
super()
|
|
this.updateValue = this.updateValue.bind(this)
|
|
|
|
this._id = originalObj._id
|
|
this.onModifiedChanged = onModifiedChanged
|
|
this.fields = {}
|
|
this.nonValueFields = {}
|
|
|
|
for (let name in validations) {
|
|
let validation = validations[name]
|
|
let field = {
|
|
isDisabled: this.normalize(validation.isDisabled, false),
|
|
isReadOnly: this.normalize(validation.isReadOnly, false),
|
|
isVisible: this.normalize(validation.isVisible, true),
|
|
nonValue: validation.nonValue || false
|
|
}
|
|
|
|
if (field.nonValue) {
|
|
field.disabled = field.isDisabled(this)
|
|
field.readOnly = field.isReadOnly(this)
|
|
field.visible = field.isVisible(this)
|
|
this.nonValueFields[name] = field
|
|
} else {
|
|
field.alwaysGet = validation.alwaysGet
|
|
field.isValid = this.normalize(validation.isValid, true)
|
|
field.initValue = (validation.initValue === undefined ? '' : validation.initValue)
|
|
field.originalValue = Validator.getObjectValue(originalObj, name)
|
|
this.updateFieldValue(field, field.originalValue || field.initValue)
|
|
this.fields[name] = field
|
|
}
|
|
}
|
|
|
|
this.updateNonValueFields()
|
|
}
|
|
|
|
normalize(obj, def) {
|
|
return obj ? ((obj.constructor === Function) ? obj : () => (!!obj)) : () => (def)
|
|
}
|
|
|
|
static stateSafeField(field) {
|
|
return {
|
|
value: field.value,
|
|
modified: field.modified,
|
|
valid: field.valid,
|
|
disabled: field.disabled,
|
|
readOnly: field.readOnly,
|
|
visible: field.visible
|
|
}
|
|
}
|
|
|
|
updateValue(name, newValue) {
|
|
let lastAnyModified = this.anyModified
|
|
let field = this.fields[name]
|
|
|
|
if (field) {
|
|
this.updateFieldValue(field, newValue)
|
|
this.updateNonValueFields()
|
|
if (lastAnyModified !== this.anyModified && this.onModifiedChanged) {
|
|
this.onModifiedChanged(this.anyModified)
|
|
}
|
|
}
|
|
|
|
return Validator.stateSafeField(field)
|
|
}
|
|
|
|
updateFieldValue(field, newValue) {
|
|
field.value = newValue
|
|
field.disabled = field.isDisabled(this)
|
|
field.readOnly = field.isReadOnly(this)
|
|
field.visible = field.isVisible(this)
|
|
field.valid = field.isValid(this, newValue)
|
|
field.modified =
|
|
field.originalValue !== undefined ? (field.originalValue !== newValue) : (newValue !== field.initValue)
|
|
|
|
this.anyModified = field.modified || any(this.fields, (field) => (field.modified))
|
|
this.allValid = !field.valid ? false : !any(this.fields, (field) => (!field.valid))
|
|
}
|
|
|
|
updateNonValueFields() {
|
|
for (let name in this.nonValueFields) {
|
|
let field = this.nonValueFields[name]
|
|
let disabled = field.isDisabled(this)
|
|
let readOnly = field.isReadOnly(this)
|
|
let visible = field.isVisible(this)
|
|
let b = (disabled !== field.disabled || readOnly !== field.readOnly || visible !== field.visible)
|
|
|
|
field.disabled = disabled
|
|
field.readOnly = readOnly
|
|
field.visible = visible
|
|
|
|
if (b) {
|
|
this.emit(name, name)
|
|
}
|
|
}
|
|
}
|
|
|
|
getField(name) {
|
|
let field = this.fields[name] || this.nonValueFields[name]
|
|
|
|
if (!field) {
|
|
throw new Error(`Field '${name}' does not have a validation entry`)
|
|
}
|
|
|
|
return Validator.stateSafeField(field)
|
|
}
|
|
|
|
getValues() {
|
|
// Generate an object that has the modified and alwaysGet fields
|
|
let obj = {}
|
|
|
|
if (!this.anyModified && !this.allValid) {
|
|
return obj
|
|
}
|
|
|
|
// Will have an _id if updating
|
|
if (this._id) {
|
|
obj._id = this._id
|
|
}
|
|
|
|
for (let name in this.fields) {
|
|
let field = this.fields[name]
|
|
|
|
if (field.alwaysGet || (!field.nonValue && field.modified)) {
|
|
let value = field.value
|
|
if (value && value.constructor === 'String') {
|
|
value = value.trim()
|
|
}
|
|
Validator.setObjectValue(obj, name, value)
|
|
}
|
|
}
|
|
|
|
return obj
|
|
}
|
|
|
|
getOriginalValues() {
|
|
// Generate an object that has the original values of all fields
|
|
let obj = {}
|
|
|
|
if (this._id) {
|
|
obj._id = this._id
|
|
}
|
|
|
|
for (let name in this.fields) {
|
|
let field = this.fields[name]
|
|
|
|
if (field.originalValue !== undefined) {
|
|
Validator.setObjectValue(obj, name, field.originalValue)
|
|
}
|
|
}
|
|
|
|
return obj
|
|
}
|
|
|
|
static getObjectValue(obj, name) {
|
|
name.split('.').forEach((namePart) => {
|
|
if (obj) {
|
|
obj = obj[namePart]
|
|
}
|
|
})
|
|
return obj
|
|
}
|
|
|
|
static setObjectValue(obj, name, value) {
|
|
name.split('.').forEach((namePart, i, nameParts) => {
|
|
if (i < nameParts.length - 1) {
|
|
if (!obj[namePart]) {
|
|
obj[namePart] = {}
|
|
}
|
|
obj = obj[namePart]
|
|
} else {
|
|
obj[namePart] = value
|
|
}
|
|
})
|
|
}
|
|
}
|