Replace handlebars with mithril, hooks for i18n.
The wallet is now a single page application.
This commit is contained in:
parent
1a0a302ad9
commit
b8627813be
@ -38,5 +38,6 @@ System.import("../lib/wallet/wxmessaging")
|
||||
wxmessaging.wxMain();
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("import failed", e.stack);
|
||||
console.log("wallet failed");
|
||||
console.error(e.stack);
|
||||
});
|
@ -17,6 +17,7 @@
|
||||
// query the availability of Taler.
|
||||
/// <reference path="../lib/decl/chrome/chrome.d.ts" />
|
||||
"use strict";
|
||||
console.log("Taler injected");
|
||||
document.addEventListener("taler-probe", function (e) {
|
||||
var evt = new Event("taler-wallet-present");
|
||||
document.dispatchEvent(evt);
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
console.log("Taler injected");
|
||||
|
||||
document.addEventListener("taler-probe", function(e) {
|
||||
let evt = new Event("taler-wallet-present");
|
||||
document.dispatchEvent(evt);
|
||||
@ -99,4 +101,4 @@ document.addEventListener('taler-execute-payment', function(e: CustomEvent) {
|
||||
document.dispatchEvent(new CustomEvent("taler-payment-result", {detail: detail}));
|
||||
};
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -56,7 +56,7 @@ const paths = {
|
||||
"lib/vendor/*",
|
||||
"lib/emscripten/libwrapper.js"
|
||||
],
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
Handlebars.registerHelper("prettyAmount", function (amount) {
|
||||
let v = amount.value + amount.fraction / 1e6;
|
||||
return `${v.toFixed(2)} ${amount.currency}`;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper("prettyAmountNoCurrency", function (amount) {
|
||||
let v = amount.value + amount.fraction / 1e6;
|
||||
return v.toFixed(2);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('objectStringifier', function (o) {
|
||||
return JSON.stringify(o);
|
||||
});
|
16525
extension/lib/decl/lodash.d.ts
vendored
Normal file
16525
extension/lib/decl/lodash.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,9 +14,25 @@
|
||||
TALER; see the file COPYING. If not, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
declare var i18n: any;
|
||||
|
||||
"use strict";
|
||||
var i18n = <any>function i18n(strings, ...values) {
|
||||
// TODO: actually look up translation
|
||||
return String.raw(strings, ...values);
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (e) => {
|
||||
// Interpolate i8nized values with arbitrary objects and
|
||||
// return array of strings/objects.
|
||||
i18n.parts = function(strings, ...values) {
|
||||
let parts = [];
|
||||
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
parts.push(strings[i]);
|
||||
if (i < values.length) {
|
||||
parts.push(values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return parts;
|
||||
};
|
||||
|
||||
});
|
879
extension/lib/mithril.d.ts
vendored
Normal file
879
extension/lib/mithril.d.ts
vendored
Normal file
@ -0,0 +1,879 @@
|
||||
// Mithril type definitions for Typescript
|
||||
|
||||
/**
|
||||
* This is the module containing all the types/declarations/etc. for Mithril
|
||||
*/
|
||||
declare interface MithrilStatic {
|
||||
/**
|
||||
* Creates a virtual element for use with m.render, m.mount, etc.
|
||||
*
|
||||
* @param selector A simple CSS selector. May include SVG tags. Nested
|
||||
* selectors are not supported.
|
||||
* @param attributes Attributes to add. Any DOM attribute may be used
|
||||
* as an attribute, although innerHTML and the like may be overwritten
|
||||
* silently.
|
||||
* @param children Child elements, components, and text to add.
|
||||
* @return A virtual element.
|
||||
*
|
||||
* @see m.render
|
||||
* @see m.mount
|
||||
* @see m.component
|
||||
*/
|
||||
<T extends MithrilController>(selector: string,
|
||||
attributes: MithrilAttributes,
|
||||
...children: Array<string |
|
||||
MithrilVirtualElement<T> |
|
||||
MithrilComponent<T>>): MithrilVirtualElement<T>;
|
||||
|
||||
/**
|
||||
* Initializes a component for use with m.render, m.mount, etc.
|
||||
*
|
||||
* @param component A component.
|
||||
* @param args Arguments to optionally pass to the component.
|
||||
* @return A component.
|
||||
*
|
||||
* @see m.render
|
||||
* @see m.mount
|
||||
* @see m
|
||||
*/
|
||||
<T extends MithrilController>(component: MithrilComponent<T>,
|
||||
...args: any[]): MithrilComponent<T>;
|
||||
|
||||
/**
|
||||
* Creates a virtual element for use with m.render, m.mount, etc.
|
||||
*
|
||||
* @param selector A simple CSS selector. Nested selectors are not
|
||||
* supported.
|
||||
* @param children Child elements, components, and text to add.
|
||||
* @return A virtual element.
|
||||
*
|
||||
* @see m.render
|
||||
* @see m.mount
|
||||
* @see m.component
|
||||
*/
|
||||
<T extends MithrilController>(selector: string,
|
||||
...children: Array<string |
|
||||
MithrilVirtualElement<T> |
|
||||
MithrilComponent<T>>): MithrilVirtualElement<T>;
|
||||
|
||||
/**
|
||||
* Initializes a component for use with m.render, m.mount, etc.
|
||||
* Shorthand for m.component.
|
||||
*
|
||||
* @param selector A component.
|
||||
* @param args Arguments to optionally pass to the component.
|
||||
* @return A component.
|
||||
*
|
||||
* @see m.render
|
||||
* @see m.mount
|
||||
* @see m.component
|
||||
*/
|
||||
<T extends MithrilController>(component: MithrilComponent<T>,
|
||||
...args: any[]): MithrilComponent<T>;
|
||||
|
||||
/**
|
||||
* Creates a getter-setter function that wraps a Mithril promise. Useful
|
||||
* for uniform data access, m.withAttr, etc.
|
||||
*
|
||||
* @param promise A thennable to initialize the property with. It may
|
||||
* optionally be a Mithril promise.
|
||||
* @return A getter-setter function wrapping the promise.
|
||||
*
|
||||
* @see m.withAttr
|
||||
*/
|
||||
prop<T>(promise: Thennable<T>) : MithrilPromiseProperty<T>;
|
||||
|
||||
/**
|
||||
* Creates a getter-setter function that wraps a simple value. Useful
|
||||
* for uniform data access, m.withAttr, etc.
|
||||
*
|
||||
* @param value A value to initialize the property with
|
||||
* @return A getter-setter function wrapping the value.
|
||||
*
|
||||
* @see m.withAttr
|
||||
*/
|
||||
prop<T>(value: T): MithrilBasicProperty<T>;
|
||||
|
||||
/**
|
||||
* Creates a getter-setter function that wraps a simple value. Useful
|
||||
* for uniform data access, m.withAttr, etc.
|
||||
*
|
||||
* @return A getter-setter function wrapping the value.
|
||||
*
|
||||
* @see m.withAttr
|
||||
*/
|
||||
prop<T>(): MithrilBasicProperty<T>;
|
||||
|
||||
/**
|
||||
* Returns a event handler that can be bound to an element, firing with
|
||||
* the specified property.
|
||||
*
|
||||
* @param property The property to get from the event.
|
||||
* @param callback The handler to use the value from the event.
|
||||
* @return A function suitable for listening to an event.
|
||||
*/
|
||||
withAttr(property: string,
|
||||
callback: (value: any) => void,
|
||||
callbackThis: any): (e: Event) => any;
|
||||
|
||||
/**
|
||||
* @deprecated Use m.mount instead
|
||||
*/
|
||||
module<T extends MithrilController>(rootElement: Node,
|
||||
component: MithrilComponent<T>): T;
|
||||
|
||||
/**
|
||||
* Mounts a component to a base DOM node.
|
||||
*
|
||||
* @param rootElement The base node.
|
||||
* @param component The component to mount.
|
||||
* @return An instance of the top-level component's controller
|
||||
*/
|
||||
mount<T extends MithrilController>(rootElement: Node,
|
||||
component: MithrilComponent<T>): T;
|
||||
|
||||
/**
|
||||
* Initializes a component for use with m.render, m.mount, etc.
|
||||
*
|
||||
* @param selector A component.
|
||||
* @param args Arguments to optionally pass to the component.
|
||||
* @return A component.
|
||||
*
|
||||
* @see m.render
|
||||
* @see m.mount
|
||||
* @see m
|
||||
*/
|
||||
component<T extends MithrilController>(component: MithrilComponent<T>,
|
||||
...args: any[]): MithrilComponent<T>;
|
||||
|
||||
/**
|
||||
* Trust this string of HTML.
|
||||
*
|
||||
* @param html The HTML to trust
|
||||
* @return A String object instance with an added internal flag to mark
|
||||
* it as trusted.
|
||||
*/
|
||||
trust(html: string): MithrilTrustedString;
|
||||
|
||||
/**
|
||||
* Render a virtual DOM tree.
|
||||
*
|
||||
* @param rootElement The base element/node to render the tree from.
|
||||
* @param children One or more child nodes to add to the tree.
|
||||
* @param forceRecreation If true, overwrite the entire tree without
|
||||
* diffing against it.
|
||||
*/
|
||||
render<T extends MithrilController>(rootElement: Element,
|
||||
children: MithrilVirtualElement<T>|MithrilVirtualElement<T>[],
|
||||
forceRecreation?: boolean): void;
|
||||
|
||||
redraw: {
|
||||
/**
|
||||
* Force a redraw the active component. It redraws asynchronously by
|
||||
* default to allow for simultaneous events to run before redrawing,
|
||||
* such as the event combination keypress + input frequently used for
|
||||
* input.
|
||||
*
|
||||
* @param force If true, redraw synchronously.
|
||||
*/
|
||||
(force?: boolean): void;
|
||||
|
||||
strategy: {
|
||||
/**
|
||||
* Gets the current redraw strategy, which returns one of the
|
||||
* following:
|
||||
*
|
||||
* "all" - recreates the DOM tree from scratch
|
||||
* "diff" - recreates the DOM tree from scratch
|
||||
* "none" - leaves the DOM tree intact
|
||||
*
|
||||
* This is useful for event handlers, which may want to cancel
|
||||
* the next redraw if the event doesn't update the UI.
|
||||
*
|
||||
* @return The current strategy
|
||||
*/
|
||||
(): string;
|
||||
|
||||
/**
|
||||
* Sets the current redraw strategy. The parameter must be one of
|
||||
* the following values:
|
||||
*
|
||||
* "all" - recreates the DOM tree from scratch
|
||||
* "diff" - recreates the DOM tree from scratch
|
||||
* "none" - leaves the DOM tree intact
|
||||
*
|
||||
* This is useful for event handlers, which may want to cancel
|
||||
* the next redraw if the event doesn't update the UI.
|
||||
*
|
||||
* @param value The value to set
|
||||
* @return The new strategy
|
||||
*/
|
||||
(value: string): string;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* Implementation detail - it's a MithrilBasicProperty instance
|
||||
*/
|
||||
toJSON(): string;
|
||||
}
|
||||
}
|
||||
|
||||
route: {
|
||||
/**
|
||||
* Enable routing, mounting a controller based on the route. It
|
||||
* automatically mounts the components for you, starting with the one
|
||||
* specified by the default route.
|
||||
*
|
||||
* @param rootElement The element to mount the active controller to.
|
||||
* @param defaultRoute The route to start with.
|
||||
* @param routes A key-value mapping of pathname to controller.
|
||||
*/
|
||||
<T extends MithrilController>(rootElement: Element,
|
||||
defaultRoute: string,
|
||||
routes: MithrilRoutes): void;
|
||||
|
||||
/**
|
||||
* This allows m.route to be used as the `config` attribute for a
|
||||
* virtual element, particularly useful for cases like this:
|
||||
*
|
||||
* ```ts
|
||||
* // Note that the '#' is not required in `href`, thanks to the
|
||||
* `config` setting.
|
||||
* m("a[href='/dashboard/alicesmith']", {config: m.route});
|
||||
* ```
|
||||
*/
|
||||
<T extends MithrilController>(element: Element,
|
||||
isInitialized: boolean,
|
||||
context?: MithrilContext,
|
||||
vdom?: MithrilVirtualElement<T>): void;
|
||||
|
||||
/**
|
||||
* Programmatically redirect to another route.
|
||||
*
|
||||
* @param path The route to go to.
|
||||
* @param params Parameters to pass as a query string.
|
||||
* @param shouldReplaceHistory Whether to replace the current history
|
||||
* instead of adding a new one.
|
||||
*/
|
||||
(path: string, params?: any, shouldReplaceHistory?: boolean): void;
|
||||
|
||||
/**
|
||||
* Gets the current route.
|
||||
*
|
||||
* @return The current route.
|
||||
*/
|
||||
(): string;
|
||||
|
||||
/**
|
||||
* Gets a route parameter.
|
||||
*
|
||||
* @param key The key to get.
|
||||
* @return The value associated with the parameter key.
|
||||
*/
|
||||
param(key: string): string;
|
||||
|
||||
/**
|
||||
* The current routing mode. This may be changed before calling
|
||||
* m.route to change the part of the URL used to perform the routing.
|
||||
*
|
||||
* The value can be set to one of the following, defaulting to
|
||||
* "hash":
|
||||
*
|
||||
* "search" - Uses the query string. This allows for named anchors to
|
||||
* work on the page, but changes cause IE8 and lower to refresh the
|
||||
* page.
|
||||
*
|
||||
* "hash" - Uses the hash. This is the only routing mode that does
|
||||
* not cause page refreshes on any browser, but it does not support
|
||||
* named anchors.
|
||||
*
|
||||
* "pathname" - Uses the URL pathname. This requires server-side
|
||||
* setup to support bookmarking and page refreshes. It always causes
|
||||
* page refreshes on IE8 and lower. Note that this requires that the
|
||||
* application to be run from the root of the URL.
|
||||
*/
|
||||
mode: string;
|
||||
|
||||
/**
|
||||
* Serialize an object into a query string.
|
||||
*
|
||||
* @param data The data to serialize.
|
||||
* @return The serialized string.
|
||||
*/
|
||||
buildQueryString(data: Object): String
|
||||
|
||||
/**
|
||||
* Parse a query string into an object.
|
||||
*
|
||||
* @param data The data to parse.
|
||||
* @return The parsed object data.
|
||||
*/
|
||||
parseQueryString(data: String): Object
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a request to a server to server. Note that the `url` option is
|
||||
* required.
|
||||
*
|
||||
* @param options The options to use
|
||||
* @return A promise to the returned data for "GET" requests, or a void
|
||||
* promise for any other request type.
|
||||
*
|
||||
* @see MithrilXHROptions for the available options.
|
||||
*/
|
||||
request<T>(options: MithrilXHROptions<T>): MithrilPromise<T>;
|
||||
|
||||
deferred: {
|
||||
/**
|
||||
* Create a Mithril deferred object. It behaves synchronously if
|
||||
* possible, an intentional deviation from Promises/A+. Note that
|
||||
* deferreds are completely separate from the redrawing system, and
|
||||
* never trigger a redraw on their own.
|
||||
*
|
||||
* @return A new Mithril deferred instance.
|
||||
*
|
||||
* @see m.deferred.onerror for the error callback called for Error
|
||||
* subclasses
|
||||
*/
|
||||
<T>(): MithrilDeferred<T>;
|
||||
|
||||
/**
|
||||
* A callback for all uncaught native Error subclasses in deferreds.
|
||||
* This defaults to synchronously rethrowing all errors, a deviation
|
||||
* from Promises/A+, but the behavior is configurable. To restore
|
||||
* Promises/A+-compatible behavior. simply set this to a no-op.
|
||||
*/
|
||||
onerror(e: Error): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of promises or thennables and returns a Mithril promise
|
||||
* that resolves once all in the list are resolved, or rejects if any of
|
||||
* them reject.
|
||||
*
|
||||
* @param promises A list of promises to try to resolve.
|
||||
* @return A promise that resolves to all the promises if all resolve, or
|
||||
* rejects with the error contained in the first rejection.
|
||||
*/
|
||||
sync<T>(promises: Thennable<T>[]): MithrilPromise<T[]>;
|
||||
|
||||
/**
|
||||
* Use this and endComputation if your views aren't redrawing after
|
||||
* calls to third-party libraries. For integrating asynchronous code,
|
||||
* this should be called before any asynchronous work is done. For
|
||||
* synchronous code, this should be called at the beginning of the
|
||||
* problematic segment. Note that these calls must be balanced, much like
|
||||
* braces and parentheses. This is mostly used internally. Prefer
|
||||
* m.redraw where possible, especially when making repeated calls.
|
||||
*
|
||||
* @see endComputation
|
||||
* @see m.render
|
||||
*/
|
||||
startComputation(): void;
|
||||
|
||||
/**
|
||||
* Use startComputation and this if your views aren't redrawing after
|
||||
* calls to third-party libraries. For integrating asynchronous code,
|
||||
* this should be called after all asynchronous work completes. For
|
||||
* synchronous code, this should be called at the end of the problematic
|
||||
* segment. Note that these calls must be balanced, much like braces and
|
||||
* parentheses. This is mostly used internally. Prefer m.redraw where
|
||||
* possible, especially when making repeated calls.
|
||||
*
|
||||
* @see startComputation
|
||||
* @see m.render
|
||||
*/
|
||||
endComputation(): void;
|
||||
|
||||
/**
|
||||
* This overwrites the internal version of window used by Mithril.
|
||||
* It's mostly useful for testing, and is also used internally by
|
||||
* Mithril to test itself. By default Mithril uses `window` for the
|
||||
* dependency.
|
||||
*
|
||||
* @param mockWindow The mock to use for the window.
|
||||
* @return The mock that was passed in.
|
||||
*/
|
||||
deps(mockWindow: Window): Window;
|
||||
}
|
||||
|
||||
interface MithrilTrustedString extends String {
|
||||
/** @private Implementation detail. Don't depend on it. */
|
||||
$trusted: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface for a virtual element. It's best to consider this immutable
|
||||
* for most use cases.
|
||||
*
|
||||
* @see m
|
||||
*/
|
||||
interface MithrilVirtualElement<T extends MithrilController> {
|
||||
/**
|
||||
* A key to optionally associate with this element.
|
||||
*/
|
||||
key?: number;
|
||||
|
||||
/**
|
||||
* The tag name of this element.
|
||||
*/
|
||||
tag?: string;
|
||||
|
||||
/**
|
||||
* The attributes of this element.
|
||||
*/
|
||||
attrs?: MithrilAttributes;
|
||||
|
||||
/**
|
||||
* The children of this element.
|
||||
*/
|
||||
children?: Array<string|MithrilVirtualElement<T>|MithrilComponent<T>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event passed by Mithril to unload event handlers.
|
||||
*/
|
||||
interface MithrilEvent {
|
||||
/**
|
||||
* Prevent the default behavior of scrolling the page and updating the
|
||||
* URL on next route change.
|
||||
*/
|
||||
preventDefault(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A context object for configuration functions.
|
||||
*
|
||||
* @see MithrilElementConfig
|
||||
*/
|
||||
interface MithrilContext {
|
||||
/**
|
||||
* A function to call when the node is unloaded. Useful for cleanup.
|
||||
*/
|
||||
onunload?(): any;
|
||||
|
||||
/**
|
||||
* Set true if the backing DOM node needs to be retained between route
|
||||
* changes if possible. Set false if this node needs to be recreated
|
||||
* every single time, regardless of how "different" it is.
|
||||
*/
|
||||
retain?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a callback function for a virtual element's config
|
||||
* attribute. It's a low-level function useful for extra cleanup after
|
||||
* removal from the tree, storing instances of third-party classes that
|
||||
* need to be associated with the DOM, etc.
|
||||
*
|
||||
* @see MithrilAttributes
|
||||
* @see MithrilContext
|
||||
*/
|
||||
interface MithrilElementConfig {
|
||||
/**
|
||||
* A callback function for a virtual element's config attribute.
|
||||
*
|
||||
* @param element The associated DOM element.
|
||||
* @param isInitialized Whether this is the first call for the virtual
|
||||
* element or not.
|
||||
* @param context The associated context for this element.
|
||||
* @param vdom The associated virtual element.
|
||||
*/
|
||||
<T extends MithrilController>(element: Element,
|
||||
isInitialized: boolean,
|
||||
context: MithrilContext,
|
||||
vdom: MithrilVirtualElement<T>): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents the attributes available for configuring virtual elements,
|
||||
* beyond the applicable DOM attributes.
|
||||
*
|
||||
* @see m
|
||||
*/
|
||||
interface MithrilAttributes {
|
||||
/**
|
||||
* The class name(s) for this virtual element, as a space-separated list.
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* The class name(s) for this virtual element, as a space-separated list.
|
||||
*/
|
||||
class?: string;
|
||||
|
||||
/**
|
||||
* A custom, low-level configuration in case this element needs special
|
||||
* cleanup after removal from the tree.
|
||||
*
|
||||
* @see MithrilElementConfig
|
||||
*/
|
||||
config?: MithrilElementConfig;
|
||||
|
||||
/**
|
||||
* Any other virtual element properties including attributes and
|
||||
* event handlers
|
||||
*/
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* The basis of a Mithril controller instance.
|
||||
*/
|
||||
interface MithrilController {
|
||||
/**
|
||||
* An optional handler to call when the associated virtual element is
|
||||
* destroyed.
|
||||
*
|
||||
* @param evt An associated event.
|
||||
*/
|
||||
onunload?(evt: MithrilEvent): any;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a controller function.
|
||||
*
|
||||
* @see MithrilControllerConstructor
|
||||
*/
|
||||
interface MithrilControllerFunction<T extends MithrilController> {
|
||||
(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a controller constructor.
|
||||
*
|
||||
* @see MithrilControllerFunction
|
||||
*/
|
||||
interface MithrilControllerConstructor<T extends MithrilController> {
|
||||
new(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a view factory.
|
||||
*/
|
||||
interface MithrilView<T extends MithrilController> {
|
||||
/**
|
||||
* Creates a view out of virtual elements.
|
||||
*/
|
||||
(ctrl: T): MithrilVirtualElement<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a Mithril component.
|
||||
*
|
||||
* @see m
|
||||
* @see m.component
|
||||
*/
|
||||
interface MithrilComponent<T extends MithrilController> {
|
||||
/**
|
||||
* The component's controller.
|
||||
*
|
||||
* @see m.component
|
||||
*/
|
||||
controller?: MithrilControllerFunction<T> |
|
||||
MithrilControllerConstructor<T>;
|
||||
|
||||
/**
|
||||
* Creates a view out of virtual elements.
|
||||
*
|
||||
* @see m.component
|
||||
*/
|
||||
view(ctrl: T): MithrilVirtualElement<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the base interface for property getter-setters
|
||||
*
|
||||
* @see m.prop
|
||||
*/
|
||||
interface MithrilProperty<T> {
|
||||
/**
|
||||
* Gets the contained value.
|
||||
*
|
||||
* @return The contained value.
|
||||
*/
|
||||
(): T;
|
||||
|
||||
/**
|
||||
* Sets the contained value.
|
||||
*
|
||||
* @param value The new value to set.
|
||||
* @return The newly set value.
|
||||
*/
|
||||
(value: T): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a non-promise getter-setter functions.
|
||||
*
|
||||
* @see m.prop which returns objects that implement this interface.
|
||||
*/
|
||||
interface MithrilBasicProperty<T> extends MithrilProperty<T> {
|
||||
/**
|
||||
* Makes this serializable to JSON.
|
||||
*/
|
||||
toJSON(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a promise getter-setter function.
|
||||
*
|
||||
* @see m.prop which returns objects that implement this interface.
|
||||
*/
|
||||
interface MithrilPromiseProperty<T> extends MithrilPromise<T>,
|
||||
MithrilProperty<MithrilPromise<T>> {
|
||||
/**
|
||||
* Gets the contained promise.
|
||||
*
|
||||
* @return The contained value.
|
||||
*/
|
||||
(): MithrilPromise<T>;
|
||||
|
||||
/**
|
||||
* Sets the contained promise.
|
||||
*
|
||||
* @param value The new value to set.
|
||||
* @return The newly set value.
|
||||
*/
|
||||
(value: MithrilPromise<T>): MithrilPromise<T>;
|
||||
|
||||
/**
|
||||
* Sets the contained wrapped value.
|
||||
*
|
||||
* @param value The new value to set.
|
||||
* @return The newly set value.
|
||||
*/
|
||||
(value: T): MithrilPromise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a key-value mapping linking routes to components.
|
||||
*/
|
||||
interface MithrilRoutes {
|
||||
/**
|
||||
* The key represents the route. The value represents the corresponding
|
||||
* component.
|
||||
*/
|
||||
[key: string]: MithrilComponent<MithrilController>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a Mithril deferred object.
|
||||
*/
|
||||
interface MithrilDeferred<T> {
|
||||
/**
|
||||
* Resolve this deferred's promise with a value.
|
||||
*
|
||||
* @param value The value to resolve the promise with.
|
||||
*/
|
||||
resolve(value?: T): void;
|
||||
|
||||
/**
|
||||
* Reject this deferred with an error.
|
||||
*
|
||||
* @param value The reason for rejecting the promise.
|
||||
*/
|
||||
reject(reason?: any): void;
|
||||
|
||||
/**
|
||||
* The backing promise.
|
||||
*
|
||||
* @see MithrilPromise
|
||||
*/
|
||||
promise: MithrilPromise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a thennable success callback.
|
||||
*/
|
||||
interface MithrilSuccessCallback<T, U> {
|
||||
(value: T): U | Thennable<U>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a thennable error callback.
|
||||
*/
|
||||
interface MithrilErrorCallback<T> {
|
||||
(value: Error): T | Thennable<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a thennable.
|
||||
*/
|
||||
interface Thennable<T> {
|
||||
then<U>(success: (value: T) => U): Thennable<U>;
|
||||
then<U,V>(success: (value: T) => U,
|
||||
error: (value: Error) => V): Thennable<U>|Thennable<V>;
|
||||
catch?: <U>(error: (value: Error) => U) => Thennable<U>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents a Mithril promise object.
|
||||
*/
|
||||
interface MithrilPromise<T> extends Thennable<T>, MithrilProperty<MithrilPromise<T>> {
|
||||
/**
|
||||
* Chain this promise with a simple success callback, propogating
|
||||
* rejections.
|
||||
*
|
||||
* @param success The callback to call when the promise is resolved.
|
||||
* @return The chained promise.
|
||||
*/
|
||||
then<U>(success: MithrilSuccessCallback<T,U>): MithrilPromise<U>;
|
||||
|
||||
/**
|
||||
* Chain this promise with a success callback and error callback, without
|
||||
* propogating rejections.
|
||||
*
|
||||
* @param success The callback to call when the promise is resolved.
|
||||
* @param error The callback to call when the promise is rejected.
|
||||
* @return The chained promise.
|
||||
*/
|
||||
then<U, V>(success: MithrilSuccessCallback<T, U>,
|
||||
error: MithrilErrorCallback<V>): MithrilPromise<U> | MithrilPromise<V>;
|
||||
|
||||
/**
|
||||
* Chain this promise with a single error callback, without propogating
|
||||
* rejections.
|
||||
*
|
||||
* @param error The callback to call when the promise is rejected.
|
||||
* @return The chained promise.
|
||||
*/
|
||||
catch<U>(error: MithrilErrorCallback<U>): MithrilPromise<T> |
|
||||
MithrilPromise<U>;
|
||||
}
|
||||
|
||||
/**
|
||||
* This represents the available options for configuring m.request.
|
||||
*
|
||||
* @see m.request
|
||||
*/
|
||||
interface MithrilXHROptions<T> {
|
||||
/**
|
||||
* This represents the HTTP method used, one of the following:
|
||||
*
|
||||
* - "GET" (default)
|
||||
* - "POST"
|
||||
* - "PUT"
|
||||
* - "DELETE"
|
||||
* - "HEAD"
|
||||
* - "OPTIONS"
|
||||
*/
|
||||
method?: string;
|
||||
|
||||
/**
|
||||
* The URL to send the request to.
|
||||
*/
|
||||
url: string;
|
||||
|
||||
/**
|
||||
* The username for HTTP authentication.
|
||||
*/
|
||||
user?: string;
|
||||
|
||||
/**
|
||||
* The password for HTTP authentication.
|
||||
*/
|
||||
password?: string;
|
||||
|
||||
/**
|
||||
* The data to be sent. It's automatically serialized in the right format
|
||||
* depending on the method (with exception of HTML5 FormData), and put in
|
||||
* the appropriate section of the request.
|
||||
*/
|
||||
data?: any;
|
||||
|
||||
/**
|
||||
* Whether to run it in the background, i.e. true if it doesn't affect
|
||||
* template rendering.
|
||||
*/
|
||||
background?: boolean;
|
||||
|
||||
/**
|
||||
* Set an initial value while the request is working, to populate the
|
||||
* promise getter-setter.
|
||||
*/
|
||||
initialValue?: T;
|
||||
|
||||
/**
|
||||
* An optional preprocessor function to unwrap a successful response, in
|
||||
* case the response contains metadata wrapping the data.
|
||||
*
|
||||
* @param data The data to unwrap.
|
||||
* @return The unwrapped result.
|
||||
*/
|
||||
unwrapSuccess?(data: any): T;
|
||||
|
||||
/**
|
||||
* An optional preprocessor function to unwrap an unsuccessful response,
|
||||
* in case the response contains metadata wrapping the data.
|
||||
*
|
||||
* @param data The data to unwrap.
|
||||
* @return The unwrapped result.
|
||||
*/
|
||||
unwrapError?(data: any): T;
|
||||
|
||||
/**
|
||||
* An optional function to serialize the data. This defaults to
|
||||
* `JSON.stringify`.
|
||||
*
|
||||
* @param dataToSerialize The data to serialize.
|
||||
* @return The serialized form as a string.
|
||||
*/
|
||||
serialize?(dataToSerialize: any): string;
|
||||
|
||||
/**
|
||||
* An optional function to deserialize the data. This defaults to
|
||||
* `JSON.parse`.
|
||||
*
|
||||
* @param dataToSerialize The data to parse.
|
||||
* @return The parsed form.
|
||||
*/
|
||||
deserialize?(dataToDeserialize: string): any;
|
||||
|
||||
/**
|
||||
* An optional function to extract the data from a raw XMLHttpRequest,
|
||||
* useful if the relevant data is in a response header or the status
|
||||
* field.
|
||||
*
|
||||
* @param xhr The associated XMLHttpRequest.
|
||||
* @param options The options passed to this request.
|
||||
* @return string The serialized format.
|
||||
*/
|
||||
extract?(xhr: XMLHttpRequest, options: MithrilXHROptions<T>): string;
|
||||
|
||||
/**
|
||||
* The parsed data, or its children if it's an array, will be passed to
|
||||
* this class constructor if it's given, to parse it into classes.
|
||||
*
|
||||
* @param data The data to parse.
|
||||
* @return The new instance for the list.
|
||||
*/
|
||||
type?: new (data: Object) => any;
|
||||
|
||||
/**
|
||||
* An optional function to run between `open` and `send`, useful for
|
||||
* adding request headers or using XHR2 features such as the `upload`
|
||||
* property. It is even possible to override the XHR altogether with a
|
||||
* similar object, such as an XDomainRequest instance.
|
||||
*
|
||||
* @param xhr The associated XMLHttpRequest.
|
||||
* @param options The options passed to this request.
|
||||
* @return The new XMLHttpRequest, or nothing if the same one is kept.
|
||||
*/
|
||||
config?(xhr: XMLHttpRequest, options: MithrilXHROptions<T>): any;
|
||||
|
||||
/**
|
||||
* For JSONP requests, this must be the string "jsonp". Otherwise, it's
|
||||
* ignored.
|
||||
*/
|
||||
dataType?: string;
|
||||
|
||||
/**
|
||||
* For JSONP requests, this is the query string key for the JSONP
|
||||
* request. This is useful for APIs that don't use common conventions,
|
||||
* such as `www.example.com/?jsonpCallback=doSomething`. It defaults to
|
||||
* `callback` for JSONP requests, and is ignored for any other kind of
|
||||
* request.
|
||||
*/
|
||||
callbackKey?: string;
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implement the "React" namespace so that we can use TSX literals.
|
||||
* Just returns plain DOM elements, no fancy virtual DOM.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
let React = {
|
||||
createElement: function(tag, props, ...children) {
|
||||
let e = document.createElement(tag);
|
||||
for (let k in props) {
|
||||
e.setAttribute(k, props[k]);
|
||||
}
|
||||
for (let child of children) {
|
||||
if ("string" === typeof child || "number" === typeof child) {
|
||||
child = document.createTextNode(child);
|
||||
}
|
||||
e.appendChild(child);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3,4 +3,4 @@
|
||||
|
||||
/// <reference path="decl/lib.es6.d.ts" />
|
||||
/// <reference path="decl/urijs/URIjs.d.ts" />
|
||||
/// <reference path="decl/systemjs/systemjs.d.ts" />
|
||||
/// <reference path="decl/systemjs/systemjs.d.ts" />
|
||||
|
29
extension/lib/vendor/lodash.core.min.js
vendored
Normal file
29
extension/lib/vendor/lodash.core.min.js
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @license
|
||||
* lodash 4.0.0 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE
|
||||
* Build: `lodash core -o ./dist/lodash.core.js`
|
||||
*/
|
||||
;(function(){function n(n,t){for(var r=-1,e=t.length,u=n.length;++r<e;)n[u+r]=t[r];return n}function t(n,t,r){for(var e=-1,u=n.length;++e<u;){var o=n[e],i=t(o);if(null!=i&&(c===ln?i===i:r(i,c)))var c=i,f=o}return f}function r(n,t,r){var e;return r(n,function(n,r,u){return t(n,r,u)?(e=n,false):void 0}),e}function e(n,t,r,e,u){return u(n,function(n,u,o){r=e?(e=false,n):t(r,n,u,o)}),r}function u(n,t){return w(t,function(t){return n[t]})}function o(n){return n&&n.Object===Object?n:null}function i(n){return vn[n];
|
||||
}function c(n){var t=false;if(null!=n&&typeof n.toString!="function")try{t=!!(n+"")}catch(r){}return t}function f(n,t){return n=typeof n=="number"||hn.test(n)?+n:-1,n>-1&&0==n%1&&(null==t?9007199254740991:t)>n}function a(n){if(Z(n)&&!Vn(n)){if(n instanceof l)return n;if(En.call(n,"__wrapped__")){var t=new l(n.__wrapped__,n.__chain__);return t.__actions__=k(n.__actions__),t}}return new l(n)}function l(n,t){this.__wrapped__=n,this.__actions__=[],this.__chain__=!!t}function p(n,t,r,e){return n===ln||H(n,xn[r])&&!En.call(e,r)?t:n;
|
||||
}function s(n,t,r){if(typeof n!="function")throw new TypeError("Expected a function");return setTimeout(function(){n.apply(ln,r)},t)}function h(n,t){var r=true;return $n(n,function(n,e,u){return r=!!t(n,e,u)}),r}function v(n,t){var r=[];return $n(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function y(t,r,e,u){u||(u=[]);for(var o=-1,i=t.length;++o<i;){var c=t[o];Z(c)&&Q(c)&&(e||Vn(c)||L(c))?r?y(c,r,e,u):n(u,c):e||(u[u.length]=c)}return u}function _(n,t){return n&&qn(n,t,un)}function g(n,t){return v(t,function(t){
|
||||
return W(n[t])})}function b(n,t,r,e,u){return n===t?true:null==n||null==t||!Y(n)&&!Z(t)?n!==n&&t!==t:j(n,t,b,r,e,u)}function j(n,t,r,e,u,o){var i=Vn(n),f=Vn(t),a="[object Array]",l="[object Array]";i||(a=kn.call(n),"[object Arguments]"==a&&(a="[object Object]")),f||(l=kn.call(t),"[object Arguments]"==l&&(l="[object Object]"));var p="[object Object]"==a&&!c(n),f="[object Object]"==l&&!c(t);return!(l=a==l)||i||p?2&u||(a=p&&En.call(n,"__wrapped__"),f=f&&En.call(t,"__wrapped__"),!a&&!f)?l?(o||(o=[]),(a=C(o,function(t){
|
||||
return t[0]===n}))&&a[1]?a[1]==t:(o.push([n,t]),t=(i?R:$)(n,t,r,e,u,o),o.pop(),t)):false:r(a?n.value():n,f?t.value():t,e,u,o):I(n,t,a)}function d(n){var t=typeof n;return"function"==t?n:null==n?fn:("object"==t?O:E)(n)}function m(n){n=null==n?n:Object(n);var t,r=[];for(t in n)r.push(t);return r}function w(n,t){var r=-1,e=Q(n)?Array(n.length):[];return $n(n,function(n,u,o){e[++r]=t(n,u,o)}),e}function O(n){var t=un(n),r=t.length;return function(e){if(null==e)return!r;for(e=Object(e);r--;){var u=t[r];if(!(u in e&&b(n[u],e[u],ln,true)))return false;
|
||||
}return true}}function x(n,t){return n=Object(n),J(t,function(t,r){return r in n&&(t[r]=n[r]),t},{})}function E(n){return function(t){return null==t?ln:t[n]}}function A(n,t,r){var e=-1,u=n.length;for(0>t&&(t=-t>u?0:u+t),r=r>u?u:r,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Array(u);++e<u;)r[e]=n[e+t];return r}function k(n){return A(n,0,n.length)}function N(n,t){var r;return $n(n,function(n,e,u){return r=t(n,e,u),!r}),!!r}function S(t,r){return J(r,function(t,r){return r.func.apply(r.thisArg,n([t],r.args))},t);
|
||||
}function T(n,t,r,e){r||(r={});for(var u=-1,o=t.length;++u<o;){var i=t[u],c=e?e(r[i],n[i],i,r,n):n[i],f=r,a=f[i];(!H(a,c)||H(a,xn[i])&&!En.call(f,i)||c===ln&&!(i in f))&&(f[i]=c)}return r}function F(n){return V(function(t,r){var e=-1,u=r.length,o=u>1?r[u-1]:ln,o=typeof o=="function"?(u--,o):ln;for(t=Object(t);++e<u;){var i=r[e];i&&n(t,i,o)}return t})}function B(n){return function(){var t=arguments,r=In(n.prototype),t=n.apply(r,t);return Y(t)?t:r}}function D(n,t,r){function e(){for(var o=-1,i=arguments.length,c=-1,f=r.length,a=Array(f+i),l=this&&this!==wn&&this instanceof e?u:n;++c<f;)a[c]=r[c];
|
||||
for(;i--;)a[c++]=arguments[++o];return l.apply(t,a)}if(typeof n!="function")throw new TypeError("Expected a function");var u=B(n);return e}function R(n,t,r,e,u,o){var i=-1,c=1&u,f=n.length,a=t.length;if(f!=a&&!(2&u&&a>f))return false;for(a=true;++i<f;){var l=n[i],p=t[i];if(void 0!==ln){a=false;break}if(c){if(!N(t,function(n){return l===n||r(l,n,e,u,o)})){a=false;break}}else if(l!==p&&!r(l,p,e,u,o)){a=false;break}}return a}function I(n,t,r){switch(r){case"[object Boolean]":case"[object Date]":return+n==+t;case"[object Error]":
|
||||
return n.name==t.name&&n.message==t.message;case"[object Number]":return n!=+n?t!=+t:n==+t;case"[object RegExp]":case"[object String]":return n==t+""}return false}function $(n,t,r,e,u,o){var i=2&u,c=1&u,f=un(n),a=f.length,l=un(t);if(a!=l.length&&!i)return false;for(var p=a;p--;){var s=f[p];if(!(i?s in t:En.call(t,s))||!c&&s!=l[p])return false}for(c=true;++p<a;){var s=f[p],l=n[s],h=t[s];if(void 0!==ln||l!==h&&!r(l,h,e,u,o)){c=false;break}i||(i="constructor"==s)}return c&&!i&&(r=n.constructor,e=t.constructor,r!=e&&"constructor"in n&&"constructor"in t&&!(typeof r=="function"&&r instanceof r&&typeof e=="function"&&e instanceof e)&&(c=false)),
|
||||
c}function q(n){var t=n?n.length:ln;if(X(t)&&(Vn(n)||tn(n)||L(n))){n=String;for(var r=-1,e=Array(t);++r<t;)e[r]=n(r);t=e}else t=null;return t}function M(n){var t=n&&n.constructor;return n===(typeof t=="function"&&t.prototype||xn)}function z(n){return n?n[0]:ln}function C(n,t){return r(n,d(t),$n)}function G(n,t){return $n(n,typeof t=="function"?t:fn)}function J(n,t,r){return e(n,d(t),r,3>arguments.length,$n)}function P(n){return null==n?0:(n=Q(n)?n:un(n),n.length)}function U(n,t){var r;if(typeof t!="function")throw new TypeError("Expected a function");
|
||||
return n=Hn(n),function(){return 0<--n&&(r=t.apply(this,arguments)),1>=n&&(t=ln),r}}function V(n){var t;if(typeof n!="function")throw new TypeError("Expected a function");return t=Rn(t===ln?n.length-1:Hn(t),0),function(){for(var r=arguments,e=-1,u=Rn(r.length-t,0),o=Array(u);++e<u;)o[e]=r[t+e];for(u=Array(t+1),e=-1;++e<t;)u[e]=r[e];return u[t]=o,n.apply(this,u)}}function H(n,t){return n===t||n!==n&&t!==t}function K(n,t){return n>t}function L(n){return Z(n)&&Q(n)&&En.call(n,"callee")&&(!Fn.call(n,"callee")||"[object Arguments]"==kn.call(n));
|
||||
}function Q(n){return null!=n&&!(typeof n=="function"&&W(n))&&X(Mn(n))}function W(n){return n=Y(n)?kn.call(n):"","[object Function]"==n||"[object GeneratorFunction]"==n}function X(n){return typeof n=="number"&&n>-1&&0==n%1&&9007199254740991>=n}function Y(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function Z(n){return!!n&&typeof n=="object"}function nn(n){return typeof n=="number"||Z(n)&&"[object Number]"==kn.call(n)}function tn(n){return typeof n=="string"||!Vn(n)&&Z(n)&&"[object String]"==kn.call(n);
|
||||
}function rn(n,t){return t>n}function en(n){return typeof n=="string"?n:null==n?"":n+""}function un(n){var t=M(n);if(!t&&!Q(n))return Dn(Object(n));var r,e=q(n),u=!!e,e=e||[],o=e.length;for(r in n)!En.call(n,r)||u&&("length"==r||f(r,o))||t&&"constructor"==r||e.push(r);return e}function on(n){for(var t=-1,r=M(n),e=m(n),u=e.length,o=q(n),i=!!o,o=o||[],c=o.length;++t<u;){var a=e[t];i&&("length"==a||f(a,c))||"constructor"==a&&(r||!En.call(n,a))||o.push(a)}return o}function cn(n){return n?u(n,un(n)):[];
|
||||
}function fn(n){return n}function an(t,r,e){var u=un(r),o=g(r,u);null!=e||Y(r)&&(o.length||!u.length)||(e=r,r=t,t=this,o=g(r,un(r)));var i=Y(e)&&"chain"in e?e.chain:true,c=W(t);return $n(o,function(e){var u=r[e];t[e]=u,c&&(t.prototype[e]=function(){var r=this.__chain__;if(i||r){var e=t(this.__wrapped__);return(e.__actions__=k(this.__actions__)).push({func:u,args:arguments,thisArg:t}),e.__chain__=r,e}return u.apply(t,n([this.value()],arguments))})}),t}var ln,pn=/[&<>"'`]/g,sn=RegExp(pn.source),hn=/^(?:0|[1-9]\d*)$/,vn={
|
||||
"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},yn={"function":true,object:true},_n=yn[typeof exports]&&exports&&!exports.nodeType?exports:null,gn=yn[typeof module]&&module&&!module.nodeType?module:null,bn=o(yn[typeof self]&&self),jn=o(yn[typeof window]&&window),dn=gn&&gn.exports===_n?_n:null,mn=o(yn[typeof this]&&this),wn=o(_n&&gn&&typeof global=="object"&&global)||jn!==(mn&&mn.window)&&jn||bn||mn||Function("return this")(),On=Array.prototype,xn=Object.prototype,En=xn.hasOwnProperty,An=0,kn=xn.toString,Nn=wn._,Sn=wn.f,Tn=Sn?Sn.g:ln,Fn=xn.propertyIsEnumerable,Bn=wn.isFinite,Dn=Object.keys,Rn=Math.max,In=function(){
|
||||
function n(){}return function(t){if(Y(t)){n.prototype=t;var r=new n;n.prototype=ln}return r||{}}}(),$n=function(n,t){return function(r,e){if(null==r)return r;if(!Q(r))return n(r,e);for(var u=r.length,o=t?u:-1,i=Object(r);(t?o--:++o<u)&&false!==e(i[o],o,i););return r}}(_),qn=function(n){return function(t,r,e){var u=-1,o=Object(t);e=e(t);for(var i=e.length;i--;){var c=e[n?i:++u];if(false===r(o[c],c,o))break}return t}}();Tn&&!Fn.call({valueOf:1},"valueOf")&&(m=function(n){n=Tn(n);for(var t,r=[];!(t=n.next()).done;)r.push(t.value);
|
||||
return r});var Mn=E("length"),zn=V(function(t,r){y(r);var e=Vn(t)?t:[Object(t)];return n(k(e),cn)}),Cn=V(function(n,t,r){var e=typeof t=="function";return w(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})}),Gn=Date.now,Jn=V(function(n,t,r){return D(n,t,r)}),Pn=V(function(n,t){return s(n,1,t)}),Un=V(function(n,t,r){return s(n,Kn(t)||0,r)}),Vn=Array.isArray,Hn=Number,Kn=Number,Ln=F(function(n,t){T(t,un(t),n)}),Qn=F(function(n,t){T(t,on(t),n)}),Wn=F(function(n,t,r){T(t,on(t),n,r)}),Xn=V(function(n){
|
||||
return n.push(ln,p),Wn.apply(ln,n)}),Yn=V(function(n,t){return null==n?{}:x(n,y(t))}),Zn=d;l.prototype=In(a.prototype),l.prototype.constructor=l,a.assignIn=Qn,a.before=U,a.bind=Jn,a.chain=function(n){return n=a(n),n.__chain__=true,n},a.compact=function(n){return v(n,Boolean)},a.concat=zn,a.create=function(n,t){var r=In(n);return t?Ln(r,t):r},a.defaults=Xn,a.defer=Pn,a.delay=Un,a.filter=function(n,t){return v(n,d(t))},a.flatten=function(n){return n&&n.length?y(n):[]},a.flattenDeep=function(n){return n&&n.length?y(n,true):[];
|
||||
},a.invokeMap=Cn,a.iteratee=Zn,a.keys=un,a.map=function(n,t){return w(n,d(t))},a.mixin=an,a.negate=function(n){if(typeof n!="function")throw new TypeError("Expected a function");return function(){return!n.apply(this,arguments)}},a.once=function(n){return U(2,n)},a.pick=Yn,a.slice=function(n,t,r){return n&&n.length?A(n,t,r):[]},a.sortBy=function(n,t){var r=0;return t=d(t),w(w(n,function(n,e,u){return{c:n,b:r++,a:t(n,e,u)}}).sort(function(n,t){var r;n:{r=n.a;var e=t.a;if(r!==e){var u=null===r,o=r===ln,i=r===r,c=null===e,f=e===ln,a=e===e;
|
||||
if(r>e&&!c||!i||u&&!f&&a||o&&a){r=1;break n}if(e>r&&!u||!a||c&&!o&&i||f&&i){r=-1;break n}}r=0}return r||n.b-t.b}),E("c"))},a.tap=function(n,t){return t(n),n},a.thru=function(n,t){return t(n)},a.toArray=function(n){return Q(n)?n.length?k(n):[]:cn(n)},a.values=cn,a.each=G,a.extend=Qn,an(a,a),a.clone=function(n){return Y(n)?Vn(n)?k(n):T(n,un(n)):n},a.escape=function(n){return(n=en(n))&&sn.test(n)?n.replace(pn,i):n},a.every=function(n,t,r){return t=r?ln:t,h(n,d(t))},a.find=C,a.forEach=G,a.has=function(n,t){
|
||||
return null!=n&&En.call(n,t)},a.head=z,a.identity=fn,a.indexOf=function(n,t,r){var e=n?n.length:0;r=typeof r=="number"?0>r?Rn(e+r,0):r:0,r=(r||0)-1;for(var u=t===t;++r<e;){var o=n[r];if(u?o===t:o!==o)return r}return-1},a.isArguments=L,a.isArray=Vn,a.isBoolean=function(n){return true===n||false===n||Z(n)&&"[object Boolean]"==kn.call(n)},a.isDate=function(n){return Z(n)&&"[object Date]"==kn.call(n)},a.isEmpty=function(n){return!Z(n)||W(n.splice)?!P(n):!un(n).length},a.isEqual=function(n,t){return b(n,t)},
|
||||
a.isFinite=function(n){return typeof n=="number"&&Bn(n)},a.isFunction=W,a.isNaN=function(n){return nn(n)&&n!=+n},a.isNull=function(n){return null===n},a.isNumber=nn,a.isObject=Y,a.isRegExp=function(n){return Y(n)&&"[object RegExp]"==kn.call(n)},a.isString=tn,a.isUndefined=function(n){return n===ln},a.last=function(n){var t=n?n.length:0;return t?n[t-1]:ln},a.max=function(n){return n&&n.length?t(n,fn,K):ln},a.min=function(n){return n&&n.length?t(n,fn,rn):ln},a.noConflict=function(){return wn._=Nn,this;
|
||||
},a.noop=function(){},a.now=Gn,a.reduce=J,a.result=function(n,t,r){return t=null==n?ln:n[t],t===ln&&(t=r),W(t)?t.call(n):t},a.size=P,a.some=function(n,t,r){return t=r?ln:t,N(n,d(t))},a.uniqueId=function(n){var t=++An;return en(n)+t},a.first=z,an(a,function(){var n={};return _(a,function(t,r){En.call(a.prototype,r)||(n[r]=t)}),n}(),{chain:false}),a.VERSION="4.0.0",$n("pop join replace reverse split push shift sort splice unshift".split(" "),function(n){var t=(/^(?:replace|split)$/.test(n)?String.prototype:On)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:pop|join|replace|shift)$/.test(n);
|
||||
a.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),a.prototype.toJSON=a.prototype.valueOf=a.prototype.value=function(){return S(this.__wrapped__,this.__actions__)},(jn||bn||{})._=a,typeof define=="function"&&typeof define.amd=="object"&&define.amd? define(function(){return a}):_n&&gn?(dn&&((gn.exports=a)._=a),_n._=a):wn._=a}).call(this);
|
1408
extension/lib/vendor/mithril.js
vendored
Normal file
1408
extension/lib/vendor/mithril.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -33,7 +33,7 @@ const DB_VERSION = 1;
|
||||
*/
|
||||
export function openTalerDb(): Promise<IDBDatabase> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
req.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
@ -45,16 +45,17 @@ export function openTalerDb(): Promise<IDBDatabase> {
|
||||
console.log("DB: upgrade needed: oldVersion = " + e.oldVersion);
|
||||
switch (e.oldVersion) {
|
||||
case 0: // DB does not exist yet
|
||||
let mints = db.createObjectStore("mints", {keyPath: "baseUrl"});
|
||||
const mints = db.createObjectStore("mints", {keyPath: "baseUrl"});
|
||||
mints.createIndex("pubKey", "keys.master_public_key");
|
||||
db.createObjectStore("reserves", {keyPath: "reserve_pub"});
|
||||
db.createObjectStore("denoms", {keyPath: "denomPub"});
|
||||
let coins = db.createObjectStore("coins", {keyPath: "coinPub"});
|
||||
const coins = db.createObjectStore("coins", {keyPath: "coinPub"});
|
||||
coins.createIndex("mintBaseUrl", "mintBaseUrl");
|
||||
db.createObjectStore("transactions", {keyPath: "contractHash"});
|
||||
db.createObjectStore("precoins",
|
||||
{keyPath: "coinPub", autoIncrement: true});
|
||||
db.createObjectStore("history", {keyPath: "id", autoIncrement: true});
|
||||
const history = db.createObjectStore("history", {keyPath: "id", autoIncrement: true});
|
||||
history.createIndex("timestamp", "timestamp");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ export interface QueryStream<T> {
|
||||
indexName: string,
|
||||
keyFn: (obj: any) => any): QueryStream<[T,S]>;
|
||||
filter(f: (any) => boolean): QueryStream<T>;
|
||||
reduce<S>(f: (S, T) => S, acc?: S): Promise<S>;
|
||||
reduce<S>(f: (v: T, acc: S) => S, start?: S): Promise<S>;
|
||||
}
|
||||
|
||||
|
||||
@ -166,7 +166,7 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
|
||||
private storeName;
|
||||
private options;
|
||||
|
||||
constructor(qr, storeName, options?) {
|
||||
constructor(qr, storeName, options) {
|
||||
super(qr);
|
||||
this.options = options;
|
||||
this.storeName = storeName;
|
||||
@ -174,15 +174,16 @@ class IterQueryStream<T> extends QueryStreamBase<T> {
|
||||
|
||||
subscribe(f) {
|
||||
let doIt = (tx) => {
|
||||
const {indexName = void 0, only = void 0} = this.options;
|
||||
let s;
|
||||
if (this.options && this.options.indexName) {
|
||||
if (indexName !== void 0) {
|
||||
s = tx.objectStore(this.storeName)
|
||||
.index(this.options.indexName);
|
||||
} else {
|
||||
s = tx.objectStore(this.storeName);
|
||||
}
|
||||
let kr = undefined;
|
||||
if (this.options && ("only" in this.options)) {
|
||||
if (only !== void 0) {
|
||||
kr = IDBKeyRange.only(this.options.only);
|
||||
}
|
||||
let req = s.openCursor(kr);
|
||||
@ -218,23 +219,11 @@ class QueryRoot {
|
||||
this.db = db;
|
||||
}
|
||||
|
||||
iter<T>(storeName): QueryStream<T> {
|
||||
iter<T>(storeName, {only = void 0, indexName = void 0} = {}): QueryStream<T> {
|
||||
this.stores.add(storeName);
|
||||
return new IterQueryStream(this, storeName);
|
||||
return new IterQueryStream(this, storeName, {only, indexName});
|
||||
}
|
||||
|
||||
iterOnly<T>(storeName, key): QueryStream<T> {
|
||||
this.stores.add(storeName);
|
||||
return new IterQueryStream(this, storeName, {only: key});
|
||||
}
|
||||
|
||||
|
||||
iterIndex<T>(storeName, indexName, key) {
|
||||
this.stores.add(storeName);
|
||||
return new IterQueryStream(this, storeName, {indexName: indexName});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Put an object into the given object store.
|
||||
* Overrides if an existing object with the same key exists
|
||||
|
@ -181,6 +181,18 @@ function canonicalizeBaseUrl(url) {
|
||||
return x.href()
|
||||
}
|
||||
|
||||
function parsePrettyAmount(pretty: string): AmountJson_interface {
|
||||
const res = /([0-9]+)(.[0-9]+)?\s*(\w+)/.exec(pretty);
|
||||
if (!res) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
value: parseInt(res[1], 10),
|
||||
fraction: res[2] ? (parseFloat(`0.${res[2]}`) * 1e-6) : 0,
|
||||
currency: res[3]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface HttpRequestLibrary {
|
||||
req(method: string,
|
||||
@ -310,7 +322,7 @@ export class Wallet {
|
||||
|
||||
let ps = allowedMints.map((info) => {
|
||||
return Query(this.db)
|
||||
.iterIndex("mints", "pubKey", info.master_pub)
|
||||
.iter("mints", {indexName: "pubKey", only: info.master_pub})
|
||||
.indexJoin("coins", "mintBaseUrl", (mint) => mint.baseUrl)
|
||||
.reduce(storeMintCoin);
|
||||
});
|
||||
@ -376,8 +388,20 @@ export class Wallet {
|
||||
payReq: payReq
|
||||
};
|
||||
|
||||
|
||||
let historyEntry = {
|
||||
type: "pay",
|
||||
timestamp: (new Date).getTime(),
|
||||
detail: {
|
||||
merchantName: offer.contract.merchant.name,
|
||||
amount: offer.contract.amount,
|
||||
contractHash: offer.H_contract
|
||||
}
|
||||
};
|
||||
|
||||
return Query(this.db)
|
||||
.put("transactions", t)
|
||||
.put("history", historyEntry)
|
||||
.putAll("coins", payCoinInfo.map((pci) => pci.updatedCoin))
|
||||
.finish();
|
||||
}
|
||||
@ -418,12 +442,17 @@ export class Wallet {
|
||||
let reservePriv = EddsaPrivateKey.create();
|
||||
let reservePub = reservePriv.getPublicKey();
|
||||
let form = new FormData();
|
||||
let now = (new Date()).toString();
|
||||
let now: number = (new Date).getTime();
|
||||
form.append(req.field_amount, req.amount_str);
|
||||
form.append(req.field_reserve_pub, reservePub.toCrock());
|
||||
form.append(req.field_mint, req.mint);
|
||||
// TODO: set bank-specified fields.
|
||||
let mintBaseUrl = canonicalizeBaseUrl(req.mint);
|
||||
let requestedAmount = parsePrettyAmount(req.amount_str);
|
||||
|
||||
if (!requestedAmount) {
|
||||
throw Error(`unrecognized amount ${req.amount_str}.`);
|
||||
}
|
||||
|
||||
return this.http.postForm(req.post_url, form)
|
||||
.then((hresp) => {
|
||||
@ -441,7 +470,7 @@ export class Wallet {
|
||||
last_query: null,
|
||||
current_amount: null,
|
||||
// XXX: set to actual amount
|
||||
initial_amount: null
|
||||
requested_amount: null
|
||||
};
|
||||
|
||||
if (hresp.status != 200) {
|
||||
@ -449,12 +478,22 @@ export class Wallet {
|
||||
return resp;
|
||||
}
|
||||
|
||||
let historyEntry = {
|
||||
type: "create-reserve",
|
||||
timestamp: now,
|
||||
detail: {
|
||||
requestedAmount,
|
||||
reservePub: reserveRecord.reserve_pub,
|
||||
}
|
||||
};
|
||||
|
||||
resp.success = true;
|
||||
// We can't show the page directly, so
|
||||
// we show some generic page from the wallet.
|
||||
resp.backlink = null;
|
||||
return Query(this.db)
|
||||
.put("reserves", reserveRecord)
|
||||
.put("history", historyEntry)
|
||||
.finish()
|
||||
.then(() => {
|
||||
// Do this in the background
|
||||
@ -574,10 +613,18 @@ export class Wallet {
|
||||
.then(doBadge.bind(this));
|
||||
}
|
||||
|
||||
storeCoin(coin: Coin) {
|
||||
Query(this.db)
|
||||
storeCoin(coin: Coin): Promise<void> {
|
||||
let historyEntry = {
|
||||
type: "withdraw",
|
||||
timestamp: (new Date).getTime(),
|
||||
detail: {
|
||||
coinPub: coin.coinPub,
|
||||
}
|
||||
};
|
||||
return Query(this.db)
|
||||
.delete("precoins", coin.coinPub)
|
||||
.add("coins", coin)
|
||||
.add("history", historyEntry)
|
||||
.finish()
|
||||
.then(() => {
|
||||
this.updateBadge();
|
||||
@ -624,7 +671,10 @@ export class Wallet {
|
||||
}
|
||||
let d = workList.pop();
|
||||
this.withdraw(d, reserve)
|
||||
.then(() => next());
|
||||
.then(() => next())
|
||||
.catch((e) => {
|
||||
console.log("Failed to withdraw coin", e.stack);
|
||||
});
|
||||
};
|
||||
|
||||
// Asynchronous recursion
|
||||
@ -647,7 +697,18 @@ export class Wallet {
|
||||
if (!reserveInfo) {
|
||||
throw Error();
|
||||
}
|
||||
let oldAmount = reserve.current_amount;
|
||||
let newAmount = reserveInfo.balance;
|
||||
reserve.current_amount = reserveInfo.balance;
|
||||
let historyEntry = {
|
||||
type: "reserve-update",
|
||||
timestamp: (new Date).getTime(),
|
||||
detail: {
|
||||
reservePub,
|
||||
oldAmount,
|
||||
newAmount
|
||||
}
|
||||
};
|
||||
return Query(this.db)
|
||||
.put("reserves", reserve)
|
||||
.finish()
|
||||
@ -696,4 +757,14 @@ export class Wallet {
|
||||
.iter("coins")
|
||||
.reduce(collectBalances, {});
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
function collect(x, acc) {
|
||||
acc.push(x);
|
||||
return acc;
|
||||
}
|
||||
return Query(this.db)
|
||||
.iter("history", {indexName: "timestamp"})
|
||||
.reduce(collect, [])
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,12 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
function makeHandlers(wallet) {
|
||||
return (_a = {},
|
||||
_a["balances"] = function (db, detail, sendResponse) {
|
||||
wallet.getBalances().then(sendResponse);
|
||||
wallet.getBalances()
|
||||
.then(sendResponse)
|
||||
.catch(function (e) {
|
||||
console.log("exception during 'balances'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
_a["dump-db"] = function (db, detail, sendResponse) {
|
||||
@ -54,6 +59,10 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
resp.backlink = chrome.extension.getURL("pages/reserve-success.html");
|
||||
}
|
||||
sendResponse(resp);
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'confirm-reserve'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
@ -63,6 +72,8 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
sendResponse({ success: true });
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'confirm-pay'");
|
||||
console.error(e.stack);
|
||||
sendResponse({ error: e.message });
|
||||
});
|
||||
return true;
|
||||
@ -77,18 +88,33 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'execute-payment'");
|
||||
console.error(e.stack);
|
||||
sendResponse({ success: false, error: e.message });
|
||||
});
|
||||
// async sendResponse
|
||||
return true;
|
||||
},
|
||||
_a["get-history"] = function (db, detail, sendResponse) {
|
||||
// TODO: limit history length
|
||||
wallet.getHistory()
|
||||
.then(function (h) {
|
||||
sendResponse(h);
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("exception during 'get-history'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
_a
|
||||
);
|
||||
var _a;
|
||||
}
|
||||
function wxMain() {
|
||||
chrome.browserAction.setBadgeText({ text: "" });
|
||||
db_3.openTalerDb().then(function (db) {
|
||||
db_3.openTalerDb()
|
||||
.then(function (db) {
|
||||
var http = new http_1.BrowserHttpLib();
|
||||
var badge = new ChromeBadge();
|
||||
var wallet = new wallet_1.Wallet(db, http, badge);
|
||||
@ -101,6 +127,10 @@ System.register(["./wallet", "./db", "./http"], function(exports_1) {
|
||||
console.error("Request type " + JSON.stringify(req) + " unknown, req " + req.type);
|
||||
return false;
|
||||
});
|
||||
})
|
||||
.catch(function (e) {
|
||||
console.error("could not open database:");
|
||||
console.error(e.stack);
|
||||
});
|
||||
}
|
||||
exports_1("wxMain", wxMain);
|
||||
|
@ -36,7 +36,12 @@ import {Badge} from "./wallet";
|
||||
function makeHandlers(wallet) {
|
||||
return {
|
||||
["balances"]: function(db, detail, sendResponse) {
|
||||
wallet.getBalances().then(sendResponse);
|
||||
wallet.getBalances()
|
||||
.then(sendResponse)
|
||||
.catch((e) => {
|
||||
console.log("exception during 'balances'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
["dump-db"]: function(db, detail, sendResponse) {
|
||||
@ -72,6 +77,10 @@ function makeHandlers(wallet) {
|
||||
"pages/reserve-success.html");
|
||||
}
|
||||
sendResponse(resp);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'confirm-reserve'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
},
|
||||
@ -81,6 +90,8 @@ function makeHandlers(wallet) {
|
||||
sendResponse({success: true})
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'confirm-pay'");
|
||||
console.error(e.stack);
|
||||
sendResponse({error: e.message});
|
||||
});
|
||||
return true;
|
||||
@ -95,10 +106,24 @@ function makeHandlers(wallet) {
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'execute-payment'");
|
||||
console.error(e.stack);
|
||||
sendResponse({success: false, error: e.message});
|
||||
});
|
||||
// async sendResponse
|
||||
return true;
|
||||
},
|
||||
["get-history"]: function(db, detail, sendResponse) {
|
||||
// TODO: limit history length
|
||||
wallet.getHistory()
|
||||
.then((h) => {
|
||||
sendResponse(h);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("exception during 'get-history'");
|
||||
console.error(e.stack);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -117,19 +142,24 @@ class ChromeBadge implements Badge {
|
||||
export function wxMain() {
|
||||
chrome.browserAction.setBadgeText({text: ""});
|
||||
|
||||
openTalerDb().then((db) => {
|
||||
let http = new BrowserHttpLib();
|
||||
let badge = new ChromeBadge();
|
||||
let wallet = new Wallet(db, http, badge);
|
||||
let handlers = makeHandlers(wallet);
|
||||
wallet.updateBadge();
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function(req, sender, onresponse) {
|
||||
if (req.type in handlers) {
|
||||
return handlers[req.type](db, req.detail, onresponse);
|
||||
}
|
||||
console.error(`Request type ${JSON.stringify(req)} unknown, req ${req.type}`);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
openTalerDb()
|
||||
.then((db) => {
|
||||
let http = new BrowserHttpLib();
|
||||
let badge = new ChromeBadge();
|
||||
let wallet = new Wallet(db, http, badge);
|
||||
let handlers = makeHandlers(wallet);
|
||||
wallet.updateBadge();
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function(req, sender, onresponse) {
|
||||
if (req.type in handlers) {
|
||||
return handlers[req.type](db, req.detail, onresponse);
|
||||
}
|
||||
console.error(`Request type ${JSON.stringify(req)} unknown, req ${req.type}`);
|
||||
return false;
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error("could not open database:");
|
||||
console.error(e.stack);
|
||||
});
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
"browser_action": {
|
||||
"default_icon": "img/icon.png",
|
||||
"default_title": "Taler",
|
||||
"default_popup": "popup/balance-overview.html"
|
||||
"default_popup": "popup/popup.html"
|
||||
},
|
||||
|
||||
"content_scripts": [
|
||||
|
@ -1,34 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
<script src="../lib/vendor/handlebars-v4.0.5.js" type="text/javascript"></script>
|
||||
<script src="../lib/commonHelpers.js" type="text/javascript"></script>
|
||||
<script src="balance-overview.js" type="text/javascript"></script>
|
||||
|
||||
<script id="balance-template" type="text/x-handlebars-template">
|
||||
{{#each this}}
|
||||
<p>{{prettyAmountNoCurrency this}} <a>{{@key}}</a></p>
|
||||
{{else}}
|
||||
<p>Looks like your wallet is empty. Want to get some
|
||||
<a id="link-kudos" href="http://bank.demo.taler.net">KUDOS?</a>
|
||||
{{/each}}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="header" class="nav">
|
||||
<a href="balance-overview.html" class="active">Wallet</a>
|
||||
<a href="history.html">History</a>
|
||||
<a href="reserves.html">Reserves</a>
|
||||
<button id="debug">Debug!</button>
|
||||
<button id="reset">Reset!</button>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
"use strict";
|
||||
document.addEventListener("DOMContentLoaded", function (e) {
|
||||
console.log("content loaded");
|
||||
chrome.runtime.sendMessage({ type: "balances" }, function (wallet) {
|
||||
var context = document.getElementById("balance-template").innerHTML;
|
||||
var template = Handlebars.compile(context);
|
||||
document.getElementById("content").innerHTML = template(wallet);
|
||||
console.log("got wallet", JSON.stringify(wallet));
|
||||
var el = document.getElementById("link-kudos");
|
||||
if (el) {
|
||||
el.onclick = function (e) {
|
||||
var target = e.target;
|
||||
chrome.tabs.create({
|
||||
"url": target.href
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
document.getElementById("debug").addEventListener("click", function (e) {
|
||||
chrome.tabs.create({
|
||||
"url": chrome.extension.getURL("pages/debug.html")
|
||||
});
|
||||
});
|
||||
document.getElementById("reset").addEventListener("click", function (e) {
|
||||
chrome.runtime.sendMessage({ type: "reset" });
|
||||
window.close();
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=balance-overview.js.map
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (e) => {
|
||||
console.log("content loaded");
|
||||
chrome.runtime.sendMessage({type: "balances"}, function(wallet) {
|
||||
let context = document.getElementById("balance-template").innerHTML;
|
||||
let template = Handlebars.compile(context);
|
||||
document.getElementById("content").innerHTML = template(wallet);
|
||||
console.log("got wallet", JSON.stringify(wallet));
|
||||
let el = document.getElementById("link-kudos");
|
||||
if (el) {
|
||||
el.onclick = (e) => {
|
||||
let target: any = e.target;
|
||||
chrome.tabs.create({
|
||||
"url": target.href
|
||||
});
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("debug").addEventListener("click", (e) => {
|
||||
chrome.tabs.create({
|
||||
"url": chrome.extension.getURL("pages/debug.html")
|
||||
});
|
||||
});
|
||||
document.getElementById("reset").addEventListener("click", (e) => {
|
||||
chrome.runtime.sendMessage({type: "reset"});
|
||||
window.close();
|
||||
});
|
||||
});
|
@ -1,31 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
<script src="history.js" type="text/javascript"></script>
|
||||
|
||||
<script id="balance-template" type="text/x-handlebars-template">
|
||||
{{#each transactions}}
|
||||
<p>bla</p>
|
||||
{{else}}
|
||||
There's nothing here. Go to
|
||||
our <a href="http://demo.taler.net">demo site</a> to try GNU Taler.
|
||||
{{/each}}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="header" class="nav">
|
||||
<a href="balance-overview.html">Wallet</a>
|
||||
<a href="history.html" class="active">Transactions</a>
|
||||
<a href="reserves.html">Reserves</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
(Loading...)
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,4 +1,5 @@
|
||||
body {
|
||||
min-height: 20em;
|
||||
width: 30em;
|
||||
margin: 0;
|
||||
padding: 0
|
||||
|
17
extension/popup/popup.html
Normal file
17
extension/popup/popup.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
<script src="../lib/vendor/mithril.js"></script>
|
||||
<script src="../lib/i18n.js"></script>
|
||||
<script src="../lib/vendor/lodash.core.min.js"></script>
|
||||
<script src="popup.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="nav"></div>
|
||||
<div id="content"></div>
|
||||
</body>
|
||||
|
||||
|
||||
</html>
|
182
extension/popup/popup.tsx
Normal file
182
extension/popup/popup.tsx
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/// <reference path="../lib/mithril.d.ts" />
|
||||
/// <reference path="../lib/decl/lodash.d.ts" />
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
declare var m: any;
|
||||
declare var i18n: any;
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
m.route.mode = "hash";
|
||||
m.route(document.getElementById("content"), "/balance", {
|
||||
"/balance": WalletBalance,
|
||||
"/history": WalletHistory,
|
||||
"/debug": WalletDebug,
|
||||
});
|
||||
m.mount(document.getElementById("nav"), WalletNavBar);
|
||||
});
|
||||
|
||||
|
||||
function makeTab(target, name) {
|
||||
let cssClass = "";
|
||||
if (target == m.route()) {
|
||||
cssClass = "active";
|
||||
}
|
||||
return m("a", {config: m.route, href: target, "class": cssClass}, name);
|
||||
}
|
||||
|
||||
var WalletNavBar = {
|
||||
view() {
|
||||
return m("div#header.nav", [
|
||||
makeTab("/balance", i18n`Balance`),
|
||||
makeTab("/history", i18n`History`),
|
||||
makeTab("/debug", i18n`Debug`),
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function openInExtension(element, isInitialized) {
|
||||
element.addEventListener("click", (e) => {
|
||||
chrome.tabs.create({
|
||||
"url": element.href
|
||||
});
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
var WalletBalance = {
|
||||
controller() {
|
||||
var myWallet;
|
||||
m.startComputation();
|
||||
chrome.runtime.sendMessage({type: "balances"}, (wallet) => {
|
||||
console.log("got wallet", wallet);
|
||||
myWallet = wallet;
|
||||
m.endComputation();
|
||||
});
|
||||
return () => myWallet;
|
||||
},
|
||||
|
||||
view(getWallet) {
|
||||
let wallet = getWallet();
|
||||
if (!wallet) {
|
||||
throw Error("Could not retrieve wallet");
|
||||
}
|
||||
let listing = _.map(wallet, x => m("p", formatAmount(x)));
|
||||
if (listing.length > 0) {
|
||||
return listing;
|
||||
}
|
||||
let link = m("a[href=https://demo.taler.net]", {config: openInExtension}, i18n`free KUDOS`);
|
||||
return i18n.parts`You have no balance to show. Want to get some ${link}?`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function formatTimestamp(t) {
|
||||
let x = new Date(t);
|
||||
return x.toLocaleString();
|
||||
}
|
||||
|
||||
|
||||
function formatAmount(amount) {
|
||||
let v = amount.value + amount.fraction / 1e6;
|
||||
return `${v.toFixed(2)} ${amount.currency}`;
|
||||
}
|
||||
|
||||
function formatHistoryItem(historyItem) {
|
||||
const d = historyItem.detail;
|
||||
const t = historyItem.timestamp;
|
||||
switch (historyItem.type) {
|
||||
case "create-reserve":
|
||||
return m("p",
|
||||
i18n`Created reserve of ${formatAmount(d.requestedAmount)} at ${formatTimestamp(
|
||||
t)}`);
|
||||
case "withdraw":
|
||||
return m("p",
|
||||
i18n`Withdraw at ${formatTimestamp(t)}`);
|
||||
case "pay":
|
||||
return m("p",
|
||||
[
|
||||
i18n`Payment for ${formatAmount(d.amount)} to merchant ${d.merchantName}. `,
|
||||
m("a[href=javascript:;]", "Retry")
|
||||
]);
|
||||
default:
|
||||
return m("p", i18n`Unknown event (${historyItem.type})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var WalletHistory = {
|
||||
controller() {
|
||||
var myHistory;
|
||||
m.startComputation();
|
||||
chrome.runtime.sendMessage({type: "get-history"}, (wallet) => {
|
||||
console.log("got history", history);
|
||||
myHistory = wallet;
|
||||
m.endComputation();
|
||||
});
|
||||
return () => myHistory;
|
||||
},
|
||||
|
||||
view(getHistory) {
|
||||
let history = getHistory();
|
||||
if (!history) {
|
||||
throw Error("Could not retrieve history");
|
||||
}
|
||||
let listing = _.map(history, formatHistoryItem);
|
||||
if (listing.length > 0) {
|
||||
return listing;
|
||||
}
|
||||
return i18n`Your wallet has no events recorded.`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function confirmReset() {
|
||||
if (confirm("Do you want to IRREVOCABLY DESTROY everything inside your" +
|
||||
" wallet and LOSE ALL YOUR COINS?")) {
|
||||
chrome.runtime.sendMessage({type: "reset"});
|
||||
window.close();
|
||||
try {
|
||||
chrome.runtime.reload();
|
||||
} catch (e) {
|
||||
// Functionality missing in firefox, ignore!
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var WalletDebug = {
|
||||
view() {
|
||||
return [
|
||||
m("button", {onclick: openWalletAsTab}, "wallet tab"),
|
||||
m("button", {onclick: confirmReset}, "reset")
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function openWalletAsTab() {
|
||||
chrome.tabs.create({
|
||||
"url": chrome.extension.getURL("popup/popup.html")
|
||||
});
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="header" class="nav">
|
||||
<a href="balance-overview.html">Wallet</a>
|
||||
<a href="history.html">Transactions</a>
|
||||
<a href="reserves.html" class="active">Reserves</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div id="reserve-create-sepa">
|
||||
SEPA info here.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="nav">
|
||||
<a href="reserves.html">List reserves</a>
|
||||
<a href="reserve-create.html">Create reserve</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,41 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="header" class="nav">
|
||||
<a href="balance-overview.html">Wallet</a>
|
||||
<a href="history.html">Transactions</a>
|
||||
<a href="reserves.html" class="active">Reserves</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<form id="reserve-create" action="reserve-create-sepa.html">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label"><label for="mint">Mint URL:</label></td>
|
||||
<td class="input"><input name="mint" type="text" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"><label for="amount">Amount:</label></td>
|
||||
<td class="input"><input name="amount" type="text" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="label"></td>
|
||||
<td class="input"><input type="submit" value="Create reserve " /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="nav">
|
||||
<a href="reserves.html">List reserves</a>
|
||||
<a href="reserve-create.html" class="active">Create reserve</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="popup.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="header" class="nav">
|
||||
<a href="balance-overview.html">Wallet</a>
|
||||
<a href="history.html">Transactions</a>
|
||||
<a href="reserves.html" class="active">Reserves</a>
|
||||
</div>
|
||||
|
||||
<div id="content">
|
||||
<div id="reserves">
|
||||
There are no reserves available.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" class="nav">
|
||||
<a href="reserves.html" class="active">List reserves</a>
|
||||
<a href="reserve-create.html">Create reserve</a>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,10 +1,24 @@
|
||||
|
||||
import * as Emsc from '../../lib/wallet/emscriptif';
|
||||
|
||||
|
||||
declare var HttpMockLib;
|
||||
|
||||
export function declareTests(assert, context, it) {
|
||||
|
||||
it("works!", function() {
|
||||
let x = new Emsc.Amount({value: 42, fraction:42, currency: "EUR"});
|
||||
let x = new Emsc.Amount({value: 42, fraction: 42, currency: "EUR"});
|
||||
let j = x.toJson();
|
||||
assert("value" in j);
|
||||
});
|
||||
|
||||
|
||||
it("retries", function() {
|
||||
let m = new HttpMockLib();
|
||||
/*m.intercept()
|
||||
.matchUrlContains()
|
||||
.counterEquals(0)
|
||||
.count()
|
||||
.sen*/
|
||||
})
|
||||
|
||||
}
|
@ -8,8 +8,7 @@
|
||||
"noLib": true
|
||||
},
|
||||
"files": [
|
||||
"lib/commonHelpers.ts",
|
||||
"lib/polyfill-react.ts",
|
||||
"lib/i18n.ts",
|
||||
"lib/refs.ts",
|
||||
"lib/wallet/checkable.ts",
|
||||
"lib/wallet/db.ts",
|
||||
@ -21,10 +20,9 @@
|
||||
"lib/wallet/wxmessaging.ts",
|
||||
"background/main.ts",
|
||||
"content_scripts/notify.ts",
|
||||
"popup/balance-overview.tsx",
|
||||
"popup/history.tsx",
|
||||
"popup/popup.tsx",
|
||||
"pages/confirm-contract.tsx",
|
||||
"pages/confirm-create-reserve.tsx",
|
||||
"test/tests/taler.ts"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user