aboutsummaryrefslogtreecommitdiff
path: root/pages
diff options
context:
space:
mode:
Diffstat (limited to 'pages')
-rw-r--r--pages/confirm-contract.html75
-rw-r--r--pages/confirm-contract.tsx134
-rw-r--r--pages/confirm-create-reserve.html76
-rw-r--r--pages/confirm-create-reserve.tsx390
-rw-r--r--pages/debug.html13
-rw-r--r--pages/help/empty-wallet.html30
-rw-r--r--pages/show-db.html15
-rw-r--r--pages/show-db.ts57
8 files changed, 790 insertions, 0 deletions
diff --git a/pages/confirm-contract.html b/pages/confirm-contract.html
new file mode 100644
index 000000000..e7200910a
--- /dev/null
+++ b/pages/confirm-contract.html
@@ -0,0 +1,75 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Taler Wallet: Confirm Reserve Creation</title>
+
+ <link rel="stylesheet" type="text/css" href="../style/lang.css">
+ <link rel="stylesheet" type="text/css" href="../style/wallet.css">
+
+ <link rel="icon" href="../img/icon.png">
+
+ <script src="../lib/vendor/URI.js"></script>
+ <script src="../lib/vendor/mithril.js"></script>
+ <script src="../lib/vendor/lodash.core.min.js"></script>
+ <script src="../lib/vendor/system-csp-production.src.js"></script>
+ <script src="../lib/vendor/jed.js"></script>
+ <script src="../lib/i18n.js"></script>
+ <script src="../i18n/strings.js"></script>
+ <script src="../lib/module-trampoline.js"></script>
+
+ <style>
+ button.accept {
+ background-color: #5757D2;
+ border: 1px solid black;
+ border-radius: 5px;
+ margin: 1em 0;
+ padding: 0.5em;
+ font-weight: bold;
+ color: white;
+ }
+ button.linky {
+ background:none!important;
+ border:none;
+ padding:0!important;
+
+ font-family:arial,sans-serif;
+ color:#069;
+ text-decoration:underline;
+ cursor:pointer;
+ }
+
+ input.url {
+ width: 25em;
+ }
+
+
+ button.accept:disabled {
+ background-color: #dedbe8;
+ border: 1px solid white;
+ border-radius: 5px;
+ margin: 1em 0;
+ padding: 0.5em;
+ font-weight: bold;
+ color: #2C2C2C;
+ }
+
+ .errorbox {
+ border: 1px solid;
+ display: inline-block;
+ margin: 1em;
+ padding: 1em;
+ font-weight: bold;
+ background: #FF8A8A;
+ }
+ </style>
+</head>
+
+<body>
+ <section id="main">
+ <h1>GNU Taler Wallet</h1>
+ <article id="contract" class="fade"></article>
+ </section>
+</body>
+
+</html>
diff --git a/pages/confirm-contract.tsx b/pages/confirm-contract.tsx
new file mode 100644
index 000000000..f162dca85
--- /dev/null
+++ b/pages/confirm-contract.tsx
@@ -0,0 +1,134 @@
+/*
+ This file is part of TALER
+ (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+ * Page shown to the user to confirm entering
+ * a contract.
+ *
+ * @author Florian Dold
+ */
+
+
+/// <reference path="../lib/decl/handlebars/handlebars.d.ts" />
+import MithrilComponent = _mithril.MithrilComponent;
+import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
+import m from "mithril";
+import {Contract, AmountJson} from "../lib/wallet/types";
+import {renderContract, prettyAmount} from "../lib/wallet/renderHtml";
+"use strict";
+
+const Details = {
+ controller() {
+ return {collapsed: m.prop(true)};
+ },
+ view(ctrl: any, contract: Contract) {
+ if (ctrl.collapsed()) {
+ return m("div", [
+ m("button.linky", {
+ onclick: () => {
+ ctrl.collapsed(false);
+ }
+ }, "show more details")
+ ]);
+ } else {
+ return m("div", [
+ m("button.linky", {
+ onclick: () => {
+ ctrl.collapsed(true);
+ }
+ }, "show less details"),
+ m("div", [
+ "Accepted exchanges:",
+ m("ul",
+ contract.exchanges.map(e => m("li", `${e.url}: ${e.master_pub}`)))
+ ])
+ ]);
+ }
+ }
+};
+
+export function main() {
+ let url = URI(document.location.href);
+ let query: any = URI.parseQuery(url.query());
+ let offer = JSON.parse(query.offer);
+ console.dir(offer);
+ let contract = offer.contract;
+ let error: string|null = null;
+ let payDisabled = true;
+
+ var Contract = {
+ view(ctrl: any) {
+ return [
+ renderContract(contract),
+ m("button.accept",
+ {onclick: doPayment, disabled: payDisabled},
+ i18n`Confirm Payment`),
+ (error ? m("p.errorbox", error) : []),
+ m(Details, contract)
+ ];
+ }
+ };
+
+ m.mount(document.getElementById("contract")!, Contract);
+
+ function checkPayment() {
+ chrome.runtime.sendMessage({type: 'check-pay', detail: {offer}}, (resp) => {
+ if (resp.error) {
+ console.log("check-pay error", JSON.stringify(resp));
+ switch (resp.error) {
+ case "coins-insufficient":
+ error = i18n`You have insufficient funds of the requested currency in your wallet.`;
+ break;
+ default:
+ error = `Error: ${resp.error}`;
+ break;
+ }
+ payDisabled = true;
+ } else {
+ payDisabled = false;
+ error = null;
+ }
+ m.redraw();
+ window.setTimeout(checkPayment, 300);
+ });
+ }
+
+ checkPayment();
+
+
+ function doPayment() {
+ let d = {offer};
+ chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => {
+ if (resp.error) {
+ console.log("confirm-pay error", JSON.stringify(resp));
+ switch (resp.error) {
+ case "coins-insufficient":
+ error = "You do not have enough coins of the requested currency.";
+ break;
+ default:
+ error = `Error: ${resp.error}`;
+ break;
+ }
+ m.redraw();
+ return;
+ }
+ let c = d.offer.contract;
+ console.log("contract", c);
+ document.location.href = substituteFulfillmentUrl(c.fulfillment_url,
+ offer);
+ });
+ }
+}
diff --git a/pages/confirm-create-reserve.html b/pages/confirm-create-reserve.html
new file mode 100644
index 000000000..b8a825bd1
--- /dev/null
+++ b/pages/confirm-create-reserve.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <title>Taler Wallet: Select Taler Provider</title>
+
+ <link rel="icon" href="../img/icon.png">
+
+ <script src="../lib/vendor/URI.js"></script>
+ <script src="../lib/vendor/mithril.js"></script>
+ <script src="../lib/vendor/system-csp-production.src.js"></script>
+ <script src="../lib/vendor/jed.js"></script>
+ <script src="../lib/i18n.js"></script>
+ <script src="../i18n/strings.js"></script>
+ <script src="../lib/module-trampoline.js"></script>
+
+ <style>
+ #main {
+ border: solid 1px black;
+ border-radius: 10px;
+ margin: auto;
+ max-width: 50%;
+ padding: 2em;
+ }
+
+ button.accept {
+ background-color: #5757D2;
+ border: 1px solid black;
+ border-radius: 5px;
+ margin: 1em 0;
+ padding: 0.5em;
+ font-weight: bold;
+ color: white;
+ }
+ button.linky {
+ background:none!important;
+ border:none;
+ padding:0!important;
+
+ font-family:arial,sans-serif;
+ color:#069;
+ text-decoration:underline;
+ cursor:pointer;
+ }
+
+ input.url {
+ width: 25em;
+ }
+
+ table {
+ border-collapse: collapse;
+ }
+
+ td {
+ border-left: 1px solid black;
+ border-right: 1px solid black;
+ text-align: center;
+ padding: 0.3em;
+ }
+
+ span.spacer {
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ }
+
+ </style>
+</head>
+
+<body>
+ <section id="main">
+ <h1>GNU Taler Wallet</h1>
+ <div class="fade" id="exchange-selection"></div>
+ </section>
+</body>
+
+</html>
diff --git a/pages/confirm-create-reserve.tsx b/pages/confirm-create-reserve.tsx
new file mode 100644
index 000000000..8e8067052
--- /dev/null
+++ b/pages/confirm-create-reserve.tsx
@@ -0,0 +1,390 @@
+/*
+ This file is part of TALER
+ (C) 2015-2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+
+/**
+ * Page shown to the user to confirm creation
+ * of a reserve, usually requested by the bank.
+ *
+ * @author Florian Dold
+ */
+
+/// <reference path="../lib/decl/mithril.d.ts" />
+
+import {amountToPretty, canonicalizeBaseUrl} from "../lib/wallet/helpers";
+import {AmountJson, CreateReserveResponse} from "../lib/wallet/types";
+import m from "mithril";
+import {ReserveCreationInfo, Amounts} from "../lib/wallet/types";
+import MithrilComponent = _mithril.MithrilComponent;
+import {Denomination} from "../lib/wallet/types";
+import {getReserveCreationInfo} from "../lib/wallet/wxApi";
+
+"use strict";
+
+/**
+ * Execute something after a delay, with the possibility
+ * to reset the delay.
+ */
+class DelayTimer {
+ ms: number;
+ f: () => void;
+ timerId: number|undefined = undefined;
+
+ constructor(ms: number, f: () => void) {
+ this.f = f;
+ this.ms = ms;
+ }
+
+ bump() {
+ this.stop();
+ const handler = () => {
+ this.f();
+ };
+ this.timerId = window.setTimeout(handler, this.ms);
+ }
+
+ stop() {
+ if (this.timerId != undefined) {
+ window.clearTimeout(this.timerId);
+ }
+ }
+}
+
+
+class Controller {
+ url = m.prop<string>();
+ statusString: string | null = null;
+ isValidExchange = false;
+ reserveCreationInfo?: ReserveCreationInfo;
+ private timer: DelayTimer;
+ amount: AmountJson;
+ callbackUrl: string;
+ wtTypes: string[];
+ detailCollapsed = m.prop<boolean>(true);
+ suggestedExchangeUrl: string;
+ complexViewRequested = false;
+ urlOkay = false;
+
+ constructor(suggestedExchangeUrl: string,
+ amount: AmountJson,
+ callbackUrl: string,
+ wt_types: string[]) {
+ console.log("creating main controller");
+ this.suggestedExchangeUrl = suggestedExchangeUrl;
+ this.amount = amount;
+ this.callbackUrl = callbackUrl;
+ this.wtTypes = wt_types;
+ this.timer = new DelayTimer(800, () => this.update());
+ this.url(suggestedExchangeUrl);
+ this.update();
+ }
+
+ private update() {
+ this.timer.stop();
+ const doUpdate = () => {
+ this.reserveCreationInfo = undefined;
+ if (!this.url()) {
+ this.statusString = i18n`Error: URL is empty`;
+ m.redraw(true);
+ return;
+ }
+ this.statusString = null;
+ let parsedUrl = URI(this.url());
+ if (parsedUrl.is("relative")) {
+ this.statusString = i18n`Error: URL may not be relative`;
+ m.redraw(true);
+ return;
+ }
+
+ m.redraw(true);
+
+ console.log("doing get exchange info");
+
+ getReserveCreationInfo(this.url(), this.amount)
+ .then((r: ReserveCreationInfo) => {
+ console.log("get exchange info resolved");
+ this.isValidExchange = true;
+ this.reserveCreationInfo = r;
+ console.dir(r);
+ m.endComputation();
+ })
+ .catch((e) => {
+ console.log("get exchange info rejected");
+ if (e.hasOwnProperty("httpStatus")) {
+ this.statusString = `Error: request failed with status ${e.httpStatus}`;
+ } else if (e.hasOwnProperty("errorResponse")) {
+ let resp = e.errorResponse;
+ this.statusString = `Error: ${resp.error} (${resp.hint})`;
+ }
+ m.endComputation();
+ });
+ };
+
+ doUpdate();
+
+ console.log("got update", this.url());
+ }
+
+ reset() {
+ this.isValidExchange = false;
+ this.statusString = null;
+ this.reserveCreationInfo = undefined;
+ }
+
+ confirmReserve(rci: ReserveCreationInfo,
+ exchange: string,
+ amount: AmountJson,
+ callback_url: string) {
+ const d = {exchange, amount};
+ const cb = (rawResp: any) => {
+ if (!rawResp) {
+ throw Error("empty response");
+ }
+ // FIXME: filter out types that bank/exchange don't have in common
+ let wire_details = rci.wireInfo;
+ if (!rawResp.error) {
+ const resp = CreateReserveResponse.checked(rawResp);
+ let q: {[name: string]: string|number} = {
+ wire_details: JSON.stringify(wire_details),
+ exchange: resp.exchange,
+ reserve_pub: resp.reservePub,
+ amount_value: amount.value,
+ amount_fraction: amount.fraction,
+ amount_currency: amount.currency,
+ };
+ let url = URI(callback_url).addQuery(q);
+ if (!url.is("absolute")) {
+ throw Error("callback url is not absolute");
+ }
+ console.log("going to", url.href());
+ document.location.href = url.href();
+ } else {
+ this.reset();
+ this.statusString = (
+ `Oops, something went wrong.` +
+ `The wallet responded with error status (${rawResp.error}).`);
+ }
+ };
+ chrome.runtime.sendMessage({type: 'create-reserve', detail: d}, cb);
+ }
+
+ onUrlChanged(url: string) {
+ this.reset();
+ this.url(url);
+ this.timer.bump();
+ }
+}
+
+function view(ctrl: Controller): any {
+ function* f(): IterableIterator<any> {
+ yield m("p",
+ i18n.parts`You are about to withdraw ${m("strong", amountToPretty(
+ ctrl.amount))} from your bank account into your wallet.`);
+
+ if (ctrl.complexViewRequested || !ctrl.suggestedExchangeUrl) {
+ yield viewComplex(ctrl);
+ return;
+ }
+ yield viewSimple(ctrl);
+ }
+ return Array.from(f());
+}
+
+function viewSimple(ctrl: Controller) {
+ function *f() {
+ if (ctrl.statusString) {
+ yield m("p", "Error: ", ctrl.statusString);
+ yield m("button.linky", {
+ onclick: () => {
+ ctrl.complexViewRequested = true;
+ }
+ }, "advanced options");
+ }
+ else if (ctrl.reserveCreationInfo != undefined) {
+ let totalCost = Amounts.add(ctrl.reserveCreationInfo.overhead,
+ ctrl.reserveCreationInfo.withdrawFee).amount;
+ yield m("p", `Withdraw fees: ${amountToPretty(totalCost)}`);
+
+ yield m("button.accept", {
+ onclick: () => ctrl.confirmReserve(ctrl.reserveCreationInfo!,
+ ctrl.url(),
+ ctrl.amount,
+ ctrl.callbackUrl),
+ disabled: !ctrl.isValidExchange
+ },
+ "Accept fees and withdraw");
+ yield m("span.spacer");
+ yield m("button.linky", {
+ onclick: () => {
+ ctrl.complexViewRequested = true;
+ }
+ }, "advanced options");
+ } else {
+ yield m("p", "Please wait ...");
+ }
+ }
+
+ return Array.from(f());
+}
+
+
+function viewComplex(ctrl: Controller) {
+ function *f() {
+ if (ctrl.reserveCreationInfo) {
+ let totalCost = Amounts.add(ctrl.reserveCreationInfo.overhead,
+ ctrl.reserveCreationInfo.withdrawFee).amount;
+ yield m("p", `Withdraw fees: ${amountToPretty(totalCost)}`);
+ }
+
+ yield m("button.accept", {
+ onclick: () => ctrl.confirmReserve(ctrl.reserveCreationInfo!,
+ ctrl.url(),
+ ctrl.amount,
+ ctrl.callbackUrl),
+ disabled: !ctrl.isValidExchange
+ },
+ "Accept fees and withdraw");
+ yield m("span.spacer");
+ yield m("button.linky", {
+ onclick: () => {
+ ctrl.complexViewRequested = false;
+ }
+ }, "back to simple view");
+
+ yield m("br");
+
+
+ yield m("input", {
+ className: "url",
+ type: "text",
+ spellcheck: false,
+ value: ctrl.url(),
+ oninput: m.withAttr("value", ctrl.onUrlChanged.bind(ctrl)),
+ });
+
+ yield m("br");
+
+ if (ctrl.statusString) {
+ yield m("p", ctrl.statusString);
+ } else if (!ctrl.reserveCreationInfo) {
+ yield m("p", "Checking URL, please wait ...");
+ }
+
+ if (ctrl.reserveCreationInfo) {
+ if (ctrl.detailCollapsed()) {
+ yield m("button.linky", {
+ onclick: () => {
+ ctrl.detailCollapsed(false);
+ }
+ }, "show more details");
+ } else {
+ yield m("button.linky", {
+ onclick: () => {
+ ctrl.detailCollapsed(true);
+ }
+ }, "hide details");
+ yield m("div", {}, renderReserveCreationDetails(ctrl.reserveCreationInfo))
+ }
+ }
+ }
+ return Array.from(f());
+}
+
+
+function renderReserveCreationDetails(rci: ReserveCreationInfo) {
+ let denoms = rci.selectedDenoms;
+
+ let countByPub: {[s: string]: number} = {};
+ let uniq: Denomination[] = [];
+
+ denoms.forEach((x: Denomination) => {
+ let c = countByPub[x.denom_pub] || 0;
+ if (c == 0) {
+ uniq.push(x);
+ }
+ c += 1;
+ countByPub[x.denom_pub] = c;
+ });
+
+ function row(denom: Denomination) {
+ return m("tr", [
+ m("td", countByPub[denom.denom_pub] + "x"),
+ m("td", amountToPretty(denom.value)),
+ m("td", amountToPretty(denom.fee_withdraw)),
+ m("td", amountToPretty(denom.fee_refresh)),
+ m("td", amountToPretty(denom.fee_deposit)),
+ ]);
+ }
+
+ let withdrawFeeStr = amountToPretty(rci.withdrawFee);
+ let overheadStr = amountToPretty(rci.overhead);
+ return [
+ m("p", `Withdrawal fees: ${withdrawFeeStr}`),
+ m("p", `Rounding loss: ${overheadStr}`),
+ m("table", [
+ m("tr", [
+ m("th", "Count"),
+ m("th", "Value"),
+ m("th", "Withdraw Fee"),
+ m("th", "Refresh Fee"),
+ m("th", "Deposit Fee"),
+ ]),
+ uniq.map(row)
+ ])
+ ];
+}
+
+
+function getSuggestedExchange(currency: string): Promise<string> {
+ // TODO: make this request go to the wallet backend
+ // Right now, this is a stub.
+ const defaultExchange: {[s: string]: string} = {
+ "KUDOS": "https://exchange.demo.taler.net",
+ "PUDOS": "https://exchange.test.taler.net",
+ };
+
+ let exchange = defaultExchange[currency];
+
+ if (!exchange) {
+ exchange = ""
+ }
+
+ return Promise.resolve(exchange);
+}
+
+
+
+export function main() {
+ const url = URI(document.location.href);
+ const query: any = URI.parseQuery(url.query());
+ const amount = AmountJson.checked(JSON.parse(query.amount));
+ const callback_url = query.callback_url;
+ const bank_url = query.bank_url;
+ const wt_types = JSON.parse(query.wt_types);
+
+ getSuggestedExchange(amount.currency)
+ .then((suggestedExchangeUrl) => {
+ const controller = function () { return new Controller(suggestedExchangeUrl, amount, callback_url, wt_types); };
+ const ExchangeSelection = {controller, view};
+ m.mount(document.getElementById("exchange-selection")!, ExchangeSelection);
+ })
+ .catch((e) => {
+ // TODO: provide more context information, maybe factor it out into a
+ // TODO:generic error reporting function or component.
+ document.body.innerText = `Fatal error: "${e.message}".`;
+ console.error(`got error "${e.message}"`, e);
+ });
+} \ No newline at end of file
diff --git a/pages/debug.html b/pages/debug.html
new file mode 100644
index 000000000..221c7380c
--- /dev/null
+++ b/pages/debug.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Taler Wallet Debugging</title>
+ <link rel="icon" href="../img/icon.png">
+ </head>
+ <body>
+ <h1>Debug Pages</h1>
+ <a href="show-db.html">Show DB</a> <br>
+ <a href="../popup/balance-overview.html">Show balance</a>
+
+ </body>
+</html>
diff --git a/pages/help/empty-wallet.html b/pages/help/empty-wallet.html
new file mode 100644
index 000000000..952bd92b7
--- /dev/null
+++ b/pages/help/empty-wallet.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>GNU Taler Help - Empty Wallet</title>
+ <link rel="icon" href="../../img/icon.png">
+ <meta name="description" content="">
+ <link rel="stylesheet" type="text/css" href="../../style/wallet.css">
+ </head>
+ <body>
+ <div class="container" id="main">
+ <div class="row">
+ <div class="col-lg-12">
+ <h2 lang="en">Your wallet is empty!</h2>
+ <p lang="en">You have succeeded with installing the Taler wallet. However, before
+ you can buy articles using the Taler wallet, you must withdraw electronic coins.
+ This is typically done by visiting your bank's online banking Web site. There,
+ you instruct your bank to transfer the funds to a Taler exchange operator. In
+ return, your wallet will be allowed to withdraw electronic coins.</p>
+ <p lang="en">At this stage, we are not aware of any regular exchange operators issuing
+ coins in well-known currencies. However, to see how Taler would work, you
+ can visit our "fake" bank at
+ <a href="https://bank.demo.taler.net/">bank.demo.taler.net</a> to
+ withdraw coins in the "KUDOS" currency that we created just for
+ demonstrating the system.</p>
+ </div>
+ </div>
+ </div>
+ </body>
+</html>
diff --git a/pages/show-db.html b/pages/show-db.html
new file mode 100644
index 000000000..024e844ee
--- /dev/null
+++ b/pages/show-db.html
@@ -0,0 +1,15 @@
+
+<!doctype html>
+
+<html>
+ <head>
+ <title>Taler Wallet: Reserve Created</title>
+ <link rel="stylesheet" type="text/css" href="../style/wallet.css">
+ <link rel="icon" href="../img/icon.png">
+ <script src="show-db.js"></script>
+ </head>
+ <body>
+ <h1>DB Dump</h1>
+ <pre id="dump"></pre>
+ </body>
+</html>
diff --git a/pages/show-db.ts b/pages/show-db.ts
new file mode 100644
index 000000000..71e74388b
--- /dev/null
+++ b/pages/show-db.ts
@@ -0,0 +1,57 @@
+/*
+ This file is part of TALER
+ (C) 2015 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+
+/**
+ * Wallet database dump for debugging.
+ *
+ * @author Florian Dold
+ */
+
+function replacer(match: string, pIndent: string, pKey: string, pVal: string,
+ pEnd: string) {
+ var key = '<span class=json-key>';
+ var val = '<span class=json-value>';
+ var str = '<span class=json-string>';
+ var r = pIndent || '';
+ if (pKey) {
+ r = r + key + pKey.replace(/[": ]/g, '') + '</span>: ';
+ }
+ if (pVal) {
+ r = r + (pVal[0] == '"' ? str : val) + pVal + '</span>';
+ }
+ return r + (pEnd || '');
+}
+
+
+function prettyPrint(obj: any) {
+ var jsonLine = /^( *)("[\w]+": )?("[^"]*"|[\w.+-]*)?([,[{])?$/mg;
+ return JSON.stringify(obj, null as any, 3)
+ .replace(/&/g, '&amp;').replace(/\\"/g, '&quot;')
+ .replace(/</g, '&lt;').replace(/>/g, '&gt;')
+ .replace(jsonLine, replacer);
+}
+
+
+document.addEventListener("DOMContentLoaded", () => {
+ chrome.runtime.sendMessage({type: 'dump-db'}, (resp) => {
+ const el = document.getElementById('dump');
+ if (!el) {
+ throw Error();
+ }
+ el.innerHTML = prettyPrint(resp);
+ });
+});