|
|
|
@@ -24,19 +24,34 @@ Item {
|
|
|
|
|
|
|
|
|
|
property alias input: statusBaseInput
|
|
|
|
|
property alias valid: statusBaseInput.valid
|
|
|
|
|
property alias pending: statusBaseInput.pending
|
|
|
|
|
property alias text: statusBaseInput.text
|
|
|
|
|
property string label: ""
|
|
|
|
|
property string secondaryLabel: ""
|
|
|
|
|
property int charLimit: 0
|
|
|
|
|
property string errorMessage: ""
|
|
|
|
|
property real leftPadding: 16
|
|
|
|
|
property real rightPadding: 16
|
|
|
|
|
property list<StatusValidator> validators
|
|
|
|
|
property list<StatusValidator> asyncValidators
|
|
|
|
|
property int validationMode: StatusInput.ValidationMode.OnlyWhenDirty
|
|
|
|
|
|
|
|
|
|
property var pendingValidators: []
|
|
|
|
|
|
|
|
|
|
enum ValidationMode {
|
|
|
|
|
OnlyWhenDirty, // validates input only after it has become dirty
|
|
|
|
|
Always // validates input even before it has become dirty
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
property var errors: ({})
|
|
|
|
|
property var asyncErrors: ({})
|
|
|
|
|
|
|
|
|
|
function reset() {
|
|
|
|
|
statusBaseInput.valid = false
|
|
|
|
|
statusBaseInput.pristine = true
|
|
|
|
|
statusBaseInput.text = ""
|
|
|
|
|
errorMessage = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function validate() {
|
|
|
|
|
if (!statusBaseInput.dirty && validationMode === StatusInput.ValidationMode.OnlyWhenDirty) {
|
|
|
|
@@ -69,6 +84,40 @@ Item {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (asyncValidators.length && !Object.values(errors).length) {
|
|
|
|
|
root.pending = true
|
|
|
|
|
for (let idx in asyncValidators) {
|
|
|
|
|
let asyncValidator = asyncValidators[idx]
|
|
|
|
|
if (pendingValidators.indexOf(asyncValidator.name) == -1) {
|
|
|
|
|
asyncValidator.input = root
|
|
|
|
|
pendingValidators.push(asyncValidator.name)
|
|
|
|
|
asyncValidator.validate(statusBaseInput.text)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateValidity(validatorName, result) {
|
|
|
|
|
if (!asyncErrors) {
|
|
|
|
|
asyncErrors = {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (typeof result === "boolean" && result) {
|
|
|
|
|
if (asyncErrors[validatorName] !== undefined) {
|
|
|
|
|
delete asyncErrors[validatorName]
|
|
|
|
|
}
|
|
|
|
|
errorMessage.text = ""
|
|
|
|
|
} else {
|
|
|
|
|
asyncErrors[validatorName] = result
|
|
|
|
|
for (let idx in asyncValidators) {
|
|
|
|
|
errorMessage.text = asyncValidators[idx].errorMessage || root.errorMessage
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pendingValidators = pendingValidators.filter(v => v !== validatorName)
|
|
|
|
|
root.pending = pendingValidators.length > 0
|
|
|
|
|
root.valid = Object.values(asyncErrors).length == 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Component.onCompleted: validate()
|
|
|
|
@@ -78,9 +127,9 @@ Item {
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.topMargin: visible ? 8 : 0
|
|
|
|
|
anchors.leftMargin: 16
|
|
|
|
|
anchors.leftMargin: root.leftPadding
|
|
|
|
|
anchors.right: (charLimitLabel.visible ? charLimitLabel.right : parent.right)
|
|
|
|
|
anchors.rightMargin: 16
|
|
|
|
|
anchors.rightMargin: root.rightPadding
|
|
|
|
|
height: visible ? 17 : 0
|
|
|
|
|
visible: !!root.label
|
|
|
|
|
spacing: 5
|
|
|
|
@@ -109,7 +158,7 @@ Item {
|
|
|
|
|
anchors.top: parent.top
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
anchors.topMargin: visible ? 11 : 0
|
|
|
|
|
anchors.rightMargin: 16
|
|
|
|
|
anchors.rightMargin: root.rightPadding
|
|
|
|
|
visible: root.charLimit > 0
|
|
|
|
|
|
|
|
|
|
text: "%1 / %2".arg(statusBaseInput.text.length).arg(root.charLimit)
|
|
|
|
@@ -124,8 +173,8 @@ Item {
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
anchors.topMargin: charLimitLabel.visible ? 11 : 8
|
|
|
|
|
anchors.leftMargin: 16
|
|
|
|
|
anchors.rightMargin: 16
|
|
|
|
|
anchors.leftMargin: root.leftPadding
|
|
|
|
|
anchors.rightMargin: root.rightPadding
|
|
|
|
|
maximumLength: root.charLimit
|
|
|
|
|
onTextChanged: root.validate()
|
|
|
|
|
|
|
|
|
@@ -138,9 +187,9 @@ Item {
|
|
|
|
|
anchors.top: statusBaseInput.bottom
|
|
|
|
|
anchors.topMargin: 11
|
|
|
|
|
anchors.right: parent.right
|
|
|
|
|
anchors.rightMargin: 16
|
|
|
|
|
anchors.rightMargin: root.rightPadding
|
|
|
|
|
anchors.left: parent.left
|
|
|
|
|
anchors.leftMargin: 16
|
|
|
|
|
anchors.leftMargin: root.leftPadding
|
|
|
|
|
|
|
|
|
|
height: visible ? implicitHeight : 0
|
|
|
|
|
visible: !!text && !statusBaseInput.valid
|
|
|
|
|