Custom Forms: Allow HTML in labels and help text (#5136)

* Custom Forms: Allow HTML in labels and help text

Fixes #5003.

* Vue: Sanitize labels and helper text input

* Form editor: Fix blur on input for select option values

---------

Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
This commit is contained in:
d11n 2023-07-11 06:02:02 +02:00 committed by GitHub
parent 9f5466a41f
commit c777746b69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 14 deletions

View file

@ -390,6 +390,11 @@ retry:
version = Regex.Match(actual, "BootstrapVue ([0-9]+.[0-9]+.[0-9]+)").Groups[1].Value;
expected = (await (await client.GetAsync($"https://cdnjs.cloudflare.com/ajax/libs/bootstrap-vue/{version}/bootstrap-vue.min.js")).Content.ReadAsStringAsync()).Trim();
EqualJsContent(expected, actual);
actual = GetFileContent("BTCPayServer", "wwwroot", "vendor", "vue-sanitize-directive", "vue-sanitize-directive.umd.min.js").Trim();
version = Regex.Match(actual, "Original file: /npm/vue-sanitize-directive@([0-9]+.[0-9]+.[0-9]+)").Groups[1].Value;
expected = (await (await client.GetAsync($"https://cdn.jsdelivr.net/npm/vue-sanitize-directive@{version}/dist/vue-sanitize-directive.umd.min.js")).Content.ReadAsStringAsync()).Trim();
EqualJsContent(expected, actual);
}
private void EqualJsContent(string expected, string actual)

View file

@ -5,7 +5,7 @@
@if (!Model.Constant)
{
<fieldset>
<legend class="h3 mt-4 mb-3">@Model.Label</legend>
<legend class="h3 mt-4 mb-3">@Safe.Raw(Model.Label)</legend>
@foreach (var field in Model.Fields)
{
if (FormComponentProviders.TypeToComponentProvider.TryGetValue(field.Type, out var partial) && !string.IsNullOrEmpty(partial.View))

View file

@ -5,7 +5,7 @@
}
<div class="form-group">
<label class="form-label" for="@Model.Name"@(Model.Required ? " data-required" : "")>
@Model.Label
@Safe.Raw(Model.Label)
</label>
<input id="@Model.Name" type="@Model.Type" class="form-control @(errors is null ? "" : "is-invalid")"
name="@Model.Name" value="@Model.Value" data-val="true"

View file

@ -12,17 +12,15 @@
}
<div class="form-group">
<label class="form-label" for="@Model.Name"@(Model.Required ? " data-required" : "")>
@Model.Label
@Safe.Raw(Model.Label)
</label>
<select id="@selectField.Name" asp-items="selectField.Options" class="form-select @(errors is null ? "" : "is-invalid")"
name="@selectField.Name" data-val="true" aria-describedby="HelpText-@selectField.Name" required="@selectField.Required"
data-val-required="@selectField.Label is required.">
</select>
<span class="text-danger" data-valmsg-for="@selectField.Name" data-valmsg-replace="true">@(isInvalid && errors.Any() ? errors.First().ErrorMessage : string.Empty)</span>
@if (!string.IsNullOrEmpty(selectField.HelpText))
{
<div id="@($"HelpText-{selectField.Name}")" class="form-text">@selectField.HelpText</div>
<div id="@($"HelpText-{selectField.Name}")" class="form-text">@Safe.Raw(selectField.HelpText)</div>
}
</div>

View file

@ -5,7 +5,7 @@
}
<div class="form-group">
<label class="form-label" for="@Model.Name"@(Model.Required ? " data-required" : "")>
@Model.Label
@Safe.Raw(Model.Label)
</label>
<textarea id="@Model.Name" class="form-control @(errors is null ? "" : "is-invalid")"
name="@Model.Name" data-val="true"

View file

@ -62,7 +62,7 @@
</button>
<div class="field flex-grow-1">
<label :for="`field-option-value-${index}`" class="form-label">Value</label>
<input :for="`field-option-value-${index}`" class="form-control" v-model="option.value" />
<input :for="`field-option-value-${index}`" class="form-control" v-model.lazy="option.value" />
</div>
<div class="field flex-grow-1">
<label :for="`field-option-text-${index}`" class="form-label">Text</label>
@ -122,25 +122,25 @@
</template>
<template id="field-type-input">
<div class="form-group mb-0">
<label class="form-label" :for="name" :data-required="required" v-text="label"></label>
<label class="form-label" :for="name" :data-required="required" v-sanitize="label"></label>
<input class="form-control" :id="name" :name="name" :type="type" v-model="value" />
<div v-if="helpText" :id="`HelpText-{name}`" class="form-text" v-text="helpText"></div>
<div v-if="helpText" :id="`HelpText-{name}`" class="form-text" v-sanitize="helpText"></div>
</div>
</template>
<template id="field-type-textarea">
<div class="form-group mb-0">
<label class="form-label" :for="name" :data-required="required" v-text="label"></label>
<label class="form-label" :for="name" :data-required="required" v-sanitize="label"></label>
<textarea class="form-control" :id="name" :name="name" v-model="value"></textarea>
<div v-if="helpText" :id="`HelpText-${name}`" class="form-text" v-text="helpText"></div>
<div v-if="helpText" :id="`HelpText-${name}`" class="form-text" v-sanitize="helpText"></div>
</div>
</template>
<template id="field-type-select">
<div class="form-group mb-0">
<label class="form-label" :for="name" :data-required="required" v-text="label"></label>
<label class="form-label" :for="name" :data-required="required" v-sanitize="label"></label>
<select class="form-select" :id="name" :name="name">
<option v-for="option in options" :key="option.value" :value="option.value" :selected="option.value === value" v-text="option.text"></option>
</select>
<div v-if="helpText" :id="`HelpText-${name}`" class="form-text" v-text="helpText"></div>
<div v-if="helpText" :id="`HelpText-${name}`" class="form-text" v-sanitize="helpText"></div>
</div>
</template>
<template id="field-type-fieldset">
@ -150,6 +150,7 @@
</fieldset>
</template>
<script src="~/vendor/vuejs/vue.min.js" asp-append-version="true"></script>
<script src="~/vendor/vue-sanitize-directive/vue-sanitize-directive.umd.min.js" asp-append-version="true"></script>
<script src="~/vendor/vue-sortable/sortable.min.js" asp-append-version="true"></script>
<script src="~/vendor/vue-sortable/vue-sortable.js" asp-append-version="true"></script>
<script src="~/js/form-editor.js" asp-append-version="true"></script>

View file

@ -119,6 +119,7 @@ document.addEventListener('DOMContentLoaded', () => {
})
Vue.use(vSortable)
Vue.use(VueSanitizeDirective.default)
new Vue({
el: '#FormEditor',

File diff suppressed because one or more lines are too long