diff options
-rw-r--r-- | lib/decl/preact.d.ts | 556 | ||||
l--------- | lib/vendor/preact | 1 | ||||
-rw-r--r-- | lib/vendor/preact.js | 469 | ||||
-rw-r--r-- | lib/wallet/renderHtml.ts | 24 | ||||
-rw-r--r-- | pages/confirm-contract.html | 3 | ||||
-rw-r--r-- | pages/confirm-contract.tsx | 187 |
6 files changed, 1159 insertions, 81 deletions
diff --git a/lib/decl/preact.d.ts b/lib/decl/preact.d.ts new file mode 100644 index 000000000..fb8a0b764 --- /dev/null +++ b/lib/decl/preact.d.ts @@ -0,0 +1,556 @@ +declare namespace preact { + interface ComponentProps { + children?:JSX.Element[]; + key?:string; + } + + interface PreactHTMLAttributes { + key?:string; + } + + interface VNode { + nodeName:ComponentConstructor<any, any>|string; + attributes:{[name:string]:any}; + children:VNode[]; + key:string; + } + + interface ComponentLifecycle<PropsType, StateType> { + componentWillMount?():void; + + componentDidMount?():void; + + componentWillUnmount?():void; + + componentDidUnmount?():void; + + componentWillReceiveProps?(props:PropsType):void; + + shouldComponentUpdate?(props:PropsType):boolean; + + componentWillUpdate?():void; + + componentDidUpdate?():void; + } + + interface ComponentConstructor<PropsType, StateType> { + new (props?:PropsType):Component<PropsType, StateType>; + } + + abstract class Component<PropsType, StateType> implements ComponentLifecycle<PropsType, StateType> { + constructor(props?:PropsType); + + state:StateType; + props:PropsType & ComponentProps; + base:HTMLElement; + + linkState:(name:string) => void; + + setState(state:StateType, opts?:any):void; + + forceUpdate():void; + + abstract render(props:PropsType & ComponentProps, state:any):JSX.Element; + } + + function h<PropsType>(node:ComponentConstructor<PropsType, any>, params:PropsType, ...children:(JSX.Element|string)[]):JSX.Element; + function h(node:string, params:JSX.HTMLAttributes|JSX.SVGAttributes, ...children:(JSX.Element|string)[]):JSX.Element; + + function render(node:JSX.Element, parent:Element, merge?:boolean):Element; + + function rerender():void; + + function cloneElement(element:JSX.Element, props:any):JSX.Element; + + var options:{ + syncComponentUpdates?:boolean; + debounceRendering?:(render:() => void) => void; + vnode?:(vnode:VNode) => void; + event?:(event:Event) => Event; + }; +} + +declare module "preact" { + export = preact; +} + +declare namespace JSX { + interface Element extends preact.VNode { + + } + + interface ElementClass extends preact.Component<any, any> { + + } + + interface ElementAttributesProperty { + props:any; + } + + interface SVGAttributes { + clipPath?:string; + cx?:number | string; + cy?:number | string; + d?:string; + dx?:number | string; + dy?:number | string; + fill?:string; + fillOpacity?:number | string; + fontFamily?:string; + fontSize?:number | string; + fx?:number | string; + fy?:number | string; + gradientTransform?:string; + gradientUnits?:string; + markerEnd?:string; + markerMid?:string; + markerStart?:string; + offset?:number | string; + opacity?:number | string; + patternContentUnits?:string; + patternUnits?:string; + points?:string; + preserveAspectRatio?:string; + r?:number | string; + rx?:number | string; + ry?:number | string; + spreadMethod?:string; + stopColor?:string; + stopOpacity?:number | string; + stroke?:string; + strokeDasharray?:string; + strokeLinecap?:string; + strokeMiterlimit?:string; + strokeOpacity?:number | string; + strokeWidth?:number | string; + textAnchor?:string; + transform?:string; + version?:string; + viewBox?:string; + x1?:number | string; + x2?:number | string; + x?:number | string; + xlinkActuate?:string; + xlinkArcrole?:string; + xlinkHref?:string; + xlinkRole?:string; + xlinkShow?:string; + xlinkTitle?:string; + xlinkType?:string; + xmlBase?:string; + xmlLang?:string; + xmlSpace?:string; + y1?:number | string; + y2?:number | string; + y?:number | string; + } + + interface PathAttributes { + d:string; + } + + interface EventHandler<E extends Event> { + (event:E):void; + } + + type ClipboardEventHandler = EventHandler<ClipboardEvent>; + type CompositionEventHandler = EventHandler<CompositionEvent>; + type DragEventHandler = EventHandler<DragEvent>; + type FocusEventHandler = EventHandler<FocusEvent>; + type KeyboardEventHandler = EventHandler<KeyboardEvent>; + type MouseEventHandler = EventHandler<MouseEvent>; + type TouchEventHandler = EventHandler<TouchEvent>; + type UIEventHandler = EventHandler<UIEvent>; + type WheelEventHandler = EventHandler<WheelEvent>; + type AnimationEventHandler = EventHandler<AnimationEvent>; + type TransitionEventHandler = EventHandler<TransitionEvent>; + + type GenericEventHandler = EventHandler<Event>; + + interface DOMAttributed { + // Clipboard Events + onCopy?:ClipboardEventHandler; + onCut?:ClipboardEventHandler; + onPaste?:ClipboardEventHandler; + + // Composition Events + onCompositionEnd?:CompositionEventHandler; + onCompositionStart?:CompositionEventHandler; + onCompositionUpdate?:CompositionEventHandler; + + // Focus Events + onFocus?:FocusEventHandler; + onBlur?:FocusEventHandler; + + // Form Events + onChange?:GenericEventHandler; + onInput?:GenericEventHandler; + onSubmit?:GenericEventHandler; + + // Keyboard Events + onKeyDown?:KeyboardEventHandler; + onKeyPress?:KeyboardEventHandler; + onKeyUp?:KeyboardEventHandler; + + // Media Events + onAbort?:GenericEventHandler; + onCanPlay?:GenericEventHandler; + onCanPlayThrough?:GenericEventHandler; + onDurationChange?:GenericEventHandler; + onEmptied?:GenericEventHandler; + onEncrypted?:GenericEventHandler; + onEnded?:GenericEventHandler; + onLoadedData?:GenericEventHandler; + onLoadedMetadata?:GenericEventHandler; + onLoadStart?:GenericEventHandler; + onPause?:GenericEventHandler; + onPlay?:GenericEventHandler; + onPlaying?:GenericEventHandler; + onProgress?:GenericEventHandler; + onRateChange?:GenericEventHandler; + onSeeked?:GenericEventHandler; + onSeeking?:GenericEventHandler; + onStalled?:GenericEventHandler; + onSuspend?:GenericEventHandler; + onTimeUpdate?:GenericEventHandler; + onVolumeChange?:GenericEventHandler; + onWaiting?:GenericEventHandler; + + // MouseEvents + onClick?:MouseEventHandler; + onContextMenu?:MouseEventHandler; + onDoubleClick?:MouseEventHandler; + onDrag?:DragEventHandler; + onDragEnd?:DragEventHandler; + onDragEnter?:DragEventHandler; + onDragExit?:DragEventHandler; + onDragLeave?:DragEventHandler; + onDragOver?:DragEventHandler; + onDragStart?:DragEventHandler; + onDrop?:DragEventHandler; + onMouseDown?:MouseEventHandler; + onMouseEnter?:MouseEventHandler; + onMouseLeave?:MouseEventHandler; + onMouseMove?:MouseEventHandler; + onMouseOut?:MouseEventHandler; + onMouseOver?:MouseEventHandler; + onMouseUp?:MouseEventHandler; + + // Selection Events + onSelect?:GenericEventHandler; + + // Touch Events + onTouchCancel?:TouchEventHandler; + onTouchEnd?:TouchEventHandler; + onTouchMove?:TouchEventHandler; + onTouchStart?:TouchEventHandler; + + // UI Events + onScroll?:UIEventHandler; + + // Wheel Events + onWheel?:WheelEventHandler; + + // Animation Events + onAnimationStart?:AnimationEventHandler; + onAnimationEnd?:AnimationEventHandler; + onAnimationIteration?:AnimationEventHandler; + + // Transition Events + onTransitionEnd?:TransitionEventHandler; + } + + interface HTMLAttributes extends preact.PreactHTMLAttributes, DOMAttributed { + // Standard HTML Attributes + accept?:string; + acceptCharset?:string; + accessKey?:string; + action?:string; + allowFullScreen?:boolean; + allowTransparency?:boolean; + alt?:string; + async?:boolean; + autocomplete?:string; + autofocus?:boolean; + autoPlay?:boolean; + capture?:boolean; + cellPadding?:number | string; + cellSpacing?:number | string; + charSet?:string; + challenge?:string; + checked?:boolean; + class?:string; + className?:string; + cols?:number; + colSpan?:number; + content?:string; + contentEditable?:boolean; + contextMenu?:string; + controls?:boolean; + coords?:string; + crossOrigin?:string; + data?:string; + dateTime?:string; + default?:boolean; + defer?:boolean; + dir?:string; + disabled?:boolean; + download?:any; + draggable?:boolean; + encType?:string; + form?:string; + formAction?:string; + formEncType?:string; + formMethod?:string; + formNoValidate?:boolean; + formTarget?:string; + frameBorder?:number | string; + headers?:string; + height?:number | string; + hidden?:boolean; + high?:number; + href?:string; + hrefLang?:string; + for?:string; + httpEquiv?:string; + icon?:string; + id?:string; + inputMode?:string; + integrity?:string; + is?:string; + keyParams?:string; + keyType?:string; + kind?:string; + label?:string; + lang?:string; + list?:string; + loop?:boolean; + low?:number; + manifest?:string; + marginHeight?:number; + marginWidth?:number; + max?:number | string; + maxLength?:number; + media?:string; + mediaGroup?:string; + method?:string; + min?:number | string; + minLength?:number; + multiple?:boolean; + muted?:boolean; + name?:string; + noValidate?:boolean; + open?:boolean; + optimum?:number; + pattern?:string; + placeholder?:string; + poster?:string; + preload?:string; + radioGroup?:string; + readOnly?:boolean; + rel?:string; + required?:boolean; + role?:string; + rows?:number; + rowSpan?:number; + sandbox?:string; + scope?:string; + scoped?:boolean; + scrolling?:string; + seamless?:boolean; + selected?:boolean; + shape?:string; + size?:number; + sizes?:string; + span?:number; + spellCheck?:boolean; + src?:string; + srcset?:string; + srcDoc?:string; + srcLang?:string; + srcSet?:string; + start?:number; + step?:number | string; + style?:any; + summary?:string; + tabIndex?:number; + target?:string; + title?:string; + type?:string; + useMap?:string; + value?:string | string[]; + width?:number | string; + wmode?:string; + wrap?:string; + + // RDFa Attributes + about?:string; + datatype?:string; + inlist?:any; + prefix?:string; + property?:string; + resource?:string; + typeof?:string; + vocab?:string; + } + + interface IntrinsicElements { + // HTML + a:HTMLAttributes; + abbr:HTMLAttributes; + address:HTMLAttributes; + area:HTMLAttributes; + article:HTMLAttributes; + aside:HTMLAttributes; + audio:HTMLAttributes; + b:HTMLAttributes; + base:HTMLAttributes; + bdi:HTMLAttributes; + bdo:HTMLAttributes; + big:HTMLAttributes; + blockquote:HTMLAttributes; + body:HTMLAttributes; + br:HTMLAttributes; + button:HTMLAttributes; + canvas:HTMLAttributes; + caption:HTMLAttributes; + cite:HTMLAttributes; + code:HTMLAttributes; + col:HTMLAttributes; + colgroup:HTMLAttributes; + data:HTMLAttributes; + datalist:HTMLAttributes; + dd:HTMLAttributes; + del:HTMLAttributes; + details:HTMLAttributes; + dfn:HTMLAttributes; + dialog:HTMLAttributes; + div:HTMLAttributes; + dl:HTMLAttributes; + dt:HTMLAttributes; + em:HTMLAttributes; + embed:HTMLAttributes; + fieldset:HTMLAttributes; + figcaption:HTMLAttributes; + figure:HTMLAttributes; + footer:HTMLAttributes; + form:HTMLAttributes; + h1:HTMLAttributes; + h2:HTMLAttributes; + h3:HTMLAttributes; + h4:HTMLAttributes; + h5:HTMLAttributes; + h6:HTMLAttributes; + head:HTMLAttributes; + header:HTMLAttributes; + hr:HTMLAttributes; + html:HTMLAttributes; + i:HTMLAttributes; + iframe:HTMLAttributes; + img:HTMLAttributes; + input:HTMLAttributes; + ins:HTMLAttributes; + kbd:HTMLAttributes; + keygen:HTMLAttributes; + label:HTMLAttributes; + legend:HTMLAttributes; + li:HTMLAttributes; + link:HTMLAttributes; + main:HTMLAttributes; + map:HTMLAttributes; + mark:HTMLAttributes; + menu:HTMLAttributes; + menuitem:HTMLAttributes; + meta:HTMLAttributes; + meter:HTMLAttributes; + nav:HTMLAttributes; + noscript:HTMLAttributes; + object:HTMLAttributes; + ol:HTMLAttributes; + optgroup:HTMLAttributes; + option:HTMLAttributes; + output:HTMLAttributes; + p:HTMLAttributes; + param:HTMLAttributes; + picture:HTMLAttributes; + pre:HTMLAttributes; + progress:HTMLAttributes; + q:HTMLAttributes; + rp:HTMLAttributes; + rt:HTMLAttributes; + ruby:HTMLAttributes; + s:HTMLAttributes; + samp:HTMLAttributes; + script:HTMLAttributes; + section:HTMLAttributes; + select:HTMLAttributes; + small:HTMLAttributes; + source:HTMLAttributes; + span:HTMLAttributes; + strong:HTMLAttributes; + style:HTMLAttributes; + sub:HTMLAttributes; + summary:HTMLAttributes; + sup:HTMLAttributes; + table:HTMLAttributes; + tbody:HTMLAttributes; + td:HTMLAttributes; + textarea:HTMLAttributes; + tfoot:HTMLAttributes; + th:HTMLAttributes; + thead:HTMLAttributes; + time:HTMLAttributes; + title:HTMLAttributes; + tr:HTMLAttributes; + track:HTMLAttributes; + u:HTMLAttributes; + ul:HTMLAttributes; + "var":HTMLAttributes; + video:HTMLAttributes; + wbr:HTMLAttributes; + + //SVG + svg:SVGAttributes; + + circle:SVGAttributes; + clipPath:SVGAttributes; + defs:SVGAttributes; + ellipse:SVGAttributes; + feBlend:SVGAttributes; + feColorMatrix:SVGAttributes; + feComponentTransfer:SVGAttributes; + feComposite:SVGAttributes; + feConvolveMatrix:SVGAttributes; + feDiffuseLighting:SVGAttributes; + feDisplacementMap:SVGAttributes; + feFlood:SVGAttributes; + feGaussianBlur:SVGAttributes; + feImage:SVGAttributes; + feMerge:SVGAttributes; + feMergeNode:SVGAttributes; + feMorphology:SVGAttributes; + feOffset:SVGAttributes; + feSpecularLighting:SVGAttributes; + feTile:SVGAttributes; + feTurbulence:SVGAttributes; + filter:SVGAttributes; + foreignObject:SVGAttributes; + g:SVGAttributes; + image:SVGAttributes; + line:SVGAttributes; + linearGradient:SVGAttributes; + marker:SVGAttributes; + mask:SVGAttributes; + path:SVGAttributes; + pattern:SVGAttributes; + polygon:SVGAttributes; + polyline:SVGAttributes; + radialGradient:SVGAttributes; + rect:SVGAttributes; + stop:SVGAttributes; + symbol:SVGAttributes; + text:SVGAttributes; + tspan:SVGAttributes; + use:SVGAttributes; + } +} diff --git a/lib/vendor/preact b/lib/vendor/preact deleted file mode 120000 index 6111fdad3..000000000 --- a/lib/vendor/preact +++ /dev/null @@ -1 +0,0 @@ -../../thirdparty/preact/src/
\ No newline at end of file diff --git a/lib/vendor/preact.js b/lib/vendor/preact.js new file mode 100644 index 000000000..3b06bb6af --- /dev/null +++ b/lib/vendor/preact.js @@ -0,0 +1,469 @@ +!function(global, factory) { + 'object' == typeof exports && 'undefined' != typeof module ? factory(exports) : 'function' == typeof define && define.amd ? define([ 'exports' ], factory) : factory(global.preact = global.preact || {}); +}(this, function(exports) { + function VNode(nodeName, attributes, children) { + this.nodeName = nodeName; + this.attributes = attributes; + this.children = children; + this.key = attributes && attributes.key; + } + function h(nodeName, attributes) { + var children, lastSimple, child, simple, i; + for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]); + if (attributes && attributes.children) { + if (!stack.length) stack.push(attributes.children); + delete attributes.children; + } + while (stack.length) if ((child = stack.pop()) instanceof Array) for (i = child.length; i--; ) stack.push(child[i]); else if (null != child && child !== !1) { + if ('number' == typeof child || child === !0) child = String(child); + simple = 'string' == typeof child; + if (simple && lastSimple) children[children.length - 1] += child; else { + if (children) children.push(child); else children = [ child ]; + lastSimple = simple; + } + } + var p = new VNode(nodeName, attributes || void 0, children); + if (options.vnode) options.vnode(p); + return p; + } + function extend(obj, props) { + if (props) for (var i in props) obj[i] = props[i]; + return obj; + } + function clone(obj) { + return extend({}, obj); + } + function delve(obj, key) { + for (var p = key.split('.'), i = 0; i < p.length && obj; i++) obj = obj[p[i]]; + return obj; + } + function isFunction(obj) { + return 'function' == typeof obj; + } + function isString(obj) { + return 'string' == typeof obj; + } + function hashToClassName(c) { + var str = ''; + for (var prop in c) if (c[prop]) { + if (str) str += ' '; + str += prop; + } + return str; + } + function cloneElement(vnode, props) { + return h(vnode.nodeName, extend(clone(vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children); + } + function createLinkedState(component, key, eventPath) { + var path = key.split('.'), p0 = path[0]; + return function(e) { + var _component$setState; + var i, t = e && e.currentTarget || this, s = component.state, obj = s, v = isString(eventPath) ? delve(e, eventPath) : t.nodeName ? (t.nodeName + t.type).match(/^input(che|rad)/i) ? t.checked : t.value : e; + if (path.length > 1) { + for (i = 0; i < path.length - 1; i++) obj = obj[path[i]] || (obj[path[i]] = {}); + obj[path[i]] = v; + v = s[p0]; + } + component.setState((_component$setState = {}, _component$setState[p0] = v, _component$setState)); + }; + } + function enqueueRender(component) { + if (!component._dirty && (component._dirty = !0) && 1 == items.push(component)) (options.debounceRendering || defer)(rerender); + } + function rerender() { + var p, list = items; + items = []; + while (p = list.pop()) if (p._dirty) renderComponent(p); + } + function isFunctionalComponent(vnode) { + var nodeName = vnode && vnode.nodeName; + return nodeName && isFunction(nodeName) && !(nodeName.prototype && nodeName.prototype.render); + } + function buildFunctionalComponent(vnode, context) { + return vnode.nodeName(getNodeProps(vnode), context || EMPTY); + } + function isSameNodeType(node, vnode) { + if (isString(vnode)) return node instanceof Text; + if (isString(vnode.nodeName)) return isNamedNode(node, vnode.nodeName); + if (isFunction(vnode.nodeName)) return node._componentConstructor === vnode.nodeName || isFunctionalComponent(vnode); else ; + } + function isNamedNode(node, nodeName) { + return node.normalizedNodeName === nodeName || toLowerCase(node.nodeName) === toLowerCase(nodeName); + } + function getNodeProps(vnode) { + var defaultProps = vnode.nodeName.defaultProps, props = clone(vnode.attributes); + if (defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i]; + if (vnode.children) props.children = vnode.children; + return props; + } + function removeNode(node) { + var p = node.parentNode; + if (p) p.removeChild(node); + } + function setAccessor(node, name, value, old, isSvg) { + node[ATTR_KEY][name] = value; + if ('className' === name) name = 'class'; + if ('class' === name && value && 'object' == typeof value) value = hashToClassName(value); + if ('key' === name || 'children' === name || 'innerHTML' === name) ; else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) { + if (!value || isString(value) || isString(old)) node.style.cssText = value || ''; + if (value && 'object' == typeof value) { + if (!isString(old)) for (var i in old) if (!(i in value)) node.style[i] = ''; + for (var i in value) node.style[i] = 'number' == typeof value[i] && !NON_DIMENSION_PROPS[i] ? value[i] + 'px' : value[i]; + } + } else if ('dangerouslySetInnerHTML' === name) { + if (value) node.innerHTML = value.__html; + } else if ('o' == name[0] && 'n' == name[1]) { + var l = node._listeners || (node._listeners = {}); + name = toLowerCase(name.substring(2)); + if (value) { + if (!l[name]) node.addEventListener(name, eventProxy, !!NON_BUBBLING_EVENTS[name]); + } else if (l[name]) node.removeEventListener(name, eventProxy, !!NON_BUBBLING_EVENTS[name]); + l[name] = value; + } else if ('list' !== name && 'type' !== name && !isSvg && name in node) { + setProperty(node, name, null == value ? '' : value); + if (null == value || value === !1) node.removeAttribute(name); + } else { + var ns = isSvg && name.match(/^xlink\:?(.+)/); + if (null == value || value === !1) if (ns) node.removeAttributeNS('http://www.w3.org/1999/xlink', toLowerCase(ns[1])); else node.removeAttribute(name); else if ('object' != typeof value && !isFunction(value)) if (ns) node.setAttributeNS('http://www.w3.org/1999/xlink', toLowerCase(ns[1]), value); else node.setAttribute(name, value); + } + } + function setProperty(node, name, value) { + try { + node[name] = value; + } catch (e) {} + } + function eventProxy(e) { + return this._listeners[e.type](options.event && options.event(e) || e); + } + function collectNode(node) { + removeNode(node); + if (node instanceof Element) { + node._component = node._componentConstructor = null; + var _name = node.normalizedNodeName || toLowerCase(node.nodeName); + (nodes[_name] || (nodes[_name] = [])).push(node); + } + } + function createNode(nodeName, isSvg) { + var name = toLowerCase(nodeName), node = nodes[name] && nodes[name].pop() || (isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName)); + node.normalizedNodeName = name; + return node; + } + function flushMounts() { + var c; + while (c = mounts.pop()) if (c.componentDidMount) c.componentDidMount(); + } + function diff(dom, vnode, context, mountAll, parent, componentRoot) { + if (!diffLevel++) isSvgMode = parent instanceof SVGElement; + var ret = idiff(dom, vnode, context, mountAll); + if (parent && ret.parentNode !== parent) parent.appendChild(ret); + if (!--diffLevel && !componentRoot) flushMounts(); + return ret; + } + function idiff(dom, vnode, context, mountAll) { + var originalAttributes = vnode && vnode.attributes; + while (isFunctionalComponent(vnode)) vnode = buildFunctionalComponent(vnode, context); + if (null == vnode) vnode = ''; + if (isString(vnode)) { + if (dom) { + if (dom instanceof Text && dom.parentNode) { + dom.nodeValue = vnode; + return dom; + } + recollectNodeTree(dom); + } + return document.createTextNode(vnode); + } + if (isFunction(vnode.nodeName)) return buildComponentFromVNode(dom, vnode, context, mountAll); + var out = dom, nodeName = vnode.nodeName, prevSvgMode = isSvgMode; + if (!isString(nodeName)) nodeName = String(nodeName); + isSvgMode = 'svg' === nodeName ? !0 : 'foreignObject' === nodeName ? !1 : isSvgMode; + if (!dom) out = createNode(nodeName, isSvgMode); else if (!isNamedNode(dom, nodeName)) { + out = createNode(nodeName, isSvgMode); + while (dom.firstChild) out.appendChild(dom.firstChild); + recollectNodeTree(dom); + } + if (vnode.children && 1 === vnode.children.length && 'string' == typeof vnode.children[0] && 1 === out.childNodes.length && out.firstChild instanceof Text) out.firstChild.nodeValue = vnode.children[0]; else if (vnode.children || out.firstChild) innerDiffNode(out, vnode.children, context, mountAll); + var props = out[ATTR_KEY]; + if (!props) { + out[ATTR_KEY] = props = {}; + for (var a = out.attributes, i = a.length; i--; ) props[a[i].name] = a[i].value; + } + diffAttributes(out, vnode.attributes, props); + if (originalAttributes && 'function' == typeof originalAttributes.ref) (props.ref = originalAttributes.ref)(out); + isSvgMode = prevSvgMode; + return out; + } + function innerDiffNode(dom, vchildren, context, mountAll) { + var j, c, vchild, child, originalChildren = dom.childNodes, children = [], keyed = {}, keyedLen = 0, min = 0, len = originalChildren.length, childrenLen = 0, vlen = vchildren && vchildren.length; + if (len) for (var i = 0; i < len; i++) { + var _child = originalChildren[i], key = vlen ? (c = _child._component) ? c.__key : (c = _child[ATTR_KEY]) ? c.key : null : null; + if (key || 0 === key) { + keyedLen++; + keyed[key] = _child; + } else children[childrenLen++] = _child; + } + if (vlen) for (var i = 0; i < vlen; i++) { + vchild = vchildren[i]; + child = null; + var key = vchild.key; + if (null != key) { + if (keyedLen && key in keyed) { + child = keyed[key]; + keyed[key] = void 0; + keyedLen--; + } + } else if (!child && min < childrenLen) { + for (j = min; j < childrenLen; j++) { + c = children[j]; + if (c && isSameNodeType(c, vchild)) { + child = c; + children[j] = void 0; + if (j === childrenLen - 1) childrenLen--; + if (j === min) min++; + break; + } + } + if (!child && min < childrenLen && isFunction(vchild.nodeName) && mountAll) { + child = children[min]; + children[min++] = void 0; + } + } + child = idiff(child, vchild, context, mountAll); + if (child && child !== dom && child !== originalChildren[i]) dom.insertBefore(child, originalChildren[i] || null); + } + if (keyedLen) for (var i in keyed) if (keyed[i]) recollectNodeTree(keyed[i]); + if (min < childrenLen) removeOrphanedChildren(children); + } + function removeOrphanedChildren(children, unmountOnly) { + for (var i = children.length; i--; ) if (children[i]) recollectNodeTree(children[i], unmountOnly); + } + function recollectNodeTree(node, unmountOnly) { + var component = node._component; + if (component) unmountComponent(component, !unmountOnly); else { + if (node[ATTR_KEY] && node[ATTR_KEY].ref) node[ATTR_KEY].ref(null); + if (!unmountOnly) collectNode(node); + if (node.childNodes && node.childNodes.length) removeOrphanedChildren(node.childNodes, unmountOnly); + } + } + function diffAttributes(dom, attrs, old) { + for (var _name in old) if (!(attrs && _name in attrs) && null != old[_name]) setAccessor(dom, _name, null, old[_name], isSvgMode); + if (attrs) for (var _name2 in attrs) if (!(_name2 in old) || attrs[_name2] !== ('value' === _name2 || 'checked' === _name2 ? dom[_name2] : old[_name2])) setAccessor(dom, _name2, attrs[_name2], old[_name2], isSvgMode); + } + function collectComponent(component) { + var name = component.constructor.name, list = components[name]; + if (list) list.push(component); else components[name] = [ component ]; + } + function createComponent(Ctor, props, context) { + var inst = new Ctor(props, context), list = components[Ctor.name]; + Component.call(inst, props, context); + if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) { + inst.nextBase = list[i].nextBase; + list.splice(i, 1); + break; + } + return inst; + } + function setComponentProps(component, props, opts, context, mountAll) { + if (!component._disable) { + component._disable = !0; + if (component.__ref = props.ref) delete props.ref; + if (component.__key = props.key) delete props.key; + if (!component.base || mountAll) { + if (component.componentWillMount) component.componentWillMount(); + } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context); + if (context && context !== component.context) { + if (!component.prevContext) component.prevContext = component.context; + component.context = context; + } + if (!component.prevProps) component.prevProps = component.props; + component.props = props; + component._disable = !1; + if (0 !== opts) if (1 === opts || options.syncComponentUpdates !== !1 || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component); + if (component.__ref) component.__ref(component); + } + } + function renderComponent(component, opts, mountAll, isChild) { + if (!component._disable) { + var skip, rendered, inst, cbase, props = component.props, state = component.state, context = component.context, previousProps = component.prevProps || props, previousState = component.prevState || state, previousContext = component.prevContext || context, isUpdate = component.base, nextBase = component.nextBase, initialBase = isUpdate || nextBase, initialChildComponent = component._component; + if (isUpdate) { + component.props = previousProps; + component.state = previousState; + component.context = previousContext; + if (2 !== opts && component.shouldComponentUpdate && component.shouldComponentUpdate(props, state, context) === !1) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context); + component.props = props; + component.state = state; + component.context = context; + } + component.prevProps = component.prevState = component.prevContext = component.nextBase = null; + component._dirty = !1; + if (!skip) { + if (component.render) rendered = component.render(props, state, context); + if (component.getChildContext) context = extend(clone(context), component.getChildContext()); + while (isFunctionalComponent(rendered)) rendered = buildFunctionalComponent(rendered, context); + var toUnmount, base, childComponent = rendered && rendered.nodeName; + if (isFunction(childComponent)) { + inst = initialChildComponent; + var childProps = getNodeProps(rendered); + if (inst && inst.constructor === childComponent) setComponentProps(inst, childProps, 1, context); else { + toUnmount = inst; + inst = createComponent(childComponent, childProps, context); + inst.nextBase = inst.nextBase || nextBase; + inst._parentComponent = component; + component._component = inst; + setComponentProps(inst, childProps, 0, context); + renderComponent(inst, 1, mountAll, !0); + } + base = inst.base; + } else { + cbase = initialBase; + toUnmount = initialChildComponent; + if (toUnmount) cbase = component._component = null; + if (initialBase || 1 === opts) { + if (cbase) cbase._component = null; + base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0); + } + } + if (initialBase && base !== initialBase && inst !== initialChildComponent) { + var baseParent = initialBase.parentNode; + if (baseParent && base !== baseParent) baseParent.replaceChild(base, initialBase); + if (!cbase && !toUnmount && component._parentComponent) { + initialBase._component = null; + recollectNodeTree(initialBase); + } + } + if (toUnmount) unmountComponent(toUnmount, base !== initialBase); + component.base = base; + if (base && !isChild) { + var componentRef = component, t = component; + while (t = t._parentComponent) componentRef = t; + base._component = componentRef; + base._componentConstructor = componentRef.constructor; + } + } + if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip && component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext); + var fn, cb = component._renderCallbacks; + if (cb) while (fn = cb.pop()) fn.call(component); + if (!diffLevel && !isChild) flushMounts(); + } + } + function buildComponentFromVNode(dom, vnode, context, mountAll) { + var c = dom && dom._component, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode); + while (c && !isOwner && (c = c._parentComponent)) isOwner = c.constructor === vnode.nodeName; + if (c && isOwner && (!mountAll || c._component)) { + setComponentProps(c, props, 3, context, mountAll); + dom = c.base; + } else { + if (c && !isDirectOwner) { + unmountComponent(c, !0); + dom = oldDom = null; + } + c = createComponent(vnode.nodeName, props, context); + if (dom && !c.nextBase) c.nextBase = dom; + setComponentProps(c, props, 1, context, mountAll); + dom = c.base; + if (oldDom && dom !== oldDom) { + oldDom._component = null; + recollectNodeTree(oldDom); + } + } + return dom; + } + function unmountComponent(component, remove) { + var base = component.base; + component._disable = !0; + if (component.componentWillUnmount) component.componentWillUnmount(); + component.base = null; + var inner = component._component; + if (inner) unmountComponent(inner, remove); else if (base) { + if (base[ATTR_KEY] && base[ATTR_KEY].ref) base[ATTR_KEY].ref(null); + component.nextBase = base; + if (remove) { + removeNode(base); + collectComponent(component); + } + removeOrphanedChildren(base.childNodes, !remove); + } + if (component.__ref) component.__ref(null); + if (component.componentDidUnmount) component.componentDidUnmount(); + } + function Component(props, context) { + this._dirty = !0; + this.context = context; + this.props = props; + if (!this.state) this.state = {}; + } + function render(vnode, parent, merge) { + return diff(merge, vnode, {}, !1, parent); + } + var options = {}; + var stack = []; + var lcCache = {}; + var toLowerCase = function(s) { + return lcCache[s] || (lcCache[s] = s.toLowerCase()); + }; + var resolved = 'undefined' != typeof Promise && Promise.resolve(); + var defer = resolved ? function(f) { + resolved.then(f); + } : setTimeout; + var EMPTY = {}; + var ATTR_KEY = 'undefined' != typeof Symbol ? Symbol.for('preactattr') : '__preactattr_'; + var NON_DIMENSION_PROPS = { + boxFlex: 1, + boxFlexGroup: 1, + columnCount: 1, + fillOpacity: 1, + flex: 1, + flexGrow: 1, + flexPositive: 1, + flexShrink: 1, + flexNegative: 1, + fontWeight: 1, + lineClamp: 1, + lineHeight: 1, + opacity: 1, + order: 1, + orphans: 1, + strokeOpacity: 1, + widows: 1, + zIndex: 1, + zoom: 1 + }; + var NON_BUBBLING_EVENTS = { + blur: 1, + error: 1, + focus: 1, + load: 1, + resize: 1, + scroll: 1 + }; + var items = []; + var nodes = {}; + var mounts = []; + var diffLevel = 0; + var isSvgMode = !1; + var components = {}; + extend(Component.prototype, { + linkState: function(key, eventPath) { + var c = this._linkedStates || (this._linkedStates = {}); + return c[key + eventPath] || (c[key + eventPath] = createLinkedState(this, key, eventPath)); + }, + setState: function(state, callback) { + var s = this.state; + if (!this.prevState) this.prevState = clone(s); + extend(s, isFunction(state) ? state(s, this.props) : state); + if (callback) (this._renderCallbacks = this._renderCallbacks || []).push(callback); + enqueueRender(this); + }, + forceUpdate: function() { + renderComponent(this, 2); + }, + render: function() {} + }); + exports.h = h; + exports.cloneElement = cloneElement; + exports.Component = Component; + exports.render = render; + exports.rerender = rerender; + exports.options = options; +}); +//# sourceMappingURL=preact.js.map
\ No newline at end of file diff --git a/lib/wallet/renderHtml.ts b/lib/wallet/renderHtml.ts index 6d9823d71..022bce113 100644 --- a/lib/wallet/renderHtml.ts +++ b/lib/wallet/renderHtml.ts @@ -24,26 +24,26 @@ import {AmountJson, Contract} from "./types"; +let h = preact.h; + export function prettyAmount(amount: AmountJson) { let v = amount.value + amount.fraction / 1e6; return `${v.toFixed(2)} ${amount.currency}`; } -export function renderContract(contract: Contract): any { +export function renderContract(contract: Contract): JSX.Element { let merchantName = m("strong", contract.merchant.name); let amount = m("strong", prettyAmount(contract.amount)); - return m("div", {}, [ - m("p", - i18n.parts`${merchantName} + return h("div", {}, + h("p", {}, + i18n.parts`${merchantName} wants to enter a contract over ${amount} with you.`), - m("p", - i18n`You are about to purchase:`), - m('ul', - - contract.products.map( - (p: any) => m("li", - `${p.description}: ${prettyAmount(p.price)}`))) - ]); + h("p", {}, + i18n`You are about to purchase:`), + h('ul', {}, + ...contract.products.map( + (p: any) => h("li", {}, + `${p.description}: ${prettyAmount(p.price)}`)))); }
\ No newline at end of file diff --git a/pages/confirm-contract.html b/pages/confirm-contract.html index e7200910a..6e773f1b6 100644 --- a/pages/confirm-contract.html +++ b/pages/confirm-contract.html @@ -11,9 +11,10 @@ <script src="../lib/vendor/URI.js"></script> <script src="../lib/vendor/mithril.js"></script> + <script src="../lib/vendor/preact.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/vendor/jed.js"></script> --> <script src="../lib/i18n.js"></script> <script src="../i18n/strings.js"></script> <script src="../lib/module-trampoline.js"></script> diff --git a/pages/confirm-contract.tsx b/pages/confirm-contract.tsx index f162dca85..8e553b05b 100644 --- a/pages/confirm-contract.tsx +++ b/pages/confirm-contract.tsx @@ -22,113 +22,166 @@ */ -/// <reference path="../lib/decl/handlebars/handlebars.d.ts" /> -import MithrilComponent = _mithril.MithrilComponent; +/// <reference path="../lib/decl/preact.d.ts" /> 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") - ]); + +interface DetailState { + collapsed: boolean; +} + +interface DetailProps { + contract: Contract; +} + +let h = preact.h; + + +class Details extends preact.Component<DetailProps, DetailState> { + constructor() { + super(); + this.state = { + collapsed: true + }; + } + + render(props: DetailProps, state: DetailState) { + if (state.collapsed) { + return h("div", {}, + h("button", { + className: "linky", + onClick: () => { + this.setState({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}`))) - ]) - ]); + return h("div", {}, + h("button", { + className: "linky", + onClick: () => { + this.setState({collapsed: true}); + } + }, "show less details"), + h("div", {}, + "Accepted exchanges:", + h("ul", {}, + ...props.contract.exchanges.map( + e => h("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) - ]; +interface ContractPromptProps { + offer: any; +} + +interface ContractPromptState { + error: string|null; + payDisabled: boolean; +} + +class ContractPrompt extends preact.Component<ContractPromptProps, ContractPromptState> { + constructor() { + super(); + this.state = { + error: null, + payDisabled: true, } - }; + } - m.mount(document.getElementById("contract")!, Contract); + componentWillMount() { + this.checkPayment(); + } + + componentWillUnmount() { + // FIXME: abort running ops + } - function checkPayment() { - chrome.runtime.sendMessage({type: 'check-pay', detail: {offer}}, (resp) => { + checkPayment() { + let msg = { + type: 'check-pay', + detail: { + offer: this.props.offer + } + }; + chrome.runtime.sendMessage(msg, (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.`; + this.state.error = i18n`You have insufficient funds of the requested currency in your wallet.`; break; default: - error = `Error: ${resp.error}`; + this.state.error = `Error: ${resp.error}`; break; } - payDisabled = true; + this.state.payDisabled = true; } else { - payDisabled = false; - error = null; + this.state.payDisabled = false; + this.state.error = null; } - m.redraw(); - window.setTimeout(checkPayment, 300); + this.forceUpdate(); + window.setTimeout(() => this.checkPayment(), 300); }); } - checkPayment(); - - - function doPayment() { - let d = {offer}; + doPayment() { + let d = {offer: this.props.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."; + this.state.error = "You do not have enough coins of the" + + " requested currency."; break; default: - error = `Error: ${resp.error}`; + this.state.error = `Error: ${resp.error}`; break; } - m.redraw(); + preact.rerender(); return; } let c = d.offer.contract; console.log("contract", c); document.location.href = substituteFulfillmentUrl(c.fulfillment_url, - offer); + this.props.offer); }); } + + + render(props: ContractPromptProps, state: ContractPromptState) { + let c = props.offer.contract; + return h("div", {}, + renderContract(c), + h("button", + { + onClick: () => this.doPayment(), + disabled: state.payDisabled, + "className": "accept" + }, + i18n`Confirm Payment`), + (state.error ? h("p", + {className: "errorbox"}, + state.error) : h("p", "")), + h(Details, {contract: c}) + ); + } +} + + +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 prompt = h(ContractPrompt, {offer}); + preact.render(prompt, document.getElementById("contract")!); } |