diff --git a/pkg/invoices.go b/pkg/invoices.go index 9de4c56..42bbd4c 100644 --- a/pkg/invoices.go +++ b/pkg/invoices.go @@ -753,6 +753,7 @@ type invoiceProductForm struct { } func newInvoiceProductForm(index int, company *Company, locale *Locale, taxOptions []*SelectOption) *invoiceProductForm { + triggerRecompute := template.HTMLAttr(`data-hx-on="change: this.dispatchEvent(new CustomEvent('recompute', {bubbles: true}))"`) form := &invoiceProductForm{ locale: locale, company: company, @@ -790,6 +791,7 @@ func newInvoiceProductForm(index int, company *Company, locale *Locale, taxOptio Type: "number", Required: true, Attributes: []template.HTMLAttr{ + triggerRecompute, `min="0"`, template.HTMLAttr(fmt.Sprintf(`step="%v"`, company.MinCents())), }, @@ -799,6 +801,7 @@ func newInvoiceProductForm(index int, company *Company, locale *Locale, taxOptio Type: "number", Required: true, Attributes: []template.HTMLAttr{ + triggerRecompute, `min="0"`, }, }, @@ -807,6 +810,7 @@ func newInvoiceProductForm(index int, company *Company, locale *Locale, taxOptio Type: "number", Required: true, Attributes: []template.HTMLAttr{ + triggerRecompute, `min="0"`, `max="100"`, }, @@ -815,6 +819,9 @@ func newInvoiceProductForm(index int, company *Company, locale *Locale, taxOptio Label: pgettext("input", "Taxes", locale), Multiple: true, Options: taxOptions, + Attributes: []template.HTMLAttr{ + triggerRecompute, + }, }, } form.Rename() diff --git a/web/static/numerus.js b/web/static/numerus.js index be79afa..06fb7aa 100644 --- a/web/static/numerus.js +++ b/web/static/numerus.js @@ -197,9 +197,12 @@ class Multiselect extends HTMLDivElement { if (!option) { return; } - option.selected = selected; - this.toSearch = this.search.value = ''; - this.rebuild(); + if (option.selected !== selected) { + option.selected = selected; + this.select.dispatchEvent(new Event('change', {bubbles: true})); + this.toSearch = this.search.value = ''; + this.rebuild(); + } } selectHighlighted() {