taler-www

Main taler.net website
Log | Files | Refs | Submodules | README | LICENSE

commit 8f6f8e71857b7ff7f0a79a74332dffd8a21d119d
parent 687e8759e3e0181ddeb40b2b0162e2c846142a46
Author: Florian Dold <dold@taler.net>
Date:   Mon,  7 Sep 2026 15:40:13 +0200

wallet page: support DD 103 action continuation

Show installation guidance and action-specific continuation controls when
the fragment contains a DD 103 wallet action. Resume through the HTTPS
wallet link and offer a smaller direct taler:// link, preserving encoded
payloads in both links.

Support all three fragment forms, update the controls on fragment changes,
and provide responsive layout and text direction for translated prompts.

Diffstat:
Mstatic/styles.css | 36+++++++++++++++++++++++++++++++++++-
Mtemplate/wallet.html.j2 | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)

diff --git a/static/styles.css b/static/styles.css @@ -88,6 +88,7 @@ ul nav { } .wallet-section-heading h2, +.wallet-action-notice h2, .wallet-demo h2, .wallet-resources h2 { font-size: clamp(1.6rem, 3vw, 2rem); @@ -181,7 +182,8 @@ ul nav { color: var(--wallet-blue-dark); } -#body_content .wallet-page a.wallet-button:focus-visible { +#body_content .wallet-page a.wallet-button:focus-visible, +.wallet-action-direct:focus-visible { outline: 3px solid #f5a623; outline-offset: 3px; } @@ -218,6 +220,7 @@ ul nav { padding: 0.85rem 1rem; } +.wallet-action-notice, .wallet-demo { align-items: center; background: var(--wallet-blue-light); @@ -230,14 +233,39 @@ ul nav { padding: 1.75rem 2rem; } +.wallet-action-notice { + margin-top: 2rem; +} + +.wallet-action-notice[hidden] { + display: none; +} + +.wallet-action-notice p, .wallet-demo p { margin-bottom: 0; } +.wallet-action-notice .wallet-button, .wallet-demo .wallet-button { flex: 0 0 auto; } +.wallet-action-options { + display: flex; + flex: 0 0 auto; + flex-direction: column; + gap: 0.25rem; + max-width: 100%; + text-align: center; +} + +.wallet-action-direct { + font-size: 0.9rem; + min-height: 44px; + padding: 0.5rem; +} + .wallet-resources { margin: 3.5rem 0 1rem; } @@ -283,6 +311,7 @@ ul nav { flex-direction: column; } + .wallet-action-notice, .wallet-demo { align-items: flex-start; flex-direction: column; @@ -291,6 +320,11 @@ ul nav { padding: 1.5rem; } + .wallet-action-notice { + margin-top: 2rem; + } + + .wallet-action-options, .wallet-demo .wallet-button { width: 100%; } diff --git a/template/wallet.html.j2 b/template/wallet.html.j2 @@ -18,6 +18,22 @@ </header> <div class="container wallet-content"> + <section id="wallet-action-notice" class="wallet-action-notice" + aria-labelledby="wallet-action-heading" dir="auto" hidden> + <div> + <h2 id="wallet-action-heading">{% trans %}Continue in your Taler wallet{% endtrans %}</h2> + <p>{% trans %}You opened a Taler wallet action link, but your wallet may not have opened. If you don’t have a wallet yet, install one below, then return here to continue.{% endtrans %}</p> + </div> + <div class="wallet-action-options"> + <a id="wallet-action-link" class="wallet-button wallet-button-primary"> + {% trans %}Continue in your wallet{% endtrans %} + </a> + <a id="wallet-action-direct-link" class="wallet-action-direct"> + {% trans %}Open <bdi>taler://</bdi> link directly{% endtrans %} + </a> + </div> + </section> + <section class="wallet-section" aria-labelledby="mobile-wallets-heading"> <div class="wallet-section-heading"> <h2 id="mobile-wallets-heading">{% trans %}Mobile wallets{% endtrans %}</h2> @@ -155,4 +171,72 @@ </section> </div> </main> +<script> + /* + @licstart The following is the entire license notice for the + JavaScript code in this page. + + Copyright (C) 2026 Taler Systems SA + + The JavaScript code in this page is free software: you can + redistribute it and/or modify it under the terms of the GNU + General Public License (GNU GPL) as published by the Free Software + Foundation, either version 3 of the License, or (at your option) + any later version. The code is distributed WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. + + As additional permission under GNU GPL version 3 section 7, you + may distribute non-source (e.g., minimized or compacted) forms of + that code without the copy of the GNU GPL normally required by + section 4, provided you include this license notice and a URL + through which recipients can access the Corresponding Source. + + @licend The above is the entire license notice + for the JavaScript code in this page. + */ + (() => { + const notice = document.getElementById("wallet-action-notice"); + const link = document.getElementById("wallet-action-link"); + const directLink = document.getElementById("wallet-action-direct-link"); + const defaultLabel = {{ _("Continue in your wallet") | tojson }}; + const labels = new Map([ + ["pay", {{ _("Continue payment") | tojson }}], + ["pay-pull", {{ _("Continue payment") | tojson }}], + ["pay-template", {{ _("Continue payment") | tojson }}], + ["withdraw", {{ _("Continue withdrawal") | tojson }}], + ["withdraw-exchange", {{ _("Continue withdrawal") | tojson }}], + ["refund", {{ _("Continue refund") | tojson }}], + ["pay-push", {{ _("Receive money") | tojson }}], + ["restore", {{ _("Restore your wallet") | tojson }}], + ]); + + function updateAction() { + notice.hidden = true; + link.removeAttribute("href"); + directLink.removeAttribute("href"); + link.textContent = defaultLabel; + + const fragment = window.location.hash.slice(1); + if (/[\s\u0000-\u001f\u007f-\u009f]/.test(fragment)) { + return; + } + + // DD 103 permits #taler://action/rest, #/action/rest and #action/rest. + // Keep the payload encoded and let the wallet validate its contents. + const match = /^(?:taler:\/\/|\/)?([a-z-]+)\/(.+)$/i.exec(fragment); + if (!match) { + return; + } + + link.href = "https://wallet.taler.net/#" + fragment; + directLink.href = "taler://" + match[1] + "/" + match[2]; + link.textContent = labels.get(match[1].toLowerCase()) || defaultLabel; + notice.hidden = false; + } + + updateAction(); + window.addEventListener("hashchange", updateAction); + })(); +</script> {% endblock body_content %}