Improve currency selection (#4155)

Removes the current value on focus, so that the user gets to see the available options. If no selection or change is made, the value is reset to the previous value on blur.

Closes #4154.
This commit is contained in:
d11n 2022-09-26 03:26:13 +02:00 committed by GitHub
parent db976a6408
commit e8766946dd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 34 additions and 15 deletions

View file

@ -13,30 +13,37 @@ namespace BTCPayServer.TagHelpers
public CurrenciesSuggestionsTagHelper(CurrencyNameTable currencies)
{
_currencies = currencies;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Attributes.RemoveAll("currency-selection");
output.PostElement.AppendHtml("<datalist id=\"currency-selection-suggestion\">");
var currencies = _currencies.Currencies.Where(c => !c.Crypto).Select(c => c.Code).OrderBy(c => c).ToList();
var currencies = _currencies.Currencies
.Where(c => !c.Crypto)
.OrderBy(c => c.Code).ToList();
// insert btc at the front
output.PostElement.AppendHtml("<option value=\"BTC\">BTC - Bitcoin</option>");
output.PostElement.AppendHtml("<option value=\"SATS\">SATS - Satoshi</option>");
// move most often used currencies up
int pos = 0;
InsertAt(currencies, "BTC", pos++);
InsertAt(currencies, "SATS", pos++);
InsertAt(currencies, "USD", pos++);
InsertAt(currencies, "EUR", pos++);
InsertAt(currencies, "JPY", pos++);
InsertAt(currencies, "CNY", pos++);
foreach (var curr in currencies)
// add options
foreach (var c in currencies)
{
output.PostElement.AppendHtml($"<option value=\"{curr}\">");
output.PostElement.AppendHtml($"<option value=\"{c.Code}\">{c.Code} - {c.Name}</option>");
}
output.PostElement.AppendHtml("</datalist>");
output.Attributes.Add("list", "currency-selection-suggestion");
base.Process(context, output);
}
private void InsertAt(List<string> currencies, string curr, int idx)
private void InsertAt(List<CurrencyData> currencies, string code, int idx)
{
var curr = currencies.FirstOrDefault(c => c.Code == code);
currencies.Remove(curr);
currencies.Insert(idx, curr);
}

View file

@ -91,7 +91,7 @@
</div>
<div class="form-group">
<label asp-for="TargetCurrency" class="form-label"></label>
<input asp-for="TargetCurrency" class="form-control" currency-selection style="max-width:10ch;" />
<input asp-for="TargetCurrency" class="form-control w-auto" currency-selection />
<small class="d-inline-block form-text text-muted">Uses the store's default currency (@Model.StoreDefaultCurrency) if empty.</small>
<span asp-validation-for="TargetCurrency" class="text-danger"></span>
</div>

View file

@ -161,7 +161,7 @@
</div>
<div class="form-group col-md-4" v-if="!srvModel.appIdEndpoint">
<label class="form-label" for="Currency">Currency</label>
<input asp-for="Currency" name="currency" currency-selection class="form-control"
<input asp-for="Currency" name="currency" class="form-control w-auto" currency-selection
v-model="srvModel.currency" v-on:change="inputChanges"
:class="{'is-invalid': errors.has('currency') }" />
</div>

View file

@ -36,7 +36,7 @@
</div>
<div class="form-group">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" class="form-control" currency-selection style="max-width:10ch;" />
<input asp-for="Currency" class="form-control w-auto" currency-selection />
<small class="d-inline-block form-text text-muted">Uses the store's default currency (@Model.StoreDefaultCurrency) if empty.</small>
<span asp-validation-for="Currency" class="text-danger"></span>
</div>

View file

@ -49,7 +49,7 @@
</div>
<div class="form-group">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" currency-selection class="form-control" />
<input asp-for="Currency" class="form-control w-auto" currency-selection />
<span asp-validation-for="Currency" class="text-danger"></span>
</div>
</div>

View file

@ -77,7 +77,7 @@
<label asp-for="CustomAmount" class="form-label"></label>
<div class="input-group">
<input asp-for="CustomAmount" type="number" step="any" asp-format="{0}" class="form-control"/>
<input asp-for="CustomCurrency" type="text" class="form-control" currency-selection style="max-width:10ch;"/>
<input asp-for="CustomCurrency" type="text" class="form-control w-auto" currency-selection />
</div>
<span asp-validation-for="CustomAmount" class="text-danger w-100"></span>
<span asp-validation-for="CustomCurrency" class="text-danger w-100"></span>

View file

@ -49,7 +49,7 @@
</div>
<div class="form-group">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" currency-selection class="form-control"/>
<input asp-for="Currency" class="form-control w-auto" currency-selection />
<span asp-validation-for="Currency" class="text-danger"></span>
</div>
</div>

View file

@ -38,7 +38,7 @@
</div>
<div class="form-group col-4">
<label asp-for="Currency" class="form-label"></label>
<input asp-for="Currency" currency-selection class="form-control"/>
<input asp-for="Currency" class="form-control w-auto" currency-selection />
<span asp-validation-for="Currency" class="text-danger"></span>
</div>

View file

@ -31,7 +31,7 @@
<h3 class="mt-5 mb-3">Payment</h3>
<div class="form-group">
<label asp-for="DefaultCurrency" class="form-label"></label>
<input asp-for="DefaultCurrency" class="form-control" currency-selection style="max-width:10ch;" />
<input asp-for="DefaultCurrency" class="form-control w-auto" currency-selection />
<span asp-validation-for="DefaultCurrency" class="text-danger"></span>
</div>
<div class="form-group d-flex align-items-center">

View file

@ -21,7 +21,7 @@
</div>
<div class="form-group">
<label asp-for="DefaultCurrency" class="form-label" data-required></label>
<input asp-for="DefaultCurrency" class="form-control" currency-selection style="max-width:10ch;" />
<input asp-for="DefaultCurrency" class="form-control w-auto" currency-selection />
<span asp-validation-for="DefaultCurrency" class="text-danger"></span>
</div>
<div class="form-group">

View file

@ -129,6 +129,18 @@ document.addEventListener("DOMContentLoaded", function () {
e.target.closest('.btcpay-theme-switch').blur()
})
// Currency Selection: Remove the current input value once the element is focused, so that the user gets to
// see the available options. If no selection or change is made, reset it to the previous value on blur.
// Note: Use focusin/focusout instead of focus/blur, because the latter do not bubble up and delegate won't work.
delegate('focusin', 'input[list="currency-selection-suggestion"]', e => {
e.target.setAttribute('placeholder', e.target.value)
e.target.value = '';
})
delegate('focusout', 'input[list="currency-selection-suggestion"]', e => {
if (!e.target.value) e.target.value = e.target.getAttribute('placeholder')
e.target.removeAttribute('placeholder')
})
// Offcanvas navigation
const mainMenuToggle = document.getElementById('mainMenuToggle')
if (mainMenuToggle) {