commonMain.internal.actions.SetTouchedAction.kt Maven / Gradle / Ivy
package io.kform.internal.actions
import io.kform.*
import io.kform.internal.*
/** Action that sets all values whose path matches [path] as touched, as well as their parents. */
internal class SetTouchedAction(formManager: FormManager, private val path: AbsolutePath) :
ValueStateAction(formManager) {
override fun toString() = "SetTouched($path)"
override val accesses =
listOf(
AccessValueStateTree(ActionAccessType.Read),
AccessIsTouched(ActionAccessType.Write),
AccessValidationState(ActionAccessType.Read),
AccessDescendantsDisplayingIssues(ActionAccessType.Write)
)
override val accessedPaths = parentPaths(path) + path
override suspend fun run() = stateInfo(path).forEach { info -> setTouched(info) }
private tailrec suspend fun setTouched(info: StateInfo<*>) {
val (state, schema, path) = info
state as StateImpl?
if (state != null && !state.isTouched) {
state.isTouched = true
formManager.eventsBus.emit(StateEvent.TouchedChange(true, path, schema))
val newDisplayStatus = state.displayStatus()
if (newDisplayStatus != DisplayStatus.Valid) {
formManager.eventsBus.emit(StateEvent.DisplayChange(newDisplayStatus, path, schema))
}
if (info.path != AbsolutePath.ROOT) {
val parentPath = path.parent()
// Once the value has been touched, if it has issues, we need to increment the count
// of "descendants displaying issues" for all ancestors
val dominantSeverity = state.dominantIssueSeverity()
if (dominantSeverity != null) {
incrementDescendantsDisplayingIssues(parentPath, dominantSeverity)
}
setTouched(stateInfo(parentPath).single())
}
}
}
private tailrec suspend fun incrementDescendantsDisplayingIssues(
path: AbsolutePath,
dominantSeverity: ValidationIssueSeverity
) {
val info = stateInfo(path).single()
val state = info.state as ParentStateImpl
val oldDisplayStatus = state.displayStatus()
if (dominantSeverity == ValidationIssueSeverity.Error) {
++state.descendantsDisplayingErrors
} else {
++state.descendantsDisplayingWarnings
}
val newDisplayStatus = state.displayStatus()
if (oldDisplayStatus != newDisplayStatus) {
formManager.eventsBus.emit(
StateEvent.DisplayChange(newDisplayStatus, path, info.schema)
)
}
if (path != AbsolutePath.ROOT) {
incrementDescendantsDisplayingIssues(path.parent(), dominantSeverity)
}
}
}