mirror of
https://github.com/acaloiaro/frm
synced 2026-07-21 10:12:23 +00:00
feat: add 'not' logic
This commit is contained in:
parent
aff261b4e5
commit
ff10a77d72
9 changed files with 45 additions and 24 deletions
|
|
@ -111,7 +111,7 @@ func Collect(w http.ResponseWriter, r *http.Request) {
|
|||
submission := r.Form
|
||||
errs := validate(f, submission)
|
||||
if errs.Any() {
|
||||
slog.Info("[collector] failed validation", "errors", errs)
|
||||
slog.Debug("[collector] failed validation", "errors", errs)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
err = ui.ValidationErrors(errs).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
|
|
@ -141,7 +141,7 @@ func Collect(w http.ResponseWriter, r *http.Request) {
|
|||
// TODO: Keep track of the submission id
|
||||
// submissionID := r.Form.Get("id")
|
||||
|
||||
// Validation renders whether there are errors or not errors, so that non-erroneous fields can be cleared of error messages
|
||||
// Validation renders whether there are errors or not, so that non-erroneous fields can be cleared of error messages
|
||||
// as the user corrects validation errors
|
||||
allFields := slices.Collect(maps.Keys(f.Fields))
|
||||
err = ui.Validation(allFields, errs).Render(ctx, w)
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@ func UpdateFields(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
oldField.Logic.TargetFieldID = targetFieldID
|
||||
updatedFields[fieldID] = oldField
|
||||
// field logic, subject field chosen
|
||||
case fieldGroup == builder.FieldGroupLogic && fieldName == builder.FieldLogicTargetFieldValue:
|
||||
oldField := draft.Fields[fieldID]
|
||||
if oldField.Logic == nil {
|
||||
|
|
@ -466,6 +467,7 @@ func UpdateFields(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
oldField.Logic.TriggerValues = fieldValues
|
||||
updatedFields[fieldID] = oldField
|
||||
// field logic, comparator chosen
|
||||
case fieldGroup == builder.FieldGroupLogic && fieldName == builder.FieldLogicComparator:
|
||||
oldField := draft.Fields[fieldID]
|
||||
if oldField.Logic == nil {
|
||||
|
|
@ -473,6 +475,7 @@ func UpdateFields(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
oldField.Logic.TriggerComparator, _ = types.FieldLogicComparatorString(fieldValues[0])
|
||||
updatedFields[fieldID] = oldField
|
||||
// field logic, action to take
|
||||
case fieldGroup == builder.FieldGroupLogic && fieldName == types.FieldLogicTriggerShow.String():
|
||||
oldField := draft.Fields[fieldID]
|
||||
if oldField.Logic == nil {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
const _FieldLogicComparatorName = "equalcontains"
|
||||
const _FieldLogicComparatorName = "equalcontainsnot"
|
||||
|
||||
var _FieldLogicComparatorIndex = [...]uint8{0, 5, 13}
|
||||
var _FieldLogicComparatorIndex = [...]uint8{0, 5, 13, 16}
|
||||
|
||||
const _FieldLogicComparatorLowerName = "equalcontains"
|
||||
const _FieldLogicComparatorLowerName = "equalcontainsnot"
|
||||
|
||||
func (i FieldLogicComparator) String() string {
|
||||
if i < 0 || i >= FieldLogicComparator(len(_FieldLogicComparatorIndex)-1) {
|
||||
|
|
@ -27,20 +27,24 @@ func _FieldLogicComparatorNoOp() {
|
|||
var x [1]struct{}
|
||||
_ = x[FieldLogicComparatorEqual-(0)]
|
||||
_ = x[FieldLogicComparatorContains-(1)]
|
||||
_ = x[FieldLogicComparatorNot-(2)]
|
||||
}
|
||||
|
||||
var _FieldLogicComparatorValues = []FieldLogicComparator{FieldLogicComparatorEqual, FieldLogicComparatorContains}
|
||||
var _FieldLogicComparatorValues = []FieldLogicComparator{FieldLogicComparatorEqual, FieldLogicComparatorContains, FieldLogicComparatorNot}
|
||||
|
||||
var _FieldLogicComparatorNameToValueMap = map[string]FieldLogicComparator{
|
||||
_FieldLogicComparatorName[0:5]: FieldLogicComparatorEqual,
|
||||
_FieldLogicComparatorLowerName[0:5]: FieldLogicComparatorEqual,
|
||||
_FieldLogicComparatorName[5:13]: FieldLogicComparatorContains,
|
||||
_FieldLogicComparatorLowerName[5:13]: FieldLogicComparatorContains,
|
||||
_FieldLogicComparatorName[0:5]: FieldLogicComparatorEqual,
|
||||
_FieldLogicComparatorLowerName[0:5]: FieldLogicComparatorEqual,
|
||||
_FieldLogicComparatorName[5:13]: FieldLogicComparatorContains,
|
||||
_FieldLogicComparatorLowerName[5:13]: FieldLogicComparatorContains,
|
||||
_FieldLogicComparatorName[13:16]: FieldLogicComparatorNot,
|
||||
_FieldLogicComparatorLowerName[13:16]: FieldLogicComparatorNot,
|
||||
}
|
||||
|
||||
var _FieldLogicComparatorNames = []string{
|
||||
_FieldLogicComparatorName[0:5],
|
||||
_FieldLogicComparatorName[5:13],
|
||||
_FieldLogicComparatorName[13:16],
|
||||
}
|
||||
|
||||
// FieldLogicComparatorString retrieves an enum value from the enum constants string name.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ type FieldLogicComparator int
|
|||
const (
|
||||
FieldLogicComparatorEqual FieldLogicComparator = iota // target field value is equal to the subject value
|
||||
FieldLogicComparatorContains // target field value contains the subject value
|
||||
FieldLogicComparatorNot // target field value is "not" the subject value
|
||||
)
|
||||
|
||||
// FieldLogicTriggerAction enum enumerates all possible field logic trigger actions
|
||||
|
|
|
|||
|
|
@ -463,15 +463,20 @@ func comparatorOptionsFor(field types.FormField) (options selector.FieldOptions)
|
|||
switch field.Type {
|
||||
default:
|
||||
options = selector.FieldOptions{
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorContains),
|
||||
Label: "Contains",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorContains,
|
||||
},
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorEqual),
|
||||
Label: "Equal to =",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorEqual,
|
||||
},
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorContains),
|
||||
Label: "Contains",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorContains,
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorNot),
|
||||
Label: "NOT",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorNot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1478,15 +1478,20 @@ func comparatorOptionsFor(field types.FormField) (options selector.FieldOptions)
|
|||
switch field.Type {
|
||||
default:
|
||||
options = selector.FieldOptions{
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorContains),
|
||||
Label: "Contains",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorContains,
|
||||
},
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorEqual),
|
||||
Label: "Equal to =",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorEqual,
|
||||
},
|
||||
selector.Option{
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorContains),
|
||||
Label: "Contains",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorContains,
|
||||
Value: fmt.Sprint(types.FieldLogicComparatorNot),
|
||||
Label: "NOT",
|
||||
Selected: field.Logic != nil && field.Logic.TriggerComparator == types.FieldLogicComparatorNot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -1540,7 +1545,7 @@ func LogicConfiguratorStepThree(form frm.Form, field types.FormField, targetFiel
|
|||
var templ_7745c5c3_Var68 string
|
||||
templ_7745c5c3_Var68, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s-logic-chosen-field-value", field.ID.String()))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 499, Col: 70}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 504, Col: 70}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var68))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -1553,7 +1558,7 @@ func LogicConfiguratorStepThree(form frm.Form, field types.FormField, targetFiel
|
|||
var templ_7745c5c3_Var69 string
|
||||
templ_7745c5c3_Var69, templ_7745c5c3_Err = templ.JoinStringErrs(fields.FieldName(field, FieldGroupLogic, FieldLogicTargetFieldValue))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 500, Col: 79}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 505, Col: 79}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var69))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -1571,7 +1576,7 @@ func LogicConfiguratorStepThree(form frm.Form, field types.FormField, targetFiel
|
|||
var templ_7745c5c3_Var70 string
|
||||
templ_7745c5c3_Var70, templ_7745c5c3_Err = templ.JoinStringErrs(field.Logic.TriggerValues[0])
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 505, Col: 41}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 510, Col: 41}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var70))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -1589,7 +1594,7 @@ func LogicConfiguratorStepThree(form frm.Form, field types.FormField, targetFiel
|
|||
var templ_7745c5c3_Var71 string
|
||||
templ_7745c5c3_Var71, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("on keyup debounced at 600ms trigger '%s'", FieldsFormUpdateEvent))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 507, Col: 86}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/builder/common.templ`, Line: 512, Col: 86}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var71))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ templ Head(pageTitle string) {
|
|||
case 'contains':
|
||||
match = watchingField.logic.trigger_values.some(val => newValue.toLowerCase().includes(val.toLowerCase()))
|
||||
break;
|
||||
case 'not':
|
||||
match = watchingField.logic.trigger_values.some(val => newValue.toLowerCase() !== val.toLowerCase())
|
||||
break;
|
||||
}
|
||||
|
||||
// Most actions are likely to be performed upon the containing element, such as show/hide/require.
|
||||
|
|
|
|||
|
|
@ -464,7 +464,7 @@ func Head(pageTitle string) templ.Component {
|
|||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\"></script> <script type=\"text/javascript\">\n\t\t\t\thtmx.onLoad(function(content) {\n\t\t\t\t var sortables = content.querySelectorAll(\".sortable\");\n\t\t\t\t for (var i = 0; i < sortables.length; i++) {\n\t\t\t\t var sortable = sortables[i];\n\t\t\t\t var sortableInstance = new Sortable(sortable, {\n\t\t\t\t animation: 150,\n\t\t\t\t\t\t draggable: \".sortme\",\n\t\t\t\t onMove: function (evt) {\n\t\t\t\t return evt.related.className.indexOf('htmx-indicator') === -1;\n\t\t\t\t },\n\t\t\t\t onEnd: function (evt) {\n\t\t\t\t this.option(\"disabled\", true);\n\t\t\t\t }\n\t\t\t\t });\n\t\t\t\t // Re-enable sorting on the `htmx:afterSwap` event\n\t\t\t\t sortable.addEventListener(\"htmx:afterSwap\", function() {\n\t\t\t\t sortableInstance.option(\"disabled\", false);\n\t\t\t\t });\n\t\t\t\t }\n\t\t\t\t})\n\n\t\t\t\tfunction formValueChanged(fieldID, newValue) {\n\t\t\t\t\tvar formMetadata = JSON.parse(document.getElementById('form-metadata').getAttribute(\"data-data\"));\n\t\t\t\t\tif (formMetadata == null) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// collect the fields that have logic monitoring the changed field \n\t\t\t\t\tvar watchingFields = Object.values(formMetadata.form.fields).filter(function(field) {\n\t\t\t\t\t\treturn field.logic != null && fieldID === field.logic.target_field_id\n\t\t\t\t\t});\n\n\t\t\t\t\t// no fields watch the one that changed\n\t\t\t\t\tif (watchingFields.length == 0) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tvar fieldElement = document.getElementById(fieldID)\n\t\t\t\t\tfor (i in watchingFields) {\n\t\t\t\t\t\tlet watchingField = watchingFields[i]\n\t\t\t\t\t\tlet match = false\n\t\t\t\t\t\tvar watcherFieldContainerID = `field-container-${watchingField.id}` // the DOM element that contains the watching field\n\t\t\t\t\t\tlogic = watchingField.logic\n\n\t\t\t\t\t\t// check whether the new value is coming from a Choices.js field, in which case the new value\n\t\t\t\t\t\t// is the array of chosen values, joined by commas, otherwise newValue is used as it was passed in\n\t\t\t\t\t\tif (fieldElement != null && fieldElement._choices != null) {\n\t\t\t\t\t\t\t// Choics.getValue() returns scalar for single selects and array for multi. Use Array.of\n\t\t\t\t\t\t\t// to treat everything it returns as an array\n\t\t\t\t\t\t\tnewValue = Array.of(fieldElement._choices.getValue(true)).join(',')\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find if _any_ trigger values match the new value\n\t\t\t\t\t\tswitch (logic.field_comparator) {\n\t\t\t\t\t\t\tcase 'equal':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.every(val => newValue.localeCompare(val, 'en', {sensitivity: \"base\"}) == 0)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'contains':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase().includes(val.toLowerCase()))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Most actions are likely to be performed upon the containing element, such as show/hide/require.\n\t\t\t\t\t\t// This may of course change or be expanded, but for now, only the watcher field container is relevant\n\t\t\t\t\t\t// to applying actions.\n\t\t\t\t\t\tlet el = document.getElementById(watcherFieldContainerID)\n\t\t\t\t\t\tlet actions = watchingField.logic.actions\n\n\t\t\t\t\t\t// we have a match, execute the action\n\t\t\t\t\t\tfor (i in actions) {\n\t\t\t\t\t\t\tswitch (actions[i]) {\n\t\t\t\t\t\t\t\tcase \"field_logic_trigger_show\":\n\t\t\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\t\t\tel.classList.remove(\"hidden\");\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tel.classList.add(\"hidden\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</script>")
|
||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "\"></script> <script type=\"text/javascript\">\n\t\t\t\thtmx.onLoad(function(content) {\n\t\t\t\t var sortables = content.querySelectorAll(\".sortable\");\n\t\t\t\t for (var i = 0; i < sortables.length; i++) {\n\t\t\t\t var sortable = sortables[i];\n\t\t\t\t var sortableInstance = new Sortable(sortable, {\n\t\t\t\t animation: 150,\n\t\t\t\t\t\t draggable: \".sortme\",\n\t\t\t\t onMove: function (evt) {\n\t\t\t\t return evt.related.className.indexOf('htmx-indicator') === -1;\n\t\t\t\t },\n\t\t\t\t onEnd: function (evt) {\n\t\t\t\t this.option(\"disabled\", true);\n\t\t\t\t }\n\t\t\t\t });\n\t\t\t\t // Re-enable sorting on the `htmx:afterSwap` event\n\t\t\t\t sortable.addEventListener(\"htmx:afterSwap\", function() {\n\t\t\t\t sortableInstance.option(\"disabled\", false);\n\t\t\t\t });\n\t\t\t\t }\n\t\t\t\t})\n\n\t\t\t\tfunction formValueChanged(fieldID, newValue) {\n\t\t\t\t\tvar formMetadata = JSON.parse(document.getElementById('form-metadata').getAttribute(\"data-data\"));\n\t\t\t\t\tif (formMetadata == null) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// collect the fields that have logic monitoring the changed field \n\t\t\t\t\tvar watchingFields = Object.values(formMetadata.form.fields).filter(function(field) {\n\t\t\t\t\t\treturn field.logic != null && fieldID === field.logic.target_field_id\n\t\t\t\t\t});\n\n\t\t\t\t\t// no fields watch the one that changed\n\t\t\t\t\tif (watchingFields.length == 0) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tvar fieldElement = document.getElementById(fieldID)\n\t\t\t\t\tfor (i in watchingFields) {\n\t\t\t\t\t\tlet watchingField = watchingFields[i]\n\t\t\t\t\t\tlet match = false\n\t\t\t\t\t\tvar watcherFieldContainerID = `field-container-${watchingField.id}` // the DOM element that contains the watching field\n\t\t\t\t\t\tlogic = watchingField.logic\n\n\t\t\t\t\t\t// check whether the new value is coming from a Choices.js field, in which case the new value\n\t\t\t\t\t\t// is the array of chosen values, joined by commas, otherwise newValue is used as it was passed in\n\t\t\t\t\t\tif (fieldElement != null && fieldElement._choices != null) {\n\t\t\t\t\t\t\t// Choics.getValue() returns scalar for single selects and array for multi. Use Array.of\n\t\t\t\t\t\t\t// to treat everything it returns as an array\n\t\t\t\t\t\t\tnewValue = Array.of(fieldElement._choices.getValue(true)).join(',')\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find if _any_ trigger values match the new value\n\t\t\t\t\t\tswitch (logic.field_comparator) {\n\t\t\t\t\t\t\tcase 'equal':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.every(val => newValue.localeCompare(val, 'en', {sensitivity: \"base\"}) == 0)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'contains':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase().includes(val.toLowerCase()))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'not':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase() !== val.toLowerCase())\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Most actions are likely to be performed upon the containing element, such as show/hide/require.\n\t\t\t\t\t\t// This may of course change or be expanded, but for now, only the watcher field container is relevant\n\t\t\t\t\t\t// to applying actions.\n\t\t\t\t\t\tlet el = document.getElementById(watcherFieldContainerID)\n\t\t\t\t\t\tlet actions = watchingField.logic.actions\n\n\t\t\t\t\t\t// we have a match, execute the action\n\t\t\t\t\t\tfor (i in actions) {\n\t\t\t\t\t\t\tswitch (actions[i]) {\n\t\t\t\t\t\t\t\tcase \"field_logic_trigger_show\":\n\t\t\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\t\t\tel.classList.remove(\"hidden\");\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tel.classList.add(\"hidden\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</script>")
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ_7745c5c3_Err
|
||||
}
|
||||
|
|
@ -619,7 +619,7 @@ func ValidationErrors(errs types.ValidationErrors) templ.Component {
|
|||
var templ_7745c5c3_Var32 string
|
||||
templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("errors-%s", fieldID))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 196, Col: 46}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 199, Col: 46}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
@ -632,7 +632,7 @@ func ValidationErrors(errs types.ValidationErrors) templ.Component {
|
|||
var templ_7745c5c3_Var33 string
|
||||
templ_7745c5c3_Var33, templ_7745c5c3_Err = templ.JoinStringErrs(err.Error())
|
||||
if templ_7745c5c3_Err != nil {
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 198, Col: 18}
|
||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `ui/common.templ`, Line: 201, Col: 18}
|
||||
}
|
||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var33))
|
||||
if templ_7745c5c3_Err != nil {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
\" nonce=\"
|
||||
\" async></script> <script type=\"text/javascript\" src=\"
|
||||
\" nonce=\"
|
||||
\"></script> <script type=\"text/javascript\">\n\t\t\t\thtmx.onLoad(function(content) {\n\t\t\t\t var sortables = content.querySelectorAll(\".sortable\");\n\t\t\t\t for (var i = 0; i < sortables.length; i++) {\n\t\t\t\t var sortable = sortables[i];\n\t\t\t\t var sortableInstance = new Sortable(sortable, {\n\t\t\t\t animation: 150,\n\t\t\t\t\t\t draggable: \".sortme\",\n\t\t\t\t onMove: function (evt) {\n\t\t\t\t return evt.related.className.indexOf('htmx-indicator') === -1;\n\t\t\t\t },\n\t\t\t\t onEnd: function (evt) {\n\t\t\t\t this.option(\"disabled\", true);\n\t\t\t\t }\n\t\t\t\t });\n\t\t\t\t // Re-enable sorting on the `htmx:afterSwap` event\n\t\t\t\t sortable.addEventListener(\"htmx:afterSwap\", function() {\n\t\t\t\t sortableInstance.option(\"disabled\", false);\n\t\t\t\t });\n\t\t\t\t }\n\t\t\t\t})\n\n\t\t\t\tfunction formValueChanged(fieldID, newValue) {\n\t\t\t\t\tvar formMetadata = JSON.parse(document.getElementById('form-metadata').getAttribute(\"data-data\"));\n\t\t\t\t\tif (formMetadata == null) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// collect the fields that have logic monitoring the changed field \n\t\t\t\t\tvar watchingFields = Object.values(formMetadata.form.fields).filter(function(field) {\n\t\t\t\t\t\treturn field.logic != null && fieldID === field.logic.target_field_id\n\t\t\t\t\t});\n\n\t\t\t\t\t// no fields watch the one that changed\n\t\t\t\t\tif (watchingFields.length == 0) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tvar fieldElement = document.getElementById(fieldID)\n\t\t\t\t\tfor (i in watchingFields) {\n\t\t\t\t\t\tlet watchingField = watchingFields[i]\n\t\t\t\t\t\tlet match = false\n\t\t\t\t\t\tvar watcherFieldContainerID = `field-container-${watchingField.id}` // the DOM element that contains the watching field\n\t\t\t\t\t\tlogic = watchingField.logic\n\n\t\t\t\t\t\t// check whether the new value is coming from a Choices.js field, in which case the new value\n\t\t\t\t\t\t// is the array of chosen values, joined by commas, otherwise newValue is used as it was passed in\n\t\t\t\t\t\tif (fieldElement != null && fieldElement._choices != null) {\n\t\t\t\t\t\t\t// Choics.getValue() returns scalar for single selects and array for multi. Use Array.of\n\t\t\t\t\t\t\t// to treat everything it returns as an array\n\t\t\t\t\t\t\tnewValue = Array.of(fieldElement._choices.getValue(true)).join(',')\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find if _any_ trigger values match the new value\n\t\t\t\t\t\tswitch (logic.field_comparator) {\n\t\t\t\t\t\t\tcase 'equal':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.every(val => newValue.localeCompare(val, 'en', {sensitivity: \"base\"}) == 0)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'contains':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase().includes(val.toLowerCase()))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Most actions are likely to be performed upon the containing element, such as show/hide/require.\n\t\t\t\t\t\t// This may of course change or be expanded, but for now, only the watcher field container is relevant\n\t\t\t\t\t\t// to applying actions.\n\t\t\t\t\t\tlet el = document.getElementById(watcherFieldContainerID)\n\t\t\t\t\t\tlet actions = watchingField.logic.actions\n\n\t\t\t\t\t\t// we have a match, execute the action\n\t\t\t\t\t\tfor (i in actions) {\n\t\t\t\t\t\t\tswitch (actions[i]) {\n\t\t\t\t\t\t\t\tcase \"field_logic_trigger_show\":\n\t\t\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\t\t\tel.classList.remove(\"hidden\");\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tel.classList.add(\"hidden\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</script>
|
||||
\"></script> <script type=\"text/javascript\">\n\t\t\t\thtmx.onLoad(function(content) {\n\t\t\t\t var sortables = content.querySelectorAll(\".sortable\");\n\t\t\t\t for (var i = 0; i < sortables.length; i++) {\n\t\t\t\t var sortable = sortables[i];\n\t\t\t\t var sortableInstance = new Sortable(sortable, {\n\t\t\t\t animation: 150,\n\t\t\t\t\t\t draggable: \".sortme\",\n\t\t\t\t onMove: function (evt) {\n\t\t\t\t return evt.related.className.indexOf('htmx-indicator') === -1;\n\t\t\t\t },\n\t\t\t\t onEnd: function (evt) {\n\t\t\t\t this.option(\"disabled\", true);\n\t\t\t\t }\n\t\t\t\t });\n\t\t\t\t // Re-enable sorting on the `htmx:afterSwap` event\n\t\t\t\t sortable.addEventListener(\"htmx:afterSwap\", function() {\n\t\t\t\t sortableInstance.option(\"disabled\", false);\n\t\t\t\t });\n\t\t\t\t }\n\t\t\t\t})\n\n\t\t\t\tfunction formValueChanged(fieldID, newValue) {\n\t\t\t\t\tvar formMetadata = JSON.parse(document.getElementById('form-metadata').getAttribute(\"data-data\"));\n\t\t\t\t\tif (formMetadata == null) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\n\t\t\t\t\t// collect the fields that have logic monitoring the changed field \n\t\t\t\t\tvar watchingFields = Object.values(formMetadata.form.fields).filter(function(field) {\n\t\t\t\t\t\treturn field.logic != null && fieldID === field.logic.target_field_id\n\t\t\t\t\t});\n\n\t\t\t\t\t// no fields watch the one that changed\n\t\t\t\t\tif (watchingFields.length == 0) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tvar fieldElement = document.getElementById(fieldID)\n\t\t\t\t\tfor (i in watchingFields) {\n\t\t\t\t\t\tlet watchingField = watchingFields[i]\n\t\t\t\t\t\tlet match = false\n\t\t\t\t\t\tvar watcherFieldContainerID = `field-container-${watchingField.id}` // the DOM element that contains the watching field\n\t\t\t\t\t\tlogic = watchingField.logic\n\n\t\t\t\t\t\t// check whether the new value is coming from a Choices.js field, in which case the new value\n\t\t\t\t\t\t// is the array of chosen values, joined by commas, otherwise newValue is used as it was passed in\n\t\t\t\t\t\tif (fieldElement != null && fieldElement._choices != null) {\n\t\t\t\t\t\t\t// Choics.getValue() returns scalar for single selects and array for multi. Use Array.of\n\t\t\t\t\t\t\t// to treat everything it returns as an array\n\t\t\t\t\t\t\tnewValue = Array.of(fieldElement._choices.getValue(true)).join(',')\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// find if _any_ trigger values match the new value\n\t\t\t\t\t\tswitch (logic.field_comparator) {\n\t\t\t\t\t\t\tcase 'equal':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.every(val => newValue.localeCompare(val, 'en', {sensitivity: \"base\"}) == 0)\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'contains':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase().includes(val.toLowerCase()))\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'not':\n\t\t\t\t\t\t\t\tmatch = watchingField.logic.trigger_values.some(val => newValue.toLowerCase() !== val.toLowerCase())\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Most actions are likely to be performed upon the containing element, such as show/hide/require.\n\t\t\t\t\t\t// This may of course change or be expanded, but for now, only the watcher field container is relevant\n\t\t\t\t\t\t// to applying actions.\n\t\t\t\t\t\tlet el = document.getElementById(watcherFieldContainerID)\n\t\t\t\t\t\tlet actions = watchingField.logic.actions\n\n\t\t\t\t\t\t// we have a match, execute the action\n\t\t\t\t\t\tfor (i in actions) {\n\t\t\t\t\t\t\tswitch (actions[i]) {\n\t\t\t\t\t\t\t\tcase \"field_logic_trigger_show\":\n\t\t\t\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\t\t\t\tel.classList.remove(\"hidden\");\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tel.classList.add(\"hidden\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</script>
|
||||
</head>
|
||||
<!doctype html><html lang=\"eng\">
|
||||
<body><main>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.8 KiB |
Loading…
Reference in a new issue