From ce0d1cfdaa6df46405fa953ee064f89373515ffe Mon Sep 17 00:00:00 2001 From: Oliver Klein Date: Thu, 17 Nov 2022 13:54:14 -0800 Subject: [PATCH 01/26] feat:(label) improved address label ux --- src/cryptoadvance/specter/static/img/tag.svg | 1 + src/cryptoadvance/specter/static/styles.css | 2 +- .../templates/includes/address-data.html | 5 +- .../templates/includes/address-label.html | 347 ++++++++++-------- .../templates/includes/address-row.html | 5 +- 5 files changed, 212 insertions(+), 148 deletions(-) create mode 100644 src/cryptoadvance/specter/static/img/tag.svg diff --git a/src/cryptoadvance/specter/static/img/tag.svg b/src/cryptoadvance/specter/static/img/tag.svg new file mode 100644 index 0000000000..a97fd69d94 --- /dev/null +++ b/src/cryptoadvance/specter/static/img/tag.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/cryptoadvance/specter/static/styles.css b/src/cryptoadvance/specter/static/styles.css index 44bda360f6..3bd4d90f36 100644 --- a/src/cryptoadvance/specter/static/styles.css +++ b/src/cryptoadvance/specter/static/styles.css @@ -1346,4 +1346,4 @@ input:checked + .slider:before { } .last-digits-in-sats-amount{ color: #797979; -} \ No newline at end of file +} diff --git a/src/cryptoadvance/specter/templates/includes/address-data.html b/src/cryptoadvance/specter/templates/includes/address-data.html index 5be940faa5..448d068ae7 100644 --- a/src/cryptoadvance/specter/templates/includes/address-data.html +++ b/src/cryptoadvance/specter/templates/includes/address-data.html @@ -40,6 +40,9 @@ border: 1px solid var(--main-color); background: var(--cmap-border); } + tr { + vertical-align: center; + }

{{ _("Address details") }}


@@ -113,7 +116,7 @@

{{ _("Address details") }}


- + diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index e4510399a0..d6b37f9579 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -1,13 +1,15 @@ @@ -76,45 +106,50 @@ constructor() { super(); // Create a shadow root - var shadow = this.attachShadow({mode: 'open'}); - var style = document.getElementById('address-label').content; + var shadow = this.attachShadow({ mode: "open" }); + + var style = document.getElementById("address-label").content; var clone = style.cloneNode(true); + this.el = clone.querySelector(".address-label-form"); this.serviceIconImg = clone.querySelector(".service-icon"); this.label = clone.querySelector(".label"); this.update = clone.querySelector(".update"); this.cancel = clone.querySelector(".cancel"); this.edit = clone.querySelector(".edit"); - this.explorerLink = clone.querySelector(".explorer-link"); - + // Attach the created element to the shadow dom shadow.appendChild(clone); } - static get observedAttributes() {return ['data-wallet', 'data-address']; } + static get observedAttributes() { + return ["data-wallet", "data-address"]; + } attributeChangedCallback(name, oldValue, newValue) { - if (name=="data-address") { - this.address = newValue + if (name == "data-address") { + this.address = newValue; } - if (name=="data-wallet") { - this.wallet = newValue + if (name == "data-wallet") { + this.wallet = newValue; } - //ToDo: Implement more here } connectedCallback() { - this.address = this.getAttribute('data-address'); - this.wallet = this.getAttribute('data-wallet'); - this.labelValue = this.getAttribute('data-label'); - this.serviceId = this.getAttribute('data-service-id'); - this.explorer = '{{ specter.explorer }}'; + this.address = this.getAttribute("data-address"); + this.wallet = this.getAttribute("data-wallet"); + this.labelValue = this.getAttribute("data-label"); + this.serviceId = this.getAttribute("data-service-id"); this.label.title = this.address; this.isEditing = false; - if ((typeof services !== 'undefined') && (this.serviceId in services)) { + if (typeof services !== "undefined" && this.serviceId in services) { // `services` globally injected via includes/services-data.html - this.serviceIconImg.src = "{{ext_url_prefix}}/" + this.serviceId + "/static/" + services[this.serviceId].icon; + this.serviceIconImg.src = + "{{ext_url_prefix}}/" + + this.serviceId + + "/static/" + + services[this.serviceId].icon; } // Set the label - fetch if not specified @@ -126,123 +161,137 @@ } // Set title mode for address-label element - if (this.getAttribute('date-size') == 'title') { + if (this.getAttribute("date-size") == "title") { this.isTitle = true; - this.label.style.fontSize = '1.5em'; - this.el.style.fontSize = '1.2em'; - this.edit.style.width = '30px'; - this.edit.children[0].style.width = '30px'; - this.explorerLink.style['text-decoration'] = 'none'; + + this.el.style.fontSize = "1.2em"; + this.el.style.justifyContent = "center"; + + this.label.style.fontSize = "1.5em"; + + this.edit.style.height = "36px"; } else { this.isTitle = false; } // Ensure text pasted is not formatted with special formatting. - this.label.addEventListener('paste', function (event) { + this.label.addEventListener("paste", function (event) { event.preventDefault(); - document.execCommand('inserttext', false, event.clipboardData.getData('text/plain')); + document.execCommand( + "inserttext", + false, + event.clipboardData.getData("text/plain") + ); }); - this.enableExplorerLink(); + this.edit.addEventListener("keyup", (e) => { + // Removes default action of spacebar + if (e.keyCode == 32) { + e.preventDefault(); + } + }); + + this.edit.addEventListener("keydown", (e) => { + // Remove default action of new line on return press + if (e.keyCode == 27) { + e.preventDefault(); + this.cancel.click(); + } + if (e.keyCode == 13) { + e.preventDefault(); + this.update.click(); + } + }); this.edit.onclick = () => { - this.label.setAttributeNode(document.createAttribute('contenteditable')); + this.label.setAttributeNode( + document.createAttribute("contenteditable") + ); + if (this.isTitle) { - this.label.style['font-size'] = '1.1em'; + this.label.style["font-size"] = "1.1em"; } - this.label.style['border-bottom'] = '1px solid #ccc'; - this.labelValue = this.label.innerText; - this.edit.classList.add('hidden'); - this.cancel.classList.remove('hidden'); - this.update.classList.remove('hidden'); - this.disableExplorerLink(); + + this.labelValue = this.label.innerText; //store the value of the element + + this.label.innerText = ""; + this.label.focus(); + + this.cancel.classList.remove("hidden"); + this.update.classList.remove("hidden"); + this.isEditing = true; - } + }; this.cancel.onclick = () => { this.label.innerText = this.labelValue; this.closeEditMode(); - } + }; this.update.onclick = async () => { - if (await this.setAddressLabel()) { - this.labelValue = this.label.innerText; - this.closeEditMode(); - let event = new CustomEvent('updateAddressLabel', { detail: { - label: this.labelValue, - address: this.address, - }}); - document.dispatchEvent(event); - if (!this.labelValue) { - this.label.innerText = this.address + if (this.label.innerText) { + if (await this.setAddressLabel()) { + this.labelValue = this.label.innerText; + this.closeEditMode(); + let event = new CustomEvent("updateAddressLabel", { + detail: { + label: this.labelValue, + address: this.address, + }, + }); + document.dispatchEvent(event); + } else { + showError( + `{{ _("Failed to update address label. Please refresh the page and try again.") }}` + ); } } else { - showError(`{{ _("Failed to update address label. Please refresh the page and try again.") }}`) + this.edit.click(); } - } - + }; + this.addEventListener("updateAddressLabel", function (e) { if (this.address != e.detail.address) { - return + return; } - this.labelValue = e.detail.label + this.labelValue = e.detail.label; if (!this.isEditing) { if (e.detail.label) { - this.label.innerText = e.detail.label + this.label.innerText = e.detail.label; } else { - this.label.innerText = e.detail.address + this.label.innerText = e.detail.address; } } }); } closeEditMode() { - this.label.removeAttribute('contenteditable') + this.label.removeAttribute("contenteditable"); if (this.isTitle) { - this.label.style['font-size'] = '1.5em'; + this.label.style["font-size"] = "1.5em"; } - this.label.style.border = 'none'; - this.edit.classList.remove('hidden'); - this.cancel.classList.add('hidden'); - this.update.classList.add('hidden'); + this.label.style.border = "none"; + this.edit.classList.remove("hidden"); + this.cancel.classList.add("hidden"); + this.update.classList.add("hidden"); this.isEditing = false; - this.enableExplorerLink(); - } - - enableExplorerLink() { - this.explorerLink.classList.add('explorer-link'); - this.explorerLink.style.removeProperty('text-decoration') - if (this.explorer) { - this.explorerLink.href = `${ this.explorer }address/${ this.address }` - this.explorerLink.onclick = () => {return true;} - } else { - this.explorerLink.onclick = () => { - copyText(this.address, `{{ _("Copied address") }}: ${ this.address }`); - } - } - } - - disableExplorerLink() { - this.explorerLink.classList.remove('explorer-link'); - this.explorerLink.removeAttribute('href') - this.explorerLink.style['text-decoration'] = 'none'; - this.explorerLink.onclick = () => {return false;} } async fetchAddressLabel() { - let url = `{{ url_for('wallets_endpoint_api.get_label', wallet_alias='WALLET_ALIAS') }}`.replace("WALLET_ALIAS", this.wallet); + let url = + `{{ url_for('wallets_endpoint_api.get_label', wallet_alias='WALLET_ALIAS') }}`.replace( + "WALLET_ALIAS", + this.wallet + ); var formData = new FormData(); - formData.append('address', this.address); - formData.append('csrf_token', '{{ csrf_token() }}'); + formData.append("address", this.address); + formData.append("csrf_token", "{{ csrf_token() }}"); try { - const response = await fetch( - url, - { - method: 'POST', - body: formData - } - ); - if(response.status != 200){ + const response = await fetch(url, { + method: "POST", + body: formData, + }); + if (response.status != 200) { showError(await response.text()); return; } @@ -253,39 +302,47 @@ } return; } - showError(`{{ _("Failed to fetch data. Please refresh the page and retry.") }}`); - } catch(e) { - console.log(`{{ _("Caught error fetching address label") }}: `, e); - showError(`{{ _("Failed to fetch data. Please refresh the page and retry.") }}`); + showError( + `{{ _("Failed to fetch data. Please refresh the page and retry.") }}` + ); + } catch (e) { + console.log( + `{{ _("Caught error fetching address label") }}: `, + e + ); + showError( + `{{ _("Failed to fetch data. Please refresh the page and retry.") }}` + ); } } async setAddressLabel() { - let url = `{{ url_for('wallets_endpoint_api.set_label', wallet_alias='WALLET_ALIAS') }}`.replace("WALLET_ALIAS", this.wallet); + let url = + `{{ url_for('wallets_endpoint_api.set_label', wallet_alias='WALLET_ALIAS') }}`.replace( + "WALLET_ALIAS", + this.wallet + ); var formData = new FormData(); - formData.append('address', this.address); - formData.append('label', this.label.innerText); - formData.append('csrf_token', '{{ csrf_token() }}'); + formData.append("address", this.address); + formData.append("label", this.label.innerText); + formData.append("csrf_token", "{{ csrf_token() }}"); try { - const response = await fetch( - url, - { - method: 'POST', - body: formData - } - ); - if(response.status != 200){ + const response = await fetch(url, { + method: "POST", + body: formData, + }); + if (response.status != 200) { showError(await response.text()); return; } const jsonResponse = await response.json(); return jsonResponse.success; - } catch(e) { + } catch (e) { console.log("Caught error: ", e); showError(e); return false; } } } - customElements.define('address-label', AddressLabelElement); + customElements.define("address-label", AddressLabelElement); diff --git a/src/cryptoadvance/specter/templates/includes/address-row.html b/src/cryptoadvance/specter/templates/includes/address-row.html index 309fda4838..b36ac25a60 100644 --- a/src/cryptoadvance/specter/templates/includes/address-row.html +++ b/src/cryptoadvance/specter/templates/includes/address-row.html @@ -12,6 +12,9 @@ .address-row:hover { background-color: var(--cmap-bg-lightest); } + td { + vertical-align: middle !important; + } @@ -169,4 +172,4 @@ } customElements.define('address-row', AddressRowElement); - \ No newline at end of file + From cd0eb5f73f62e007c5d469623a022091663ffcb4 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Wed, 23 Nov 2022 17:49:18 +0100 Subject: [PATCH 02/26] service icon alignment --- .../specter/templates/includes/address-label.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index d6b37f9579..b1baab27ea 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -5,7 +5,8 @@ } .service-icon { - margin-top: -5px; + margin-left: 2px; + margin-right: 2px; height: 24px; vertical-align: middle; } @@ -192,11 +193,13 @@ }); this.edit.addEventListener("keydown", (e) => { - // Remove default action of new line on return press + // Escape = cancel if (e.keyCode == 27) { e.preventDefault(); this.cancel.click(); } + // Return = update + // Removes default action of new line on return press if (e.keyCode == 13) { e.preventDefault(); this.update.click(); From d5a0c1657fe5a2f8cc8256f861e4ba458e3926f9 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Wed, 23 Nov 2022 21:11:38 +0100 Subject: [PATCH 03/26] make it work on firefox --- .../templates/includes/address-label.html | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index b1baab27ea..caa07f319c 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -22,6 +22,7 @@ margin-left: 2px; white-space: nowrap; overflow: visible; + caret-color: orange; } .edit { @@ -207,23 +208,18 @@ }); this.edit.onclick = () => { - this.label.setAttributeNode( - document.createAttribute("contenteditable") - ); - + this.isEditing = true; + this.label.setAttribute("contenteditable", "true"); + let selection = window.getSelection(); + selection.selectAllChildren(this.label); + this.label.blur(); // This blur is needed on Firefox to display the caret - for whatever reasons ... + this.label.focus(); if (this.isTitle) { this.label.style["font-size"] = "1.1em"; } - this.labelValue = this.label.innerText; //store the value of the element - - this.label.innerText = ""; - this.label.focus(); - this.cancel.classList.remove("hidden"); this.update.classList.remove("hidden"); - - this.isEditing = true; }; this.cancel.onclick = () => { @@ -249,7 +245,7 @@ ); } } else { - this.edit.click(); + this.closeEditMode(); } }; From 05171c48e0a6f1882974af0ca8ccecb371e77a72 Mon Sep 17 00:00:00 2001 From: Oliver Klein Date: Thu, 24 Nov 2022 11:24:37 -0800 Subject: [PATCH 04/26] fix:(label) fix spacing of the service logo on tx table --- src/cryptoadvance/specter/templates/includes/tx-row.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/tx-row.html b/src/cryptoadvance/specter/templates/includes/tx-row.html index 5dfa6e42ae..6389bfb92d 100644 --- a/src/cryptoadvance/specter/templates/includes/tx-row.html +++ b/src/cryptoadvance/specter/templates/includes/tx-row.html @@ -32,7 +32,6 @@ text-overflow: ellipsis; } .service-icon { - margin-top: -5px; margin-right: 0.5em; height:24px; vertical-align: middle; @@ -100,7 +99,7 @@ - + - From 3b60fe7cfd8030fcf4674b3daee4c34ffad1cbc6 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 1 Dec 2022 15:03:36 +0100 Subject: [PATCH 08/26] draft - copy button in address list --- .../specter/static/img/copy-color.svg | 61 +++++++++++++++++++ src/cryptoadvance/specter/static/styles.css | 1 - .../templates/includes/address-row.html | 29 ++++++++- 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/cryptoadvance/specter/static/img/copy-color.svg diff --git a/src/cryptoadvance/specter/static/img/copy-color.svg b/src/cryptoadvance/specter/static/img/copy-color.svg new file mode 100644 index 0000000000..5fc36bea20 --- /dev/null +++ b/src/cryptoadvance/specter/static/img/copy-color.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cryptoadvance/specter/static/styles.css b/src/cryptoadvance/specter/static/styles.css index 44371ec175..aff6cbdef7 100644 --- a/src/cryptoadvance/specter/static/styles.css +++ b/src/cryptoadvance/specter/static/styles.css @@ -739,7 +739,6 @@ table{ } td, th{ padding: 20px 10px; - border-bottom: 1px solid var(--cmap-bg-lightest); } tr, thead{ background: var(--cmap-bg-lighter); diff --git a/src/cryptoadvance/specter/templates/includes/address-row.html b/src/cryptoadvance/specter/templates/includes/address-row.html index 60421b6b23..5f933c9eb2 100644 --- a/src/cryptoadvance/specter/templates/includes/address-row.html +++ b/src/cryptoadvance/specter/templates/includes/address-row.html @@ -15,11 +15,27 @@ td { vertical-align: middle !important; } + .address { + display: flex; + align-items: center; + gap: 5px; + } + .copy { + display: none; + height: 30px; + width: 30px; + color: white; + cursor: pointer; + border-radius: 3px; + background: rgba(255,255,255,0.08); + padding: 3px; + } - @@ -50,6 +66,8 @@ this.index = clone.querySelector(".index"); this.address = clone.querySelector(".address .explorer-link"); + this.addressContainer = clone.getElementById('address-container') + this.copyBtn = clone.getElementById('copy-btn') this.label = clone.querySelector(".label"); this.used = clone.querySelector(".used"); this.utxo = clone.querySelector(".utxo"); @@ -82,6 +100,15 @@ } } + this.copyBtn.addEventListener('click', () => { + let address = this.addressData.address + copyText(address, "Copied address") + }) + this.addressContainer.addEventListener('mouseover', () => { + console.log("Is the hover event listener working at all?") + this.copyBtn.style.display = "block" + }) + if (this.hideSensitiveInfo) { this.label.innerHTML = '############' } else { From 91c903a6fe751423ba03d98253de27f3b17df4e3 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Sun, 11 Dec 2022 20:20:34 +0100 Subject: [PATCH 09/26] click away from edit section cancels editing --- src/cryptoadvance/specter/static/helpers.js | 23 +++++++++++++++++++ .../templates/includes/address-label.html | 3 +-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/cryptoadvance/specter/static/helpers.js b/src/cryptoadvance/specter/static/helpers.js index 6375d0be85..026ad99f13 100644 --- a/src/cryptoadvance/specter/static/helpers.js +++ b/src/cryptoadvance/specter/static/helpers.js @@ -62,6 +62,29 @@ document.addEventListener("updateAddressLabel", function (e) { } }); +// Clicking somewhere else than on the edit label section cancels the label editing +document.addEventListener("click", (e) => { + addressesTableComponent = document.querySelector('addresses-table') + const path = e.composedPath() + const clickedElement = path[0] + const parentElement = path[1] + addressesTableComponent.shadowRoot.querySelectorAll('address-row').forEach(addressRow => { + const addressLabel = addressRow.shadowRoot.querySelector('address-label') + if (addressLabel.isEditing) { + if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { + console.log("Clicking on the edit button or on the label span, don't end the editing ...") + return + } + else { + console.log("Clicking somewhere else on the screen. Canceling editing.") + if (addressLabel.isEditing) { + addressLabel.closeEditMode() + } + } + } + }) +}) + document.documentElement.style.setProperty('--mobileDistanceElementBottomHeight', `${Math.max(0, window.outerHeight - window.innerHeight)}px`); function showError(msg, timeout=0) { diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index 2190fbe6a2..5d7e2c2930 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -109,10 +109,8 @@ super(); // Create a shadow root var shadow = this.attachShadow({ mode: "open" }); - var style = document.getElementById("address-label").content; var clone = style.cloneNode(true); - this.el = clone.querySelector(".address-label-form"); this.serviceIconImg = clone.querySelector(".service-icon"); this.label = clone.querySelector(".label"); @@ -187,6 +185,7 @@ this.edit.addEventListener("keyup", (e) => { // Removes default action of spacebar + // Only works on Chrome! No space on Firefox ... if (e.keyCode == 32) { e.preventDefault(); } From eb5f68f7f41d71e697a4efbd41c0245c663318ba Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Mon, 12 Dec 2022 18:23:56 +0100 Subject: [PATCH 10/26] check whether addressesTableComponent is available --- src/cryptoadvance/specter/static/helpers.js | 28 +++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/cryptoadvance/specter/static/helpers.js b/src/cryptoadvance/specter/static/helpers.js index 026ad99f13..8e0f738a88 100644 --- a/src/cryptoadvance/specter/static/helpers.js +++ b/src/cryptoadvance/specter/static/helpers.js @@ -68,21 +68,23 @@ document.addEventListener("click", (e) => { const path = e.composedPath() const clickedElement = path[0] const parentElement = path[1] - addressesTableComponent.shadowRoot.querySelectorAll('address-row').forEach(addressRow => { - const addressLabel = addressRow.shadowRoot.querySelector('address-label') - if (addressLabel.isEditing) { - if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { - console.log("Clicking on the edit button or on the label span, don't end the editing ...") - return - } - else { - console.log("Clicking somewhere else on the screen. Canceling editing.") - if (addressLabel.isEditing) { - addressLabel.closeEditMode() + if (addressesTableComponent) { + addressesTableComponent.shadowRoot.querySelectorAll('address-row').forEach(addressRow => { + const addressLabel = addressRow.shadowRoot.querySelector('address-label') + if (addressLabel.isEditing) { + if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { + console.log("Clicking on the edit button or on the label span, don't end the editing ...") + return + } + else { + console.log("Clicking somewhere else on the screen. Canceling editing.") + if (addressLabel.isEditing) { + addressLabel.closeEditMode() + } } } - } - }) + }) + } }) document.documentElement.style.setProperty('--mobileDistanceElementBottomHeight', `${Math.max(0, window.outerHeight - window.innerHeight)}px`); From 9204952693122a589336f0ca1fa207a04691affb Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Mon, 12 Dec 2022 18:24:37 +0100 Subject: [PATCH 11/26] solution for spacebar bug in firefox --- .../templates/includes/address-label.html | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index 5d7e2c2930..ed66b7f291 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -183,15 +183,24 @@ ); }); - this.edit.addEventListener("keyup", (e) => { - // Removes default action of spacebar - // Only works on Chrome! No space on Firefox ... - if (e.keyCode == 32) { - e.preventDefault(); + this.label.addEventListener("keyup", (e) => { + // Just removes default action of spacebar for Chrome + if (navigator.userAgent.indexOf('Chrome') !== -1) { + if (e.keyCode == 32) { + e.preventDefault() + } + } + // This simpel approach does not work on Firefox, here we have to emulate the spacebar with JS + else if (navigator.userAgent.indexOf('Firefox') !== -1) { + if (e.keyCode == 32) { + e.preventDefault() + this.label.innerText = this.label.innerText + '\u00A0' + this.moveCaret(1) + } } }); - this.edit.addEventListener("keydown", (e) => { + this.label.addEventListener("keydown", (e) => { // Escape = cancel if (e.keyCode == 27) { e.preventDefault(); @@ -274,6 +283,13 @@ this.isEditing = false; } + moveCaret(charCount) { + const selection = window.getSelection() + const focusNode = selection.focusNode + const newOffset = selection.focusOffset + charCount; + selection.collapse(focusNode, newOffset) + } + async fetchAddressLabel() { let url = `{{ url_for('wallets_endpoint_api.get_label', wallet_alias='WALLET_ALIAS') }}`.replace( From 7f36482125d3d0d2c92e3461bc2d9d327153fb59 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Tue, 13 Dec 2022 09:46:05 +0100 Subject: [PATCH 12/26] address data and tx table listeneres --- src/cryptoadvance/specter/static/helpers.js | 38 ++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/static/helpers.js b/src/cryptoadvance/specter/static/helpers.js index 8e0f738a88..6572315e67 100644 --- a/src/cryptoadvance/specter/static/helpers.js +++ b/src/cryptoadvance/specter/static/helpers.js @@ -65,6 +65,8 @@ document.addEventListener("updateAddressLabel", function (e) { // Clicking somewhere else than on the edit label section cancels the label editing document.addEventListener("click", (e) => { addressesTableComponent = document.querySelector('addresses-table') + txTableComponent = document.querySelector('tx-table') + addressDataComponent = document.querySelector('address-data') const path = e.composedPath() const clickedElement = path[0] const parentElement = path[1] @@ -79,7 +81,41 @@ document.addEventListener("click", (e) => { else { console.log("Clicking somewhere else on the screen. Canceling editing.") if (addressLabel.isEditing) { - addressLabel.closeEditMode() + addressLabel.cancel.click() + } + } + } + }) + } + else if (txTableComponent) { + txTableComponent.shadowRoot.querySelectorAll('tx-row').forEach(txRow => { + const addressLabel = txRow.shadowRoot.querySelector('address-label') + if (addressLabel.isEditing) { + if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { + console.log("Clicking on the edit button or on the label span, don't end the editing ...") + return + } + else { + console.log("Clicking somewhere else on the screen. Canceling editing.") + if (addressLabel.isEditing) { + addressLabel.cancel.click() + } + } + } + }) + } + // Can't use else if here: Address data is a pop-up so addresses or tx table are still in the DOM + if (addressDataComponent) { + addressDataComponent.shadowRoot.querySelectorAll('address-label').forEach(addressLabel => { + if (addressLabel.isEditing) { + if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { + console.log("Clicking on the edit button or on the label span, don't end the editing ...") + return + } + else { + console.log("Clicking somewhere else on the screen. Canceling editing.") + if (addressLabel.isEditing) { + addressLabel.cancel.click() } } } From 5eaae5257710dabe18912fb31d9103c0a2585454 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Tue, 13 Dec 2022 16:56:44 +0100 Subject: [PATCH 13/26] make pressing ENTER work --- src/cryptoadvance/specter/static/helpers.js | 24 +++----- .../templates/includes/address-label.html | 56 +++++++++++-------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/cryptoadvance/specter/static/helpers.js b/src/cryptoadvance/specter/static/helpers.js index 6572315e67..e7c5851db6 100644 --- a/src/cryptoadvance/specter/static/helpers.js +++ b/src/cryptoadvance/specter/static/helpers.js @@ -74,15 +74,13 @@ document.addEventListener("click", (e) => { addressesTableComponent.shadowRoot.querySelectorAll('address-row').forEach(addressRow => { const addressLabel = addressRow.shadowRoot.querySelector('address-label') if (addressLabel.isEditing) { - if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { - console.log("Clicking on the edit button or on the label span, don't end the editing ...") + if ([addressLabel.edit, addressLabel.cancel, addressLabel.update].includes(parentElement) || clickedElement == addressLabel.edit) { + console.log("Clicking on the label buttons, don't end the editing ...") return } else { console.log("Clicking somewhere else on the screen. Canceling editing.") - if (addressLabel.isEditing) { - addressLabel.cancel.click() - } + addressLabel.cancelEditing() } } }) @@ -91,15 +89,13 @@ document.addEventListener("click", (e) => { txTableComponent.shadowRoot.querySelectorAll('tx-row').forEach(txRow => { const addressLabel = txRow.shadowRoot.querySelector('address-label') if (addressLabel.isEditing) { - if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { - console.log("Clicking on the edit button or on the label span, don't end the editing ...") + if ([addressLabel.edit, addressLabel.cancel, addressLabel.update].includes(parentElement) || clickedElement == addressLabel.edit) { + console.log("Clicking on the label buttons, don't end the editing ...") return } else { console.log("Clicking somewhere else on the screen. Canceling editing.") - if (addressLabel.isEditing) { - addressLabel.cancel.click() - } + addressLabel.cancelEditing() } } }) @@ -108,15 +104,13 @@ document.addEventListener("click", (e) => { if (addressDataComponent) { addressDataComponent.shadowRoot.querySelectorAll('address-label').forEach(addressLabel => { if (addressLabel.isEditing) { - if (parentElement == addressLabel.edit || clickedElement == addressLabel.edit) { - console.log("Clicking on the edit button or on the label span, don't end the editing ...") + if ([addressLabel.edit, addressLabel.cancel, addressLabel.update].includes(parentElement) || clickedElement == addressLabel.edit) { + console.log("Clicking on the label buttons, don't end the editing ...") return } else { console.log("Clicking somewhere else on the screen. Canceling editing.") - if (addressLabel.isEditing) { - addressLabel.cancel.click() - } + addressLabel.cancelEditing() } } }) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index ed66b7f291..3705286256 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -204,13 +204,13 @@ // Escape = cancel if (e.keyCode == 27) { e.preventDefault(); - this.cancel.click(); + this.cancelEditing(); } // Return = update // Removes default action of new line on return press if (e.keyCode == 13) { e.preventDefault(); - this.update.click(); + this.updateAddressLabel(); } }); @@ -230,30 +230,11 @@ }; this.cancel.onclick = () => { - this.label.innerText = this.labelValue; - this.closeEditMode(); + this.cancelEditing() }; - this.update.onclick = async () => { - if (this.label.innerText) { - if (await this.setAddressLabel()) { - this.labelValue = this.label.innerText; - this.closeEditMode(); - let event = new CustomEvent("updateAddressLabel", { - detail: { - label: this.labelValue, - address: this.address, - }, - }); - document.dispatchEvent(event); - } else { - showError( - `{{ _("Failed to update address label. Please refresh the page and try again.") }}` - ); - } - } else { - this.closeEditMode(); - } + this.update.onclick = () => { + this.updateAddresLabel() }; this.addEventListener("updateAddressLabel", function (e) { @@ -283,6 +264,33 @@ this.isEditing = false; } + cancelEditing() { + this.label.innerText = this.labelValue; + this.closeEditMode() + } + + async updateAddressLabel() { + if (this.label.innerText) { + if (await this.setAddressLabel()) { + this.labelValue = this.label.innerText; + this.closeEditMode(); + let event = new CustomEvent("updateAddressLabel", { + detail: { + label: this.labelValue, + address: this.address, + }, + }); + document.dispatchEvent(event); + } else { + showError( + `{{ _("Failed to update address label. Please refresh the page and try again.") }}` + ); + } + } else { + this.closeEditMode(); + } + } + moveCaret(charCount) { const selection = window.getSelection() const focusNode = selection.focusNode From 27d44e3ba917c813e9eae2e1eeb335f5fe841bd1 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Tue, 13 Dec 2022 19:23:44 +0100 Subject: [PATCH 14/26] add address to tx info --- .../specter/templates/includes/tx-data.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/tx-data.html b/src/cryptoadvance/specter/templates/includes/tx-data.html index c4112f5d53..06da34a8be 100644 --- a/src/cryptoadvance/specter/templates/includes/tx-data.html +++ b/src/cryptoadvance/specter/templates/includes/tx-data.html @@ -166,8 +166,9 @@

{{ _("Transaction details") }}


var price = formatPrice(spentOutput.value, spentOutput.assetlabel, this.symbol, this.price); addressAndValue = ` - {{ _("Address:") }} - ${address}
+ {{ _("Label:") }} + {{ _("Transaction details") }}
rawtxHTML += `

{{ _("Output #${i}") }}

- {{ _("Address:") }} - ${address}
+ {{ _("Label:") }} + Date: Wed, 14 Dec 2022 11:52:22 +0100 Subject: [PATCH 15/26] typo --- src/cryptoadvance/specter/templates/includes/address-label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index 3705286256..eefaea4d01 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -234,7 +234,7 @@ }; this.update.onclick = () => { - this.updateAddresLabel() + this.updateAddressLabel() }; this.addEventListener("updateAddressLabel", function (e) { From fbd7d95f4e5bc88d595951eabebb0151c2fb7e50 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Wed, 14 Dec 2022 18:23:52 +0100 Subject: [PATCH 16/26] firefox fixes --- .../templates/includes/address-label.html | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index eefaea4d01..f62f0fb40c 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -82,7 +82,7 @@ value="{{ csrf_token() }}" /> - + {{ _("Fetching address label...") }} @@ -183,19 +183,21 @@ ); }); + + // Browsers can interpret releasing the spacebar as a click this.label.addEventListener("keyup", (e) => { - // Just removes default action of spacebar for Chrome - if (navigator.userAgent.indexOf('Chrome') !== -1) { - if (e.keyCode == 32) { - e.preventDefault() - } + if (e.keyCode == 32) { + e.preventDefault() } - // This simpel approach does not work on Firefox, here we have to emulate the spacebar with JS - else if (navigator.userAgent.indexOf('Firefox') !== -1) { + }) + + // Pressing the spacebar does not work in Firefox by default + this.label.addEventListener("keydown", (e) => { + if (navigator.userAgent.indexOf('Firefox') !== -1) { if (e.keyCode == 32) { e.preventDefault() - this.label.innerText = this.label.innerText + '\u00A0' - this.moveCaret(1) + // This inserts a space and moves the cursor to the right + document.execCommand('insertHTML', false, '\u00A0'); } } }); @@ -217,10 +219,12 @@ this.edit.onclick = () => { this.isEditing = true; this.label.setAttribute("contenteditable", "true"); + // Setting contenteditable is already giving focus, just as a safeguard. + if (!this.label.matches(':focus')) { + this.label.focus() + } let selection = window.getSelection(); selection.selectAllChildren(this.label); - this.label.blur(); // This blur is needed on Firefox to display the caret - for whatever reasons ... - this.label.focus(); if (this.isTitle) { this.label.style["font-size"] = "1.1em"; } @@ -291,13 +295,6 @@ } } - moveCaret(charCount) { - const selection = window.getSelection() - const focusNode = selection.focusNode - const newOffset = selection.focusOffset + charCount; - selection.collapse(focusNode, newOffset) - } - async fetchAddressLabel() { let url = `{{ url_for('wallets_endpoint_api.get_label', wallet_alias='WALLET_ALIAS') }}`.replace( From 1607e039f680ea8a6324ffe1394226da5276f619 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Wed, 14 Dec 2022 19:20:29 +0100 Subject: [PATCH 17/26] prevent bubbling --- .../specter/templates/includes/address-label.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index f62f0fb40c..94e6352b1b 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -216,7 +216,7 @@ } }); - this.edit.onclick = () => { + this.edit.onclick = (e) => { this.isEditing = true; this.label.setAttribute("contenteditable", "true"); // Setting contenteditable is already giving focus, just as a safeguard. @@ -231,6 +231,7 @@ this.labelValue = this.label.innerText; //store the value of the element this.cancel.classList.remove("hidden"); this.update.classList.remove("hidden"); + e.stopPropagation() }; this.cancel.onclick = () => { From 0f4885295f048fc0bdbc9ee5a73260003d0eeaf2 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Wed, 14 Dec 2022 19:21:17 +0100 Subject: [PATCH 18/26] check whether there is an address-label for txlist --- src/cryptoadvance/specter/static/helpers.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/static/helpers.js b/src/cryptoadvance/specter/static/helpers.js index 4fc0d66393..e8dab648e1 100644 --- a/src/cryptoadvance/specter/static/helpers.js +++ b/src/cryptoadvance/specter/static/helpers.js @@ -88,7 +88,8 @@ document.addEventListener("click", (e) => { else if (txTableComponent) { txTableComponent.shadowRoot.querySelectorAll('tx-row').forEach(txRow => { const addressLabel = txRow.shadowRoot.querySelector('address-label') - if (addressLabel.isEditing) { + // In the tx labeling there also "3 Recipients labels" + if (addressLabel !== null && addressLabel.isEditing) { if ([addressLabel.edit, addressLabel.cancel, addressLabel.update].includes(parentElement) || clickedElement == addressLabel.edit) { console.log("Clicking on the label buttons, don't end the editing ...") return From b4f1abf73d948525580d8d6f9a8d9f693f9fa4a3 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 15 Dec 2022 14:40:48 +0100 Subject: [PATCH 19/26] select all only at edit start --- .../specter/templates/includes/address-label.html | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index 94e6352b1b..cb6b18e113 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -217,14 +217,21 @@ }); this.edit.onclick = (e) => { - this.isEditing = true; + let editingStarted = false + if (!this.isEditing) { + this.isEditing = true + editingStarted = true + } this.label.setAttribute("contenteditable", "true"); // Setting contenteditable is already giving focus, just as a safeguard. if (!this.label.matches(':focus')) { this.label.focus() } - let selection = window.getSelection(); - selection.selectAllChildren(this.label); + // Select all only when we start editing + if (editingStarted === true) { + let selection = window.getSelection() + selection.selectAllChildren(this.label) + } if (this.isTitle) { this.label.style["font-size"] = "1.1em"; } From 809cec7e6f12ab731ebb5b933c50c8f38bf8d89a Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 15 Dec 2022 16:16:13 +0100 Subject: [PATCH 20/26] revert copy address button --- .../templates/includes/address-row.html | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-row.html b/src/cryptoadvance/specter/templates/includes/address-row.html index 5f933c9eb2..3d7fa25a55 100644 --- a/src/cryptoadvance/specter/templates/includes/address-row.html +++ b/src/cryptoadvance/specter/templates/includes/address-row.html @@ -15,27 +15,11 @@ td { vertical-align: middle !important; } - .address { - display: flex; - align-items: center; - gap: 5px; - } - .copy { - display: none; - height: 30px; - width: 30px; - color: white; - cursor: pointer; - border-radius: 3px; - background: rgba(255,255,255,0.08); - padding: 3px; - }

- @@ -63,11 +47,8 @@ var style = document.getElementById('address-row').content; var clone = style.cloneNode(true); this.el = clone.querySelector(".address-row"); - this.index = clone.querySelector(".index"); this.address = clone.querySelector(".address .explorer-link"); - this.addressContainer = clone.getElementById('address-container') - this.copyBtn = clone.getElementById('copy-btn') this.label = clone.querySelector(".label"); this.used = clone.querySelector(".used"); this.utxo = clone.querySelector(".utxo"); @@ -100,15 +81,6 @@ } } - this.copyBtn.addEventListener('click', () => { - let address = this.addressData.address - copyText(address, "Copied address") - }) - this.addressContainer.addEventListener('mouseover', () => { - console.log("Is the hover event listener working at all?") - this.copyBtn.style.display = "block" - }) - if (this.hideSensitiveInfo) { this.label.innerHTML = '############' } else { From d6e08db5d5c0cfe29cdf8cebbf283156343fcf07 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 15 Dec 2022 20:27:09 +0100 Subject: [PATCH 21/26] add editable attribute --- .../specter/templates/includes/address-label.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index cb6b18e113..441e28b2bd 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -117,7 +117,6 @@ this.update = clone.querySelector(".update"); this.cancel = clone.querySelector(".cancel"); this.edit = clone.querySelector(".edit"); - // Attach the created element to the shadow dom shadow.appendChild(clone); } @@ -136,6 +135,11 @@ } connectedCallback() { + // We want to set editable=false only selectively + this.editable = this.hasAttribute('editable') ? JSON.parse(this.getAttribute('editable')) : true; + if (!this.editable) { + this.edit.disabled = true + } this.address = this.getAttribute("data-address"); this.wallet = this.getAttribute("data-wallet"); this.labelValue = this.getAttribute("data-label"); From acb4829332e885c16627277bc513e961b9d81b4a Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 15 Dec 2022 20:27:55 +0100 Subject: [PATCH 22/26] disable editing for receive page --- .../specter/templates/wallet/receive/wallet_receive.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/templates/wallet/receive/wallet_receive.jinja b/src/cryptoadvance/specter/templates/wallet/receive/wallet_receive.jinja index c83b657053..488f8ba0e0 100644 --- a/src/cryptoadvance/specter/templates/wallet/receive/wallet_receive.jinja +++ b/src/cryptoadvance/specter/templates/wallet/receive/wallet_receive.jinja @@ -34,7 +34,7 @@
- + {% if specter.is_liquid and wallet.address != wallet.unconfidential_address %}
{{ _("Address") }}:
{{ _("Label") }}:
{{ _("Label") }}:
{{ _("From wallet") }}:${walletName}
{{ _("Address index") }}:${addressIndex}
{{ _("Is change address") }}:${isChange ? '{{ _("Yes") }}' : '{{ _("No") }}'}
From 464972793babf1c0554969c3d5c93dfceb1f9a68 Mon Sep 17 00:00:00 2001 From: Oliver Klein Date: Thu, 24 Nov 2022 11:32:49 -0800 Subject: [PATCH 05/26] fix:(label) fix sizing of service icon within label --- src/cryptoadvance/specter/templates/includes/address-label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index caa07f319c..556a477df5 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -7,7 +7,7 @@ .service-icon { margin-left: 2px; margin-right: 2px; - height: 24px; + height: 18px; vertical-align: middle; } From 6cd2f2e8832c304eb811284e9c52167fd41f296d Mon Sep 17 00:00:00 2001 From: Oliver Klein Date: Thu, 24 Nov 2022 11:33:11 -0800 Subject: [PATCH 06/26] fix:(label) fix table not scaling to label width --- pyinstaller/electron/styles.css | 5 +---- src/cryptoadvance/specter/static/styles.css | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/pyinstaller/electron/styles.css b/pyinstaller/electron/styles.css index 31d89891c2..0831439def 100644 --- a/pyinstaller/electron/styles.css +++ b/pyinstaller/electron/styles.css @@ -665,9 +665,6 @@ tbody tr:hover{ .xpub{ max-width: 300px; } -.tx{ - max-width: 200px; -} .scroll{ padding: 0 10px; } @@ -1118,4 +1115,4 @@ input:checked + .slider:before { -webkit-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); text-align: center; -} \ No newline at end of file +} diff --git a/src/cryptoadvance/specter/static/styles.css b/src/cryptoadvance/specter/static/styles.css index 3bd4d90f36..44371ec175 100644 --- a/src/cryptoadvance/specter/static/styles.css +++ b/src/cryptoadvance/specter/static/styles.css @@ -752,9 +752,6 @@ th{ .xpub{ max-width: 300px; } -.tx{ - max-width: 200px; -} /* Scroll functionality along x axis (mainly used for xpub keys) From e689e8cdcf26b254c66357bb8e1b8f153297c9a6 Mon Sep 17 00:00:00 2001 From: moneymanolis Date: Thu, 1 Dec 2022 13:21:15 +0100 Subject: [PATCH 07/26] add / change titles --- .../specter/templates/includes/address-label.html | 7 +++---- .../specter/templates/includes/address-row.html | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/cryptoadvance/specter/templates/includes/address-label.html b/src/cryptoadvance/specter/templates/includes/address-label.html index 556a477df5..2190fbe6a2 100644 --- a/src/cryptoadvance/specter/templates/includes/address-label.html +++ b/src/cryptoadvance/specter/templates/includes/address-label.html @@ -82,18 +82,18 @@ value="{{ csrf_token() }}" /> - + {{ _("Fetching address label...") }} - -
+
+ +
+ -