├── test ├── lib │ └── angular │ │ └── version.txt ├── unit │ ├── controllersSpec.js │ ├── servicesSpec.js │ ├── filtersSpec.js │ └── directivesSpec.js ├── e2e │ ├── runner.html │ └── scenarios.js ├── testacular.conf.js └── testacular-e2e.conf.js ├── src ├── jade │ ├── tabs │ │ ├── rates.jade │ │ ├── exchange.jade │ │ ├── invite.jade │ │ ├── receive.jade │ │ ├── peers.jade │ │ ├── feed.jade │ │ ├── options.jade │ │ ├── tx.jade │ │ ├── unl.jade │ │ ├── balance │ │ │ └── effects.jade │ │ ├── security.jade │ │ └── history.jade │ ├── menu │ │ ├── advanced.jade │ │ └── wallet.jade │ ├── notification │ │ └── account.jade │ └── client │ │ └── status.jade ├── less │ ├── ripple │ │ ├── browser-chrome.less │ │ ├── browser-firefox.less │ │ ├── utils.less │ │ ├── buttons.less │ │ ├── overlay.less │ │ ├── desktop.less │ │ ├── combobox.less │ │ ├── forms.less │ │ └── pagemodes.less │ ├── elements │ │ └── README.md │ └── bootstrap │ │ ├── layouts.less │ │ ├── component-animations.less │ │ ├── utilities.less │ │ ├── grid.less │ │ ├── breadcrumbs.less │ │ ├── responsive-768px-979px.less │ │ ├── hero-unit.less │ │ ├── wells.less │ │ ├── responsive-1200px-min.less │ │ ├── close.less │ │ ├── accordion.less │ │ ├── pager.less │ │ ├── media.less │ │ ├── scaffolding.less │ │ ├── responsive.less │ │ ├── thumbnails.less │ │ ├── alerts.less │ │ ├── code.less │ │ ├── palette.less │ │ ├── bootstrap.less │ │ ├── responsive-utilities.less │ │ ├── tooltip.less │ │ ├── labels-badges.less │ │ ├── modals.less │ │ ├── carousel.less │ │ ├── pagination.less │ │ ├── progress-bars.less │ │ ├── popovers.less │ │ ├── style.less │ │ └── reset.less └── js │ ├── util │ ├── log.js │ ├── types.js │ └── base58.js │ ├── tabs │ ├── rates.js │ ├── exchange.js │ ├── invite.js │ ├── security.js │ ├── options.js │ ├── peers.js │ ├── unl.js │ ├── receive.js │ ├── feed.js │ ├── history.js │ ├── contacts.js │ ├── balance.js │ ├── login.js │ ├── register.js │ └── tx.js │ ├── directives │ ├── events.js │ ├── datalinks.js │ ├── effects.js │ ├── formatters.js │ └── charts.js │ ├── client │ ├── tab.js │ └── tabdefs.js │ ├── data │ ├── pairs.js │ ├── currencies.js │ └── iso4217.js │ ├── services │ ├── transactions.js │ ├── network.js │ ├── rippletxt.js │ ├── domainalias.js │ ├── popup.js │ └── ledger.js │ └── entry │ └── desktop.js ├── favicon.ico ├── deps ├── js │ ├── ripple-sjcl.js │ ├── store.js │ ├── bootstrap-popover.js │ ├── spin.js │ └── bootstrap-tab.js └── css │ └── ui-lightness │ └── images │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ ├── ui-icons_ffffff_256x240.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ └── ui-bg_highlight-soft_75_ffe45c_1x100.png ├── img ├── logo.png ├── bg_btm.png ├── bg_tile.png ├── bg_top.png ├── expanded.png ├── loading.png ├── logo_l.png ├── oblique.png ├── options.png ├── psm │ ├── red.png │ ├── green.png │ ├── yellow.png │ └── redcheck.png ├── sprite_j.png ├── throbber.gif ├── collapsed.png ├── drop-down.png ├── nav-hover.png ├── select-bg.png ├── subnav_active.png ├── subnav_shadow.png ├── transparent.gif ├── transparent_l.gif ├── select-bg-small.png ├── glyphicons-halflings.png ├── glyphicons-halflings-white.png ├── nav-icon.svg └── nav-icon-white.svg ├── compat └── ie │ ├── ws │ ├── ws-config.js │ └── WebSocketMain.swf │ ├── xdr │ └── xdr.js │ └── base64 │ └── base64.js ├── .gitignore ├── fonts ├── OpenSans-Bold-webfont.eot ├── OpenSans-Bold-webfont.ttf ├── OpenSans-Bold-webfont.woff ├── OpenSans-Italic-webfont.eot ├── OpenSans-Italic-webfont.ttf ├── OpenSans-Light-webfont.eot ├── OpenSans-Light-webfont.ttf ├── OpenSans-Light-webfont.woff ├── OpenSans-ExtraBold-webfont.eot ├── OpenSans-ExtraBold-webfont.ttf ├── OpenSans-Italic-webfont.woff ├── OpenSans-Regular-webfont.eot ├── OpenSans-Regular-webfont.ttf ├── OpenSans-Regular-webfont.woff ├── OpenSans-Semibold-webfont.eot ├── OpenSans-Semibold-webfont.ttf ├── OpenSans-Semibold-webfont.woff ├── OpenSans-BoldItalic-webfont.eot ├── OpenSans-BoldItalic-webfont.ttf ├── OpenSans-BoldItalic-webfont.woff ├── OpenSans-ExtraBold-webfont.woff ├── OpenSans-LightItalic-webfont.eot ├── OpenSans-LightItalic-webfont.ttf ├── OpenSans-LightItalic-webfont.woff ├── OpenSans-SemiboldItalic-webfont.eot ├── OpenSans-SemiboldItalic-webfont.ttf ├── OpenSans-ExtraBoldItalic-webfont.eot ├── OpenSans-ExtraBoldItalic-webfont.ttf ├── OpenSans-ExtraBoldItalic-webfont.woff └── OpenSans-SemiboldItalic-webfont.woff ├── Guardfile ├── package.json ├── LICENSE ├── config-example.js ├── README.md ├── index_debug.html └── index.html /test/lib/angular/version.txt: -------------------------------------------------------------------------------- 1 | 1.0.5 2 | -------------------------------------------------------------------------------- /src/jade/tabs/rates.jade: -------------------------------------------------------------------------------- 1 | section.panel.content 2 | -------------------------------------------------------------------------------- /src/jade/tabs/exchange.jade: -------------------------------------------------------------------------------- 1 | section.panel.content 2 | table.table 3 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/favicon.ico -------------------------------------------------------------------------------- /deps/js/ripple-sjcl.js: -------------------------------------------------------------------------------- 1 | // Import SJCL from ripple.js 2 | window.sjcl = ripple.sjcl; 3 | -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/logo.png -------------------------------------------------------------------------------- /compat/ie/ws/ws-config.js: -------------------------------------------------------------------------------- 1 | WEB_SOCKET_SWF_LOCATION = "compat/ie/ws/WebSocketMain.swf"; 2 | -------------------------------------------------------------------------------- /img/bg_btm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/bg_btm.png -------------------------------------------------------------------------------- /img/bg_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/bg_tile.png -------------------------------------------------------------------------------- /img/bg_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/bg_top.png -------------------------------------------------------------------------------- /img/expanded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/expanded.png -------------------------------------------------------------------------------- /img/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/loading.png -------------------------------------------------------------------------------- /img/logo_l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/logo_l.png -------------------------------------------------------------------------------- /img/oblique.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/oblique.png -------------------------------------------------------------------------------- /img/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/options.png -------------------------------------------------------------------------------- /img/psm/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/psm/red.png -------------------------------------------------------------------------------- /img/sprite_j.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/sprite_j.png -------------------------------------------------------------------------------- /img/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/throbber.gif -------------------------------------------------------------------------------- /img/collapsed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/collapsed.png -------------------------------------------------------------------------------- /img/drop-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/drop-down.png -------------------------------------------------------------------------------- /img/nav-hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/nav-hover.png -------------------------------------------------------------------------------- /img/psm/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/psm/green.png -------------------------------------------------------------------------------- /img/psm/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/psm/yellow.png -------------------------------------------------------------------------------- /img/select-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/select-bg.png -------------------------------------------------------------------------------- /img/psm/redcheck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/psm/redcheck.png -------------------------------------------------------------------------------- /img/subnav_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/subnav_active.png -------------------------------------------------------------------------------- /img/subnav_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/subnav_shadow.png -------------------------------------------------------------------------------- /img/transparent.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/transparent.gif -------------------------------------------------------------------------------- /img/transparent_l.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/transparent_l.gif -------------------------------------------------------------------------------- /img/select-bg-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/select-bg-small.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | js/.DS_Store 2 | npm-debug.log 3 | .DS_Store 4 | node_modules 5 | build/ 6 | config.js 7 | analytics.js -------------------------------------------------------------------------------- /src/jade/tabs/invite.jade: -------------------------------------------------------------------------------- 1 | include ../menu/wallet.jade 2 | section.panel.content(ng-controller="InviteCtrl") 3 | -------------------------------------------------------------------------------- /img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /compat/ie/ws/WebSocketMain.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/compat/ie/ws/WebSocketMain.swf -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Bold-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Italic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Light-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBold-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBold-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Regular-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Semibold-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Semibold-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-Semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-Semibold-webfont.woff -------------------------------------------------------------------------------- /img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-BoldItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBold-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-LightItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-SemiboldItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-SemiboldItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBoldItalic-webfont.eot -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBoldItalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBoldItalic-webfont.ttf -------------------------------------------------------------------------------- /fonts/OpenSans-ExtraBoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-ExtraBoldItalic-webfont.woff -------------------------------------------------------------------------------- /fonts/OpenSans-SemiboldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/fonts/OpenSans-SemiboldItalic-webfont.woff -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /src/less/ripple/browser-chrome.less: -------------------------------------------------------------------------------- 1 | input[type=number]::-webkit-inner-spin-button, 2 | input[type=number]::-webkit-outer-spin-button { 3 | -webkit-appearance: none; 4 | margin: 0; 5 | } -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /src/less/ripple/browser-firefox.less: -------------------------------------------------------------------------------- 1 | select:focus, option:focus, select::-moz-focus-inner, option::-moz-focus-inner { 2 | outline: none; 3 | } 4 | 5 | :active, :focus { 6 | outline: none; 7 | } -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /deps/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/ripple-client/develop/deps/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /src/less/elements/README.md: -------------------------------------------------------------------------------- 1 | LESS Elements 2 | ============= 3 | 4 | A set of useful mixins for LESS, the CSS pre-processor: 5 | 6 | More information and usage examples over at: 7 | 8 | TextMate bundle: 9 | -------------------------------------------------------------------------------- /src/js/util/log.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Print an exception for debug purposes. 3 | * 4 | * Includes some logic to try and log a stack in various browsers. 5 | */ 6 | exports.exception = function (exception) { 7 | console.log("function" === typeof exception.getStack ? exception.getStack() : exception.stack); 8 | }; 9 | 10 | -------------------------------------------------------------------------------- /test/unit/controllersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for controllers go here */ 4 | 5 | /* 6 | describe('MyCtrl1', function(){ 7 | var myCtrl1; 8 | 9 | beforeEach(function(){ 10 | myCtrl1 = new MyCtrl1(); 11 | }); 12 | 13 | 14 | it('should ....', function() { 15 | //spec body 16 | }); 17 | }); 18 | */ 19 | -------------------------------------------------------------------------------- /test/e2e/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End2end Test Runner 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/unit/servicesSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for services go here */ 4 | 5 | /* 6 | describe('service', function() { 7 | beforeEach(module('myApp.services')); 8 | 9 | 10 | describe('version', function() { 11 | it('should return current version', inject(function(version) { 12 | expect(version).toEqual('0.1'); 13 | })); 14 | }); 15 | }); 16 | */ 17 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # 2 | # This is the Guardfile for use with guard-livereload. 3 | # 4 | # Once the new official livereload-cli (Node.js-based) is out, we'll get rid of this. 5 | # 6 | 7 | guard 'livereload' do 8 | watch(%r{build/dist/ripple-client-desktop-debug.js}) 9 | watch(%r{build/dist/deps-debug.js}) 10 | watch(%r{build/.+\.css}) 11 | watch(%r{config\.js}) 12 | watch(%r{.+\.html}) 13 | end 14 | -------------------------------------------------------------------------------- /src/jade/menu/advanced.jade: -------------------------------------------------------------------------------- 1 | nav(rp-off-canvas-menu) 2 | h2(ng-bind="$route.current.tabName | rpucfirst") 3 | ul 4 | li(ng-class="{active: $route.current.tabName == 'trust'}") 5 | a(href="#/trust") Trust 6 | li(ng-class="{active: $route.current.tabName == 'trade'}") 7 | a(href="#/trade") Trade 8 | li(ng-class="{active: $route.current.tabName == 'options'}") 9 | a(href="#/options") Options -------------------------------------------------------------------------------- /src/js/tabs/rates.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var RatesTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(RatesTab, Tab); 10 | 11 | RatesTab.prototype.parent = 'wallet'; 12 | 13 | RatesTab.prototype.generateHtml = function () 14 | { 15 | return require('../../jade/tabs/rates.jade')(); 16 | }; 17 | 18 | module.exports = RatesTab; 19 | -------------------------------------------------------------------------------- /src/less/bootstrap/layouts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Layouts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container (centered, fixed-width layouts) 7 | .container { 8 | .container-fixed(); 9 | } 10 | 11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content) 12 | .container-fluid { 13 | padding-right: @gridGutterWidth; 14 | padding-left: @gridGutterWidth; 15 | .clearfix(); 16 | } -------------------------------------------------------------------------------- /src/js/tabs/exchange.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var ExchangeTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(ExchangeTab, Tab); 10 | 11 | ExchangeTab.prototype.parent = 'wallet'; 12 | 13 | ExchangeTab.prototype.generateHtml = function () 14 | { 15 | return require('../../jade/tabs/exchange.jade')(); 16 | }; 17 | 18 | module.exports = ExchangeTab; 19 | -------------------------------------------------------------------------------- /test/testacular.conf.js: -------------------------------------------------------------------------------- 1 | basePath = '../'; 2 | 3 | files = [ 4 | JASMINE, 5 | JASMINE_ADAPTER, 6 | 'build/dist/deps-debug.js', 7 | 'test/lib/angular/angular-mocks.js', 8 | 'config.js', 9 | 'build/dist/ripple-client-desktop-debug.js', 10 | 'test/unit/**/*.js' 11 | ]; 12 | 13 | autoWatch = true; 14 | 15 | browsers = ['Chrome']; 16 | 17 | junitReporter = { 18 | outputFile: 'test_out/unit.xml', 19 | suite: 'unit' 20 | }; 21 | -------------------------------------------------------------------------------- /src/less/bootstrap/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | 6 | .fade { 7 | opacity: 0; 8 | .transition(opacity .15s linear); 9 | &.in { 10 | opacity: 1; 11 | } 12 | } 13 | 14 | .collapse { 15 | position: relative; 16 | height: 0; 17 | overflow: hidden; 18 | .transition(height .35s ease); 19 | &.in { 20 | height: auto; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/js/directives/events.js: -------------------------------------------------------------------------------- 1 | /** 2 | * EVENTS 3 | * 4 | * Angular-powered event handling directives go into this file. 5 | */ 6 | 7 | var module = angular.module('events', []); 8 | 9 | /** 10 | * Handle ENTER key press. 11 | */ 12 | module.directive('ngEnter', function() { 13 | return function(scope, elm, attrs) { 14 | elm.bind('keypress', function(e) { 15 | if (e.charCode === 13) scope.$apply(attrs.ngEnter); 16 | }); 17 | }; 18 | }); 19 | -------------------------------------------------------------------------------- /src/jade/tabs/receive.jade: -------------------------------------------------------------------------------- 1 | section.single.content(ng-controller="ReceiveCtrl") 2 | p.literal This is your public address. Give this address to other users so they can send you money. 3 | hr 4 | .address 5 | span#receive-address(ng-bind="address") 6 | .qr#qr-code 7 | p.literal(ng-show="!copy_supported") 8 | | Tip:  9 | a.select(rp-select-el="receive-address") Select 10 | | and copy using Ctrl+C. 11 | form(ng-show="copy_supported") 12 | button.btn.btn-success Copy Address -------------------------------------------------------------------------------- /src/less/bootstrap/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Quick floats 7 | .pull-right { 8 | float: right; 9 | } 10 | .pull-left { 11 | float: left; 12 | } 13 | 14 | // Toggling content 15 | .hide { 16 | display: none; 17 | } 18 | .show { 19 | display: block; 20 | } 21 | 22 | // Visibility 23 | .invisible { 24 | visibility: hidden; 25 | } 26 | 27 | // For Affix plugin 28 | .affix { 29 | position: fixed; 30 | } 31 | -------------------------------------------------------------------------------- /src/jade/menu/wallet.jade: -------------------------------------------------------------------------------- 1 | nav(rp-off-canvas-menu) 2 | h2(ng-bind="$route.current.tabName | rpucfirst") 3 | ul 4 | li(ng-class="{active: $route.current.tabName == 'balance'}") 5 | a(href="#/balance") Balance 6 | li(ng-class="{active: $route.current.tabName == 'history'}") 7 | a(href="#/history") History 8 | li(ng-class="{active: $route.current.tabName == 'contacts'}") 9 | a(href="#/contacts") Contacts 10 | li(ng-class="{active: $route.current.tabName == 'security'}") 11 | a(href="#/security") Security -------------------------------------------------------------------------------- /src/less/bootstrap/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Fixed (940px) 7 | #grid > .core(@gridColumnWidth, @gridGutterWidth); 8 | 9 | // Fluid (940px) 10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); 11 | 12 | // Reset utility classes due to specificity 13 | [class*="span"].hide, 14 | .row-fluid [class*="span"].hide { 15 | display: none; 16 | } 17 | 18 | [class*="span"].pull-right, 19 | .row-fluid [class*="span"].pull-right { 20 | float: right; 21 | } 22 | -------------------------------------------------------------------------------- /src/less/bootstrap/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: 8px 15px; 8 | margin: 0 0 @baseLineHeight; 9 | list-style: none; 10 | background-color: #f5f5f5; 11 | .border-radius(@baseBorderRadius); 12 | li { 13 | display: inline-block; 14 | .ie7-inline-block(); 15 | text-shadow: 0 1px 0 @white; 16 | } 17 | .divider { 18 | padding: 0 5px; 19 | color: #ccc; 20 | } 21 | .active { 22 | color: @grayLight; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/unit/filtersSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for filters go here */ 4 | 5 | /* 6 | describe('filter', function() { 7 | beforeEach(module('myApp.filters')); 8 | 9 | 10 | describe('interpolate', function() { 11 | beforeEach(module(function($provide) { 12 | $provide.value('version', 'TEST_VER'); 13 | })); 14 | 15 | 16 | it('should replace VERSION', inject(function(interpolateFilter) { 17 | expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after'); 18 | })); 19 | }); 20 | }); 21 | */ 22 | -------------------------------------------------------------------------------- /src/less/bootstrap/responsive-768px-979px.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Tablet to desktop 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 768px) and (max-width: 979px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768); 16 | 17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth 18 | 19 | } 20 | -------------------------------------------------------------------------------- /img/nav-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /img/nav-icon-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/unit/directivesSpec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* jasmine specs for directives go here */ 4 | 5 | /* 6 | describe('directives', function() { 7 | beforeEach(module('myApp.directives')); 8 | 9 | describe('app-version', function() { 10 | it('should print current version', function() { 11 | module(function($provide) { 12 | $provide.value('version', 'TEST_VER'); 13 | }); 14 | inject(function($compile, $rootScope) { 15 | var element = $compile('')($rootScope); 16 | expect(element.text()).toEqual('TEST_VER'); 17 | }); 18 | }); 19 | }); 20 | }); 21 | */ 22 | -------------------------------------------------------------------------------- /src/less/bootstrap/hero-unit.less: -------------------------------------------------------------------------------- 1 | // 2 | // Hero unit 3 | // -------------------------------------------------- 4 | 5 | 6 | .hero-unit { 7 | padding: 60px; 8 | margin-bottom: 30px; 9 | font-size: 18px; 10 | font-weight: 200; 11 | line-height: @baseLineHeight * 1.5; 12 | color: @heroUnitLeadColor; 13 | background-color: @heroUnitBackground; 14 | .border-radius(6px); 15 | h1 { 16 | margin-bottom: 0; 17 | font-size: 60px; 18 | line-height: 1; 19 | color: @heroUnitHeadingColor; 20 | letter-spacing: -1px; 21 | } 22 | li { 23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/js/directives/datalinks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DATALINKS 3 | * 4 | * Data-centric links for things like transactions, accounts etc. 5 | */ 6 | 7 | var module = angular.module('datalinks', []); 8 | 9 | module.directive('rpLinkTx', ['$location', function ($location) { 10 | return { 11 | restrict: 'A', 12 | link: function ($scope, element, attr) { 13 | var url; 14 | $scope.$watch(attr.rpLinkTx, function (hash) { 15 | url = "/tx?id="+hash; 16 | }); 17 | element.click(function () { 18 | $scope.$apply(function () { 19 | if (url) $location.url(url); 20 | }); 21 | }); 22 | } 23 | }; 24 | }]); 25 | -------------------------------------------------------------------------------- /src/jade/tabs/peers.jade: -------------------------------------------------------------------------------- 1 | section.panel.content(ng-controller="PeerCtrl") 2 | form(name="addForm") 3 | label(for='unl_hanko') Domain or Hanko: 4 | .unl_key 5 | input#unl_key(name='unl_key', type='text', step='any', ng-model='unl_key', required) 6 | label(for='unl_note') Comment (Optional): 7 | .unl_note 8 | input#unl_note(name='unl_note', type='text', step='any', ng-model='unl_note', unl_note, required) 9 | .submitsection 10 | button.btn.btn-info(type='submit', ng-click='add()', ng-disabled='addForm.$invalid') Add Peer 11 | table.table.table-striped 12 | tr 13 | th # 14 | th IP 15 | th Port 16 | th Version 17 | -------------------------------------------------------------------------------- /src/less/bootstrap/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @wellBackground; 12 | border: 1px solid darken(@wellBackground, 7%); 13 | .border-radius(@baseBorderRadius); 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-large { 23 | padding: 24px; 24 | .border-radius(@borderRadiusLarge); 25 | } 26 | .well-small { 27 | padding: 9px; 28 | .border-radius(@borderRadiusSmall); 29 | } 30 | -------------------------------------------------------------------------------- /test/testacular-e2e.conf.js: -------------------------------------------------------------------------------- 1 | basePath = '../'; 2 | 3 | files = [ 4 | ANGULAR_SCENARIO, 5 | ANGULAR_SCENARIO_ADAPTER, 6 | {pattern: 'index_debug.html', included: false}, 7 | {pattern: 'build/css/*.css', included: false}, 8 | {pattern: 'build/dist/*.js', included: false}, 9 | {pattern: '*.js', included: false, watch: false}, 10 | {pattern: 'fonts/*', included: false, watch: false}, 11 | {pattern: 'deps/js/modernizr-2.5.3.min.js', included: false, watch: false}, 12 | {pattern: 'img/*', included: false, watch: false}, 13 | 'test/e2e/**/*.js' 14 | ]; 15 | 16 | autoWatch = false; 17 | 18 | browsers = ['Chrome']; 19 | 20 | junitReporter = { 21 | outputFile: 'test_out/e2e.xml', 22 | suite: 'e2e' 23 | }; 24 | -------------------------------------------------------------------------------- /src/js/tabs/invite.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var webutil = require('../util/web'); 3 | var Tab = require('../client/tab').Tab; 4 | 5 | var InviteTab = function () 6 | { 7 | Tab.call(this); 8 | }; 9 | 10 | util.inherits(InviteTab, Tab); 11 | 12 | InviteTab.prototype.mainMenu = 'wallet'; 13 | 14 | InviteTab.prototype.generateHtml = function () 15 | { 16 | return require('../../jade/tabs/invite.jade')(); 17 | }; 18 | 19 | InviteTab.prototype.angular = function (module) { 20 | module.controller('InviteCtrl', ['$scope', 'rpId', 21 | function ($scope, $id) 22 | { 23 | if (!$id.loginStatus) return $id.goId(); 24 | 25 | 26 | }]); 27 | }; 28 | 29 | module.exports = InviteTab; 30 | -------------------------------------------------------------------------------- /src/less/bootstrap/responsive-1200px-min.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Large desktop and up 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 1200px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); 16 | 17 | // Thumbnails 18 | .thumbnails { 19 | margin-left: -@gridGutterWidth1200; 20 | } 21 | .thumbnails > li { 22 | margin-left: @gridGutterWidth1200; 23 | } 24 | .row-fluid .thumbnails { 25 | margin-left: 0; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ripple-client", 3 | "version": "0.2.24", 4 | "description": "Client for the Ripple payment network", 5 | "dependencies": { 6 | "async": "~0.2.9", 7 | "extend": "~1.1.3", 8 | "grunt": "~0.4.1", 9 | "grunt-webpack": "~0.10.5", 10 | "grunt-recess": "~0.3.3", 11 | "grunt-contrib-concat": "~0.3.0", 12 | "grunt-contrib-uglify": "~0.2.2", 13 | "grunt-contrib-watch": "~0.4.4", 14 | "jade-loader": "~0.5.1", 15 | "jshint-loader": "~0.5.0", 16 | "webpack": "~0.10.0-beta24" 17 | }, 18 | "scripts": {}, 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/rippleFoundation/ripple-client.git" 22 | }, 23 | "readmeFilename": "README" 24 | } 25 | -------------------------------------------------------------------------------- /src/js/client/tab.js: -------------------------------------------------------------------------------- 1 | var util = require('util'), 2 | webutil = require('../util/web'), 3 | log = require('../util/log'); 4 | 5 | var Tab = function (config) 6 | { 7 | }; 8 | 9 | Tab.prototype.pageMode = 'default'; 10 | 11 | Tab.prototype.mainMenu = 'none'; 12 | 13 | /** 14 | * AngularJS dependencies. 15 | * 16 | * List any controllers the tab uses here. 17 | */ 18 | Tab.prototype.angularDeps = [ 19 | // Directives 20 | 'charts', 21 | 'effects', 22 | 'events', 23 | 'fields', 24 | 'formatters', 25 | 'directives', 26 | 'validators', 27 | 'datalinks', 28 | // Filters 29 | 'filters' 30 | ]; 31 | 32 | /** 33 | * Other routes this tab should handle. 34 | */ 35 | Tab.prototype.aliases = []; 36 | 37 | exports.Tab = Tab; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012,2013 OpenCoin, Inc. 2 | 3 | Permission to use, copy, modify, and distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /src/less/bootstrap/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: 20px; 9 | font-weight: bold; 10 | line-height: @baseLineHeight; 11 | color: @black; 12 | text-shadow: 0 1px 0 rgba(255,255,255,1); 13 | .opacity(20); 14 | &:hover { 15 | color: @black; 16 | text-decoration: none; 17 | cursor: pointer; 18 | .opacity(40); 19 | } 20 | } 21 | 22 | // Additional properties for button version 23 | // iOS requires the button element instead of an anchor tag. 24 | // If you want the anchor version, it requires `href="#"`. 25 | button.close { 26 | padding: 0; 27 | cursor: pointer; 28 | background: transparent; 29 | border: 0; 30 | -webkit-appearance: none; 31 | } -------------------------------------------------------------------------------- /src/less/bootstrap/accordion.less: -------------------------------------------------------------------------------- 1 | // 2 | // Accordion 3 | // -------------------------------------------------- 4 | 5 | 6 | // Parent container 7 | .accordion { 8 | margin-bottom: @baseLineHeight; 9 | } 10 | 11 | // Group == heading + body 12 | .accordion-group { 13 | margin-bottom: 2px; 14 | border: 1px solid #e5e5e5; 15 | .border-radius(@baseBorderRadius); 16 | } 17 | .accordion-heading { 18 | border-bottom: 0; 19 | } 20 | .accordion-heading .accordion-toggle { 21 | display: block; 22 | padding: 8px 15px; 23 | } 24 | 25 | // General toggle styles 26 | .accordion-toggle { 27 | cursor: pointer; 28 | } 29 | 30 | // Inner needs the styles because you can't animate properly with any styles on the element 31 | .accordion-inner { 32 | padding: 9px 15px; 33 | border-top: 1px solid #e5e5e5; 34 | } 35 | -------------------------------------------------------------------------------- /src/js/data/pairs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ripple trading default currency pairs. 3 | * 4 | * This list is a bit arbitrary, but it's basically the Majors [1] from forex 5 | * trading with some XRP pairs added. 6 | * 7 | * [1] http://en.wikipedia.org/wiki/Currency_pair#The_Majors 8 | */ 9 | module.exports = [ 10 | {name: 'BTC/XRP', order: 1}, 11 | {name: 'USD/XRP', order: 1}, 12 | {name: 'EUR/XRP', order: 1}, 13 | {name: 'JPY/XRP', order: 0}, 14 | {name: 'GBP/XRP', order: 0}, 15 | {name: 'AUD/XRP', order: 0}, 16 | {name: 'CHF/XRP', order: 0}, 17 | {name: 'CAD/XRP', order: 0}, 18 | {name: 'CNY/XRP', order: 0}, 19 | {name: 'BTC/USD', order: 0}, 20 | {name: 'BTC/EUR', order: 0}, 21 | {name: 'EUR/USD', order: 0}, 22 | {name: 'USD/JPY', order: 0}, 23 | {name: 'GBP/USD', order: 0}, 24 | {name: 'AUD/USD', order: 0}, 25 | {name: 'USD/CHF', order: 0} 26 | ]; 27 | -------------------------------------------------------------------------------- /src/less/bootstrap/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | margin: @baseLineHeight 0; 8 | list-style: none; 9 | text-align: center; 10 | .clearfix(); 11 | } 12 | .pager li { 13 | display: inline; 14 | } 15 | .pager li > a, 16 | .pager li > span { 17 | display: inline-block; 18 | padding: 5px 14px; 19 | background-color: #fff; 20 | border: 1px solid #ddd; 21 | .border-radius(15px); 22 | } 23 | .pager li > a:hover { 24 | text-decoration: none; 25 | background-color: #f5f5f5; 26 | } 27 | .pager .next > a, 28 | .pager .next > span { 29 | float: right; 30 | } 31 | .pager .previous > a, 32 | .pager .previous > span { 33 | float: left; 34 | } 35 | .pager .disabled > a, 36 | .pager .disabled > a:hover, 37 | .pager .disabled > span { 38 | color: @grayLight; 39 | background-color: #fff; 40 | cursor: default; 41 | } -------------------------------------------------------------------------------- /src/js/directives/effects.js: -------------------------------------------------------------------------------- 1 | /** 2 | * EFFECTS 3 | * 4 | * Angular-powered animation and visual effects directives go into this file. 5 | */ 6 | 7 | var module = angular.module('effects', []); 8 | 9 | /** 10 | * Animate element creation 11 | */ 12 | module.directive('rpAnimate', function() { 13 | return { 14 | restrict: 'A', 15 | link: function(scope, elm, attrs) { 16 | if (attrs.rpAnimate !== "rp-animate" && !scope.$eval(attrs.rpAnimate)) return; 17 | elm = jQuery(elm); 18 | elm.hide(); 19 | elm.fadeIn(600); 20 | elm.css('background-color', '#E2F5E4'); 21 | elm.addClass('rp-animate-during rp-animate'); 22 | elm.animate({ 23 | 'background-color': '#fff' 24 | }, { 25 | duration: 600, 26 | complete: function () { 27 | elm.removeClass('rp-animate-during').addClass('rp-animate-after'); 28 | } 29 | }); 30 | } 31 | }; 32 | }); 33 | -------------------------------------------------------------------------------- /config-example.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ripple Client Configuration 3 | * 4 | * Copy this file to config.js and edit to suit your preferences. 5 | */ 6 | var Options = { 7 | server: { 8 | "trusted" : true, 9 | "websocket_ip" : "s1.ripple.com", 10 | "websocket_port" : 51233, 11 | "websocket_ssl" : true 12 | // "websocket_ip" : "127.0.0.1", 13 | // "websocket_port" : 5006, 14 | // "websocket_ssl" : false 15 | }, 16 | blobvault : "https://blobvault.payward.com", 17 | 18 | // If set, login will persist across sessions (page reload). This is mostly 19 | // intended for developers, be careful about using this in a real setting. 20 | persistent_auth : false, 21 | 22 | // Number of transactions each page has in balance tab notifications 23 | transactions_per_page: 50 24 | }; 25 | 26 | // Load client-side overrides 27 | if (store.enabled) { 28 | $.extend(true, Options, JSON.parse(store.get('ripple_settings') || "{}")); 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/jade/notification/account.jade: -------------------------------------------------------------------------------- 1 | case tx.type 2 | when "sent" 3 | .type-info You sent  4 | span(title="{{tx.counterparty}}") {{tx.counterparty | rpcontactname}}  5 | span.number {{tx.amount | rpamount}}  6 | span.currency {{tx.currency}} 7 | when "received" 8 | .type-success 9 | span(title="{{tx.counterparty}}") {{tx.counterparty | rpcontactname}} sent you  10 | span.number {{tx.amount | rpamount}}  11 | span.currency {{tx.currency}} 12 | when "trusted" 13 | .type-success 14 | span(title="{{tx.counterparty}}") {{tx.counterparty | rpcontactname}} now trusts you for  15 | span.number {{tx.amount | rpamount}}  16 | span.currency {{tx.currency}} 17 | when "trusting" 18 | .type-success 19 | span(title="{{tx.counterparty}}") You now trust {{tx.counterparty | rpcontactname}} for  20 | span.number {{tx.amount | rpamount}}  21 | span.currency {{tx.currency}} -------------------------------------------------------------------------------- /src/jade/tabs/feed.jade: -------------------------------------------------------------------------------- 1 | section.panel.content(ng-controller="FeedCtrl") 2 | table.spaceTable 3 | tr 4 | td Ledger 5 | input#FeedLedgerCheckbox(type="checkbox", ng-model="ledgerCheck") 6 | td Transactions 7 | input#FeedTransactionsCheckbox(type="checkbox", ng-click='toggle_feed_transactions()', ng-model="transCheck") 8 | td Server 9 | input#FeedServerCheckbox(type="checkbox", ng-click='toggle_feed_server()', ng-model="serverCheck") 10 | td: button.btn.btn-danger.btn-small(ng-click='clear_feed()') Clear Feed 11 | table.table 12 | thead 13 | tr 14 | th.date Date 15 | th.type Type 16 | th.msg Message 17 | tbody 18 | tr(ng-repeat="entry in feed", class="{{entry.type}}") 19 | td.date {{entry.date}} 20 | td.type {{entry.type}} 21 | td.msg {{entry.msg}} 22 | tr(ng-show="!feed.length") 23 | td(colspan="3") 24 | span.literal Nothing in feed yet. So hungry. -------------------------------------------------------------------------------- /src/less/ripple/utils.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Useful helper to create virtual elements like a:after and a:before 3 | */ 4 | .virtualel { 5 | content: ""; 6 | display: block; 7 | } 8 | 9 | 10 | .transition-multi(@elements) { 11 | -webkit-transition: @elements; 12 | -moz-transition: @elements; 13 | transition: @elements; 14 | } 15 | 16 | @-webkit-keyframes fadebg { 17 | 0% { } 18 | 100% { background-color: transparent } 19 | } 20 | @-ms-keyframes fadebg { 21 | 0% { } 22 | 100% { background-color: transparent } 23 | } 24 | @-moz-keyframes fadebg { 25 | 0% { } 26 | 100% { background-color: transparent } 27 | } 28 | @keyframes fadebg { 29 | 0% { } 30 | 100% { background-color: transparent } 31 | } 32 | 33 | .animation(@tween:fadebg, @duration:1s, @fillmode:forwards) { 34 | -webkit-animation: @tween @duration 1; 35 | -moz-animation: @tween @duration 1; 36 | -ms-animation: @tween @duration 1; 37 | animation: @tween @duration 1; 38 | -webkit-animation-fill-mode: @fillmode; 39 | } -------------------------------------------------------------------------------- /src/js/tabs/security.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var SecurityTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(SecurityTab, Tab); 10 | 11 | SecurityTab.prototype.mainMenu = 'wallet'; 12 | 13 | SecurityTab.prototype.generateHtml = function () 14 | { 15 | return require('../../jade/tabs/security.jade')(); 16 | }; 17 | 18 | SecurityTab.prototype.angular = function (module) { 19 | module.controller('SecurityCtrl', ['$scope', 'rpId', 'rpBlob', 20 | function ($scope, $id, $blob) 21 | { 22 | if (!$id.loginStatus) return $id.goId(); 23 | 24 | $scope.$watch('userBlob', updateEnc, true); 25 | 26 | function updateEnc() 27 | { 28 | if ("string" === typeof $id.username && 29 | "string" === typeof $id.password && 30 | $scope.userBlob) { 31 | $scope.enc = $blob.enc($id.username.toLowerCase(), $id.password, $scope.userBlob); 32 | } 33 | } 34 | }]); 35 | }; 36 | 37 | module.exports = SecurityTab; 38 | -------------------------------------------------------------------------------- /src/less/bootstrap/media.less: -------------------------------------------------------------------------------- 1 | // Media objects 2 | // Source: http://stubbornella.org/content/?p=497 3 | // -------------------------------------------------- 4 | 5 | 6 | // Common styles 7 | // ------------------------- 8 | 9 | // Clear the floats 10 | .media, 11 | .media-body { 12 | overflow: hidden; 13 | *overflow: visible; 14 | zoom: 1; 15 | } 16 | 17 | // Proper spacing between instances of .media 18 | .media, 19 | .media .media { 20 | margin-top: 15px; 21 | } 22 | .media:first-child { 23 | margin-top: 0; 24 | } 25 | 26 | // For images and videos, set to block 27 | .media-object { 28 | display: block; 29 | } 30 | 31 | // Reset margins on headings for tighter default spacing 32 | .media-heading { 33 | margin: 0 0 5px; 34 | } 35 | 36 | 37 | // Media image alignment 38 | // ------------------------- 39 | 40 | .media .pull-left { 41 | margin-right: 10px; 42 | } 43 | .media .pull-right { 44 | margin-left: 10px; 45 | } 46 | 47 | 48 | // Media list variation 49 | // ------------------------- 50 | 51 | // Undo default ul/ol styles 52 | .media-list { 53 | margin-left: 0; 54 | list-style: none; 55 | } 56 | -------------------------------------------------------------------------------- /src/less/bootstrap/scaffolding.less: -------------------------------------------------------------------------------- 1 | // 2 | // Scaffolding 3 | // -------------------------------------------------- 4 | 5 | 6 | // Body reset 7 | // ------------------------- 8 | 9 | body { 10 | margin: 0; 11 | font-family: @baseFontFamily; 12 | font-size: @baseFontSize; 13 | line-height: @baseLineHeight; 14 | color: @textColor; 15 | background-color: @bodyBackground; 16 | } 17 | 18 | 19 | // Links 20 | // ------------------------- 21 | 22 | a { 23 | color: @linkColor; 24 | text-decoration: none; 25 | } 26 | a:hover { 27 | color: @linkColorHover; 28 | text-decoration: underline; 29 | } 30 | 31 | 32 | // Images 33 | // ------------------------- 34 | 35 | // Rounded corners 36 | .img-rounded { 37 | .border-radius(6px); 38 | } 39 | 40 | // Add polaroid-esque trim 41 | .img-polaroid { 42 | padding: 4px; 43 | background-color: #fff; 44 | border: 1px solid #ccc; 45 | border: 1px solid rgba(0,0,0,.2); 46 | .box-shadow(0 1px 3px rgba(0,0,0,.1)); 47 | } 48 | 49 | // Perfect circle 50 | .img-circle { 51 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images 52 | } 53 | -------------------------------------------------------------------------------- /test/e2e/scenarios.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* http://docs.angularjs.org/guide/dev_guide.e2e-testing */ 4 | 5 | describe('ripple client', function() { 6 | 7 | beforeEach(function() { 8 | var base = window.__rp_client_base || '/base'; 9 | browser().navigateTo(base + '/index_debug.html'); 10 | }); 11 | 12 | 13 | it('should automatically redirect to /balance when location hash/fragment is empty', function() { 14 | expect(browser().location().url()).toBe("/register"); 15 | }); 16 | 17 | describe('login', function() { 18 | 19 | beforeEach(function() { 20 | browser().navigateTo('#/login'); 21 | }); 22 | 23 | 24 | it('should render login when user navigates to /login', function() { 25 | expect(element('[ng-view] p:first').text()). 26 | toMatch(/Enter the Name and Passphrase used to encrypt your Wallet below/); 27 | }); 28 | 29 | }); 30 | 31 | 32 | describe('register', function() { 33 | 34 | beforeEach(function() { 35 | browser().navigateTo('#/register'); 36 | }); 37 | 38 | 39 | it('should render register when user navigates to /register', function() { 40 | expect(element('[ng-view] p:first').text()). 41 | toMatch(/Ripple is an open source p2p payment network./); 42 | }); 43 | 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/less/bootstrap/responsive.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | 12 | // Responsive.less 13 | // For phone and tablet devices 14 | // ------------------------------------------------------------- 15 | 16 | 17 | // REPEAT VARIABLES & MIXINS 18 | // ------------------------- 19 | // Required since we compile the responsive stuff separately 20 | 21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 22 | @import "mixins.less"; 23 | 24 | 25 | // RESPONSIVE CLASSES 26 | // ------------------ 27 | 28 | @import "responsive-utilities.less"; 29 | 30 | 31 | // MEDIA QUERIES 32 | // ------------------ 33 | 34 | // Large desktops 35 | @import "responsive-1200px-min.less"; 36 | 37 | // Tablets to regular desktops 38 | @import "responsive-768px-979px.less"; 39 | 40 | // Phones to portrait tablets and narrow desktops 41 | @import "responsive-767px-max.less"; 42 | 43 | 44 | // RESPONSIVE NAVBAR 45 | // ------------------ 46 | 47 | // From 979px and below, show a button to toggle navbar contents 48 | @import "responsive-navbar.less"; 49 | -------------------------------------------------------------------------------- /src/jade/tabs/options.jade: -------------------------------------------------------------------------------- 1 | include ../menu/advanced.jade 2 | section.panel.content(ng-controller="OptionsCtrl") 3 | p.literal Options 4 | hr 5 | form(name="optionsForm", ng-submit="save()") 6 | div 7 | label(for="socketIp") Web Socket IP, port 8 | input.socketIp( 9 | name='socketIp', id="socketIp", type='text' 10 | ng-model='socketIp' 11 | rp-hostname) 12 | input.socketPort( 13 | name='socketPort', id="socketPort", type='text' 14 | ng-model='socketPort' 15 | rp-port-number) 16 | .errorGroup 17 | div(rp-errors='socketIp') 18 | .error(rp-error-on='rpHostname') 19 | | Socket ip or hostname is invalid. 20 | div(rp-errors='socketPort') 21 | .error(rp-error-on='rpPortNumber') 22 | | Port number is invalid. 23 | div.helperInput 24 | input(type="checkbox", name="socketSsl", id="socketSsl", ng-model='socketSsl') 25 | label(for="socketSsl") Web Socket ssl 26 | div 27 | label(for="blobIp") Blob vault URL 28 | input.blobIp( 29 | name='blobIp', id="blobIp", type='text' 30 | ng-model='blobIp') 31 | div 32 | p.submitsection 33 | button.btn.btn-success.submit( 34 | type='submit' 35 | ng-disabled='optionsForm.$invalid') Save -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ripple Client 2 | 3 | This is a general purpose Ripple client in JavaScript. 4 | 5 | ## Directory structure 6 | 7 | * `build/` Compiled files 8 | * `src/` Source code 9 | * `src/js/client` Client classes 10 | * `src/js/entry` Entry points for the various client versions 11 | * `src/js/util` Various static, stateless utility functions 12 | * `tools/` Tools used in the build process 13 | 14 | ## Bug tracker 15 | 16 | Have a bug or a feature request? [Please open a new issue](https://github.com/rippleFoundation/ripple-client/issues). Before opening any issue, please search for existing issues and read the [Issue Guidelines](https://github.com/necolas/issue-guidelines), written by [Nicolas Gallagher](https://github.com/necolas/). 17 | 18 | ## Community 19 | 20 | Keep track of development and community news. 21 | 22 | * Read and subscribe to the [The Official Ripple Blog](https://ripple.com/blog/). 23 | * Follow [@Ripple on Twitter](http://twitter.com/ripple). 24 | * Subscribe to [@Ripple on Reddit](http://www.reddit.com/r/Ripple) 25 | * Have a question that's not a feature request or bug report? Send a message to [info@ripple.com](mailto:info@ripple.com) 26 | * Chat with ripplers in IRC. On the `irc.freenode.net` server, in the `#ripple` channel. 27 | 28 | ## More information 29 | 30 | * https://ripple.com/wiki/Ripple_Client 31 | -------------------------------------------------------------------------------- /src/less/ripple/buttons.less: -------------------------------------------------------------------------------- 1 | @btnInfoBackground: #33aaec; 2 | @btnInfoBackgroundHighlight: #2c93c7; 3 | 4 | .btn { 5 | padding: 13px; 6 | font: 15px 'OpenSansBold'; 7 | font-weight: normal; 8 | letter-spacing: 0; 9 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.15); 10 | .rounded(5px); 11 | .transition-multi(background); 12 | .transition-duration(0.2s); 13 | } 14 | 15 | .btn-small { 16 | padding: 4px 13px; 17 | } 18 | .btn-info { 19 | border: 1px solid #336; 20 | } 21 | 22 | .btn-success { 23 | border: 1px solid #488148; 24 | } 25 | .btn-danger { 26 | border: 1px solid #922823; 27 | } 28 | 29 | .btn-wide { 30 | width: 190px; 31 | } 32 | 33 | .btn:disabled { 34 | background: #ccc; 35 | border-color: #ccc; 36 | } 37 | 38 | .btn.sign { 39 | padding: 2px 10px; 40 | font: 20px Arial; 41 | font-weight: bold; 42 | line-height: 25px; 43 | } 44 | .btn.sign.small { 45 | padding: 2px 7px; 46 | font: 20px Arial; 47 | line-height: 25px; 48 | } 49 | 50 | // TODO move to separate file 51 | .icon { 52 | background: url('../../img/sprite_j.png') 53 | } 54 | .icon.up { 55 | display: inline-block; 56 | width: 10px; 57 | height: 10px; 58 | background-position: 13px -3px; 59 | } 60 | .icon.down { 61 | display: inline-block; 62 | width: 10px; 63 | height: 10px; 64 | background-position: -4px -3px; 65 | } -------------------------------------------------------------------------------- /compat/ie/xdr/xdr.js: -------------------------------------------------------------------------------- 1 | (function( jQuery ) { 2 | 3 | if ( window.XDomainRequest ) { 4 | jQuery.ajaxTransport(function( s ) { 5 | if ( s.crossDomain && s.async ) { 6 | if ( s.timeout ) { 7 | s.xdrTimeout = s.timeout; 8 | delete s.timeout; 9 | } 10 | var xdr; 11 | return { 12 | send: function( _, complete ) { 13 | function callback( status, statusText, responses, responseHeaders ) { 14 | xdr.onload = xdr.onerror = xdr.ontimeout = xdr.onprogress = jQuery.noop; 15 | xdr = undefined; 16 | complete( status, statusText, responses, responseHeaders ); 17 | } 18 | xdr = new XDomainRequest(); 19 | xdr.open( s.type, s.url ); 20 | xdr.onload = function() { 21 | callback( 200, "OK", { text: xdr.responseText }, "Content-Type: " + xdr.contentType ); 22 | }; 23 | xdr.onerror = function() { 24 | callback( 404, "Not Found" ); 25 | }; 26 | xdr.onprogress = function() {}; 27 | if ( s.xdrTimeout ) { 28 | xdr.ontimeout = function() { 29 | callback( 0, "timeout" ); 30 | }; 31 | xdr.timeout = s.xdrTimeout; 32 | } 33 | xdr.send( ( s.hasContent && s.data ) || null ); 34 | }, 35 | abort: function() { 36 | if ( xdr ) { 37 | xdr.onerror = jQuery.noop(); 38 | xdr.abort(); 39 | } 40 | } 41 | }; 42 | } 43 | }); 44 | } 45 | })( jQuery ); 46 | -------------------------------------------------------------------------------- /src/less/ripple/overlay.less: -------------------------------------------------------------------------------- 1 | // Overlay, currently unused 2 | 3 | // The corresponding markup should be: 4 | // 5 | //

Transmitting send...

6 | // 7 | 8 | #modal { 9 | position: fixed; 10 | top: 0; 11 | left: 0; 12 | width: 100%; 13 | height: 100%; 14 | z-index: 30; 15 | padding-top: 115px; 16 | 17 | &:after { 18 | .virtualel; 19 | position: fixed; 20 | top: 0; 21 | left: 0; 22 | width: 100%; 23 | height: 100%; 24 | background-color: #000; 25 | opacity: 0.2; 26 | } 27 | 28 | &:empty:after { 29 | opacity: 0; 30 | } 31 | 32 | .log { 33 | position: relative; 34 | background-color: #fff; 35 | z-index: 20; 36 | .box-shadow(0 0 8px #999); 37 | 38 | > p { 39 | border-left: 20px solid #eee; 40 | padding: 20px 40px; 41 | // Same width as container 42 | width: @siteWidth - 100px; 43 | margin: 0 auto; 44 | } 45 | 46 | &.success > p { 47 | border-left: 20px solid @successBackground; 48 | } 49 | 50 | &.error > p { 51 | border-left: 20px solid @errorBackground; 52 | } 53 | 54 | &.warning > p { 55 | border-left: 20px solid @warningBackground; 56 | } 57 | 58 | &.info > p { 59 | border-left: 20px solid @infoBackground; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/js/directives/formatters.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FORMATTERS 3 | * 4 | * Formatters are directives that simply display a value. Normally we do this 5 | * via filters, however if the value needs HTML (rather than just text) it's 6 | * better to use a directive. 7 | */ 8 | 9 | var webutil = require('../util/web'); 10 | 11 | var module = angular.module('formatters', ['domainalias']); 12 | 13 | module.directive('rpPrettyIssuer', ['rpDomainAlias', 14 | function (aliasService) { 15 | return { 16 | restrict: 'EA', 17 | scope: { 18 | issuer: '=rpPrettyIssuer', 19 | contacts: '=rpPrettyIssuerContacts' 20 | }, 21 | template: '{{alias || name || issuer}}', 22 | compile: function (element, attr, linker) { 23 | return function (scope, element, attr) { 24 | function update() { 25 | if (!scope.issuer) { 26 | scope.alias = attr.rpPrettyIssuerDefault ? attr.rpPrettyIssuerDefault : '???'; 27 | return; 28 | } 29 | scope.alias = aliasService.getAliasForAddress(scope.issuer); 30 | 31 | if (scope.contacts) { 32 | scope.name = webutil.unresolveContact(scope.contacts, scope.issuer); 33 | } 34 | } 35 | 36 | scope.$watch('issuer', update); 37 | scope.$watch('contacts', update, true); 38 | update(); 39 | }; 40 | } 41 | }; 42 | }]); 43 | -------------------------------------------------------------------------------- /src/less/bootstrap/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files 7 | 8 | // Make wrapper ul behave like the grid 9 | .thumbnails { 10 | margin-left: -@gridGutterWidth; 11 | list-style: none; 12 | .clearfix(); 13 | } 14 | // Fluid rows have no left margin 15 | .row-fluid .thumbnails { 16 | margin-left: 0; 17 | } 18 | 19 | // Float li to make thumbnails appear in a row 20 | .thumbnails > li { 21 | float: left; // Explicity set the float since we don't require .span* classes 22 | margin-bottom: @baseLineHeight; 23 | margin-left: @gridGutterWidth; 24 | } 25 | 26 | // The actual thumbnail (can be `a` or `div`) 27 | .thumbnail { 28 | display: block; 29 | padding: 4px; 30 | line-height: @baseLineHeight; 31 | border: 1px solid #ddd; 32 | .border-radius(@baseBorderRadius); 33 | .box-shadow(0 1px 3px rgba(0,0,0,.055)); 34 | .transition(all .2s ease-in-out); 35 | } 36 | // Add a hover state for linked versions only 37 | a.thumbnail:hover { 38 | border-color: @linkColor; 39 | .box-shadow(0 1px 4px rgba(0,105,214,.25)); 40 | } 41 | 42 | // Images and captions 43 | .thumbnail > img { 44 | display: block; 45 | max-width: 100%; 46 | margin-left: auto; 47 | margin-right: auto; 48 | } 49 | .thumbnail .caption { 50 | padding: 9px; 51 | color: @gray; 52 | } 53 | -------------------------------------------------------------------------------- /src/js/services/transactions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * TRANSACTIONS 3 | * 4 | * The transactions service is used to listen to all Ripple network 5 | * transactions. 6 | * 7 | * This obviously won't scale, but it'll do long enough for us (or somebody 8 | * else) to come up with something better. 9 | */ 10 | 11 | var module = angular.module('transactions', ['network']); 12 | 13 | module.factory('rpTransactions', ['$rootScope', 'rpNetwork', 14 | function($scope, net) { 15 | var listeners = [], 16 | subscribed = false; 17 | 18 | function subscribe() { 19 | if (subscribed) return; 20 | net.remote.request_subscribe("transactions").request(); 21 | subscribed = true; 22 | } 23 | 24 | function handleTransaction(msg) { 25 | $scope.$apply(function () { 26 | listeners.forEach(function (fn) { 27 | fn(msg); 28 | }); 29 | }); 30 | } 31 | 32 | net.remote.on('net_transaction', handleTransaction); 33 | 34 | return { 35 | addListener: function (fn) { 36 | listeners.push(fn); 37 | subscribe(); 38 | }, 39 | removeListener: function (fn) { 40 | var position = -1; 41 | for (var i = 0, l = listeners.length; i < l; i++) { 42 | if (listeners[i] === fn) { 43 | position = i; 44 | } 45 | } 46 | if (position < 0) return; 47 | listeners.splice(position, 1); 48 | } 49 | }; 50 | }]); 51 | -------------------------------------------------------------------------------- /src/less/bootstrap/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: 8px 35px 8px 14px; 11 | margin-bottom: @baseLineHeight; 12 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 13 | background-color: @warningBackground; 14 | border: 1px solid @warningBorder; 15 | .border-radius(@baseBorderRadius); 16 | color: @warningText; 17 | } 18 | .alert h4 { 19 | margin: 0; 20 | } 21 | 22 | // Adjust close link position 23 | .alert .close { 24 | position: relative; 25 | top: -2px; 26 | right: -21px; 27 | line-height: @baseLineHeight; 28 | } 29 | 30 | 31 | // Alternate styles 32 | // ------------------------- 33 | 34 | .alert-success { 35 | background-color: @successBackground; 36 | border-color: @successBorder; 37 | color: @successText; 38 | } 39 | .alert-danger, 40 | .alert-error { 41 | background-color: @errorBackground; 42 | border-color: @errorBorder; 43 | color: @errorText; 44 | } 45 | .alert-info { 46 | background-color: @infoBackground; 47 | border-color: @infoBorder; 48 | color: @infoText; 49 | } 50 | 51 | 52 | // Block alerts 53 | // ------------------------- 54 | 55 | .alert-block { 56 | padding-top: 14px; 57 | padding-bottom: 14px; 58 | } 59 | .alert-block > p, 60 | .alert-block > ul { 61 | margin-bottom: 0; 62 | } 63 | .alert-block p + p { 64 | margin-top: 5px; 65 | } 66 | -------------------------------------------------------------------------------- /src/less/ripple/desktop.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Ripple Client 3 | * Desktop Stylesheet 4 | * 5 | * Copyright 2012 Opencoin, Inc. 6 | */ 7 | 8 | // CSS Reset 9 | @import "../bootstrap/reset.less"; 10 | 11 | // Core variables and mixins 12 | @import "../bootstrap/variables.less"; 13 | @import "../bootstrap/mixins.less"; 14 | @import "../elements/elements.less"; 15 | 16 | // Grid system and page structure 17 | @import "../bootstrap/scaffolding.less"; 18 | @import "../bootstrap/grid.less"; 19 | @import "../bootstrap/layouts.less"; 20 | 21 | // Base CSS 22 | @import "../bootstrap/buttons.less"; 23 | @import "../bootstrap/button-groups.less"; 24 | @import "../bootstrap/forms.less"; 25 | @import "../bootstrap/tables.less"; 26 | 27 | // Components: common 28 | @import "../bootstrap/close.less"; 29 | 30 | // Components: Nav 31 | @import "../bootstrap/pagination.less"; 32 | @import "../bootstrap/pager.less"; 33 | 34 | // Components: Popovers 35 | @import "../bootstrap/modals.less"; 36 | @import "../bootstrap/tooltip.less"; 37 | @import "../bootstrap/popovers.less"; 38 | 39 | // Responsive 40 | @import "../bootstrap/responsive.less"; 41 | 42 | // Ripple Styles 43 | @import "utils.less"; 44 | @import "layout.less"; 45 | @import "buttons.less"; 46 | @import "forms.less"; 47 | @import "combobox.less"; 48 | @import "content.less"; 49 | @import "status.less"; 50 | @import "pagemodes.less"; 51 | @import "tabs.less"; 52 | @import "browser-chrome.less"; 53 | @import "browser-firefox.less"; 54 | 55 | -------------------------------------------------------------------------------- /src/less/bootstrap/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and blocK) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | pre { 9 | padding: 0 3px 2px; 10 | #font > #family > .monospace; 11 | font-size: @baseFontSize - 2; 12 | color: @grayDark; 13 | .border-radius(3px); 14 | } 15 | 16 | // Inline code 17 | code { 18 | padding: 2px 4px; 19 | color: #d14; 20 | background-color: #f7f7f9; 21 | border: 1px solid #e1e1e8; 22 | } 23 | 24 | // Blocks of code 25 | pre { 26 | display: block; 27 | padding: (@baseLineHeight - 1) / 2; 28 | margin: 0 0 @baseLineHeight / 2; 29 | font-size: @baseFontSize - 1; // 14px to 13px 30 | line-height: @baseLineHeight; 31 | word-break: break-all; 32 | word-wrap: break-word; 33 | white-space: pre; 34 | white-space: pre-wrap; 35 | background-color: #f5f5f5; 36 | border: 1px solid #ccc; // fallback for IE7-8 37 | border: 1px solid rgba(0,0,0,.15); 38 | .border-radius(@baseBorderRadius); 39 | 40 | // Make prettyprint styles more spaced out for readability 41 | &.prettyprint { 42 | margin-bottom: @baseLineHeight; 43 | } 44 | 45 | // Account for some code outputs that place code tags in pre tags 46 | code { 47 | padding: 0; 48 | color: inherit; 49 | background-color: transparent; 50 | border: 0; 51 | } 52 | } 53 | 54 | // Enable scrollable blocks of code 55 | .pre-scrollable { 56 | max-height: 340px; 57 | overflow-y: scroll; 58 | } -------------------------------------------------------------------------------- /src/js/tabs/options.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var webutil = require('../util/web'); 3 | var Tab = require('../client/tab').Tab; 4 | 5 | var OptionsTab = function () 6 | { 7 | Tab.call(this); 8 | }; 9 | 10 | util.inherits(OptionsTab, Tab); 11 | 12 | OptionsTab.prototype.mainMenu = 'advanced'; 13 | 14 | OptionsTab.prototype.generateHtml = function () 15 | { 16 | return require('../../jade/tabs/options.jade')(); 17 | }; 18 | 19 | OptionsTab.prototype.angular = function(module) 20 | { 21 | module.controller('OptionsCtrl', ['$scope', '$rootScope', 'rpId', 22 | function ($scope, $rootScope, $id) 23 | { 24 | $scope.socketIp = Options.server.websocket_ip; 25 | $scope.socketPort = Options.server.websocket_port; 26 | $scope.socketSsl = Options.server.websocket_ssl; 27 | $scope.blobIp = Options.blobvault; 28 | 29 | $scope.save = function () { 30 | // Save in local storage 31 | store.set('ripple_settings', JSON.stringify({ 32 | server: { 33 | "trusted" : true, 34 | "websocket_ip" : $scope.socketIp, 35 | "websocket_port" : $scope.socketPort, 36 | "websocket_ssl" : $scope.socketSsl 37 | }, 38 | blobvault : $scope.blobIp, 39 | persistent_auth : Options.persistent_auth, 40 | transactions_per_page: Options.transactions_per_page 41 | })); 42 | 43 | // Reload 44 | location.reload(); 45 | } 46 | }]); 47 | }; 48 | 49 | module.exports = OptionsTab; 50 | -------------------------------------------------------------------------------- /src/js/util/types.js: -------------------------------------------------------------------------------- 1 | var Base58Utils = require('./base58'); 2 | 3 | var RippleAddress = (function () { 4 | function append_int(a, i) { 5 | return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff) 6 | } 7 | 8 | function firstHalfOfSHA512(bytes) { 9 | return sjcl.bitArray.bitSlice( 10 | sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)), 11 | 0, 256 12 | ); 13 | } 14 | 15 | function SHA256_RIPEMD160(bits) { 16 | return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits)); 17 | } 18 | 19 | return function (seed) { 20 | this.seed = Base58Utils.decode_base_check(33, seed); 21 | 22 | if (!this.seed) { 23 | throw "Invalid seed." 24 | } 25 | 26 | this.getAddress = function (seq) { 27 | seq = seq || 0; 28 | 29 | var private_gen, public_gen, i = 0; 30 | do { 31 | private_gen = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(this.seed, i))); 32 | i++; 33 | } while (!sjcl.ecc.curves.c256.r.greaterEquals(private_gen)); 34 | 35 | public_gen = sjcl.ecc.curves.c256.G.mult(private_gen); 36 | 37 | var sec; 38 | i = 0; 39 | do { 40 | sec = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(append_int(public_gen.toBytesCompressed(), seq), i))); 41 | i++; 42 | } while (!sjcl.ecc.curves.c256.r.greaterEquals(sec)); 43 | 44 | var pubKey = sjcl.ecc.curves.c256.G.mult(sec).toJac().add(public_gen).toAffine(); 45 | 46 | return Base58Utils.encode_base_check(0, sjcl.codec.bytes.fromBits(SHA256_RIPEMD160(sjcl.codec.bytes.toBits(pubKey.toBytesCompressed())))); 47 | }; 48 | }; 49 | })(); 50 | 51 | exports.RippleAddress = RippleAddress; 52 | 53 | -------------------------------------------------------------------------------- /src/less/bootstrap/palette.less: -------------------------------------------------------------------------------- 1 | /* Vars ----------------------------------------------------*/ 2 | 3 | @fontColor: #444444; 4 | @fontColorLight: #888888; 5 | @linkColor: #468dd1; 6 | 7 | @accentColor: #e37655; 8 | @fgColor: #ece9d6; 9 | @bgColor: #dadbdd; 10 | @headerColor: #5e5f63; 11 | 12 | 13 | 14 | /* Mixins ----------------------------------------------------*/ 15 | 16 | .box-shadow-full (@x: 0, @y: 5px, @blur: 5px, @spread: -5px, @color: #000) { 17 | -moz-box-shadow: @x @y @blur @spread @color; 18 | -webkit-box-shadow: @x @y @blur @spread @color; 19 | box-shadow: @x @y @blur @spread @color; 20 | } 21 | 22 | .box-shadow (@opa: 0.2) { 23 | -webkit-box-shadow: 0px 0px 2px rgba(0,0,0,@opa); 24 | -moz-box-shadow: 0px 0px 2px rgba(0,0,0,@opa); 25 | -o-box-shadow: 0px 0px 2px rgba(0,0,0,@opa); 26 | box-shadow: 0px 0px 2px rgba(0,0,0,@opa); 27 | } 28 | 29 | .transition(@speed: 0.3s){ 30 | -webkit-transition: all @speed ease; 31 | -moz-transition: all @speed ease; 32 | -o-transition: all @speed ease; 33 | transition: all @speed ease; 34 | } 35 | 36 | .noTransition(){ 37 | -moz-transition: none; 38 | -webkit-transition: none; 39 | -o-transition: color 0 ease-in; 40 | transition: none; 41 | } 42 | 43 | .shadow(){ 44 | box-shadow: 0px 0px 3px 0px rgba(0,0,0,.22); 45 | } 46 | 47 | .shadow-hard(){ 48 | box-shadow: 3px 3px 0 0 rgba(0,0,0,0.1); 49 | } 50 | 51 | .border-radius-all(@t:40px, @r:40px, @b:40px, @l:40px){ 52 | -moz-border-radius: @t @r @b @l; 53 | -webkit-border-radius: @t @r @b @l; 54 | border-radius: @t @r @b @l; 55 | } 56 | 57 | .text-shadow(){ 58 | text-shadow: 0px 2px 0 rgba(0, 0, 0, 0.3); 59 | } 60 | 61 | .text-shadow-white(){ 62 | text-shadow: 0px 1px 0 rgba(255, 255, 255, 1); 63 | } -------------------------------------------------------------------------------- /src/jade/client/status.jade: -------------------------------------------------------------------------------- 1 | #status(ng-controller="StatusCtrl", ng-class="{expand: show_secondary && balance_count >= 2}", ng-show="userCredentials.username") 2 | .user 3 | div 4 | span.username(ng-show="shortUsername", rp-tooltip="{{userCredentials.username}}", rp-tooltip-placement="bottom") {{shortUsername}} 5 | span.username(ng-hide="shortUsername") {{userCredentials.username}} 6 | a.logout(ng-click='logout()') logout 7 | .balance.primary(ng-show="!loadState.account") 8 | | Loading your balance... 9 | .balance.primary(ng-show="loadState.account && !account.Balance") 10 | | Unfunded account 11 | .balance.primary(ng-show="loadState.account && account.Balance") 12 | span.amount(ng-class="{low: lowBalance}", rp-tooltip="{{account.Balance | rpamount}} (reserve: {{ account.reserve | rpamount }} XRP)") {{account.Balance | rpamount:{rel_precision: 0} }} 13 | span.currency XRP 14 | a.icon.low(ng-show="lowBalance" 15 | rp-popover 16 | rp-popover-placement="bottom" 17 | rp-popover-title='Low ripple balance' 18 | rp-popover-trigger="hover" 19 | data-content="Your current balance is low. You must keep a minimum of {{account.reserve_low_balance | rpamount}} XRP to use all the features of ripple") 20 | ul.secondary 21 | li.balance(ng-repeat="(index, balance) in orderedBalances", ng-class="{negative: balance.total.is_negative()}") 22 | | {{balance.total | rpamount:{rel_precision: 0} }} 23 | span.currency {{balance.total.currency().to_human()}} 24 | a.toggle-secondary(ng-click="toggle_secondary()", ng-show="balance_count >= 2") 25 | a#status-anon(ng-hide="userCredentials.username", href="#/options") 26 | span Options -------------------------------------------------------------------------------- /src/js/data/currencies.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Ripple default external currency list. 3 | * 4 | * These currencies are ranked by value of notes in circulation. Source: 5 | * 6 | * * http://goldnews.bullionvault.com/all_the_money_in_the_world_102720093 7 | * (A better source is welcome. Note: The US dollar was moved to the top.) 8 | * 9 | * Important: XRP must be the first entry in this list. 10 | */ 11 | module.exports = [ 12 | {value: 'XRP', name: 'XRP - Ripples', order: 4}, 13 | {value: 'USD', name: 'USD - US Dollar', order: 3}, 14 | {value: 'EUR', name: 'EUR - Euro', order: 2}, 15 | {value: 'BTC', name: 'BTC - Bitcoin', order: 1}, 16 | {value: 'JPY', name: 'JPY - Japanese Yen', order: 0}, 17 | {value: 'CNY', name: 'CNY - Chinese Yuan', order: 0}, 18 | {value: 'INR', name: 'INR - Indian Rupee', order: 0}, 19 | {value: 'RUB', name: 'RUB - Russian Ruble', order: 0}, 20 | {value: 'GBP', name: 'GBP - British Pound', order: 0}, 21 | {value: 'CAD', name: 'CAD - Canadian Dollar', order: 0}, 22 | {value: 'BRL', name: 'BRL - Brazilian Real', order: 0}, 23 | {value: 'CHF', name: 'CHF - Swiss Franc', order: 0}, 24 | {value: 'DKK', name: 'DKK - Danish Krone', order: 0}, 25 | {value: 'NOK', name: 'NOK - Norwegian Krone', order: 0}, 26 | {value: 'SEK', name: 'SEK - Swedish Krona', order: 0}, 27 | {value: 'CZK', name: 'CZK - Czech Koruna', order: 0}, 28 | {value: 'PLN', name: 'PLN - Polish Zloty', order: 0}, 29 | {value: 'AUD', name: 'AUD - Australian Dollar', order: 0}, 30 | {value: 'MXN', name: 'MXN - Mexican Peso', order: 0}, 31 | {value: 'KRW', name: 'KRW - South Korean Won', order: 0}, 32 | {value: 'TWD', name: 'TWD - New Taiwan Dollar', order: 0}, 33 | {value: 'HKD', name: 'HKD - Hong Kong Dollar', order: 0} 34 | ]; 35 | -------------------------------------------------------------------------------- /src/js/tabs/peers.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var PeersTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(PeersTab, Tab); 10 | PeersTab.prototype.parent = 'advanced'; 11 | 12 | PeersTab.prototype.generateHtml = function () 13 | { 14 | return require('../../jade/tabs/peers.jade')(); 15 | }; 16 | 17 | PeersTab.prototype.angular = function (module) 18 | { 19 | module.controller('PeerCtrl', function ($scope) 20 | { 21 | $scope.addressbookmaster = angular.copy($scope.addressbook); 22 | 23 | $scope.toggle_form = function () 24 | { 25 | $scope.addform_visible = !$scope.addform_visible; 26 | } 27 | 28 | $scope.add = function () 29 | { 30 | $scope.addressbook.push({ 31 | name: $scope.name, 32 | address: $scope.address 33 | }); 34 | } 35 | 36 | $scope.edit = function (index) 37 | { 38 | $scope.addressbook[index].isEditMode = true; 39 | } 40 | 41 | $scope.update = function (index) 42 | { 43 | $scope.addressbookmaster[index] = { 44 | name: $scope.addressbook[index].name, 45 | address: $scope.addressbook[index].address 46 | }; 47 | 48 | $scope.addressbook[index].isEditMode = false; 49 | } 50 | 51 | $scope.remove = function (index) { 52 | $scope.addressbook.splice(index,1); 53 | } 54 | 55 | $scope.cancel = function (index) 56 | { 57 | $scope.addressbook[index] = { 58 | name: $scope.addressbookmaster[index].name, 59 | address: $scope.addressbookmaster[index].address 60 | }; 61 | 62 | $scope.addressbook[index].isEditMode = false; 63 | } 64 | }); 65 | }; 66 | 67 | module.exports = PeersTab; 68 | -------------------------------------------------------------------------------- /src/js/tabs/unl.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var UNLTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(UNLTab, Tab); 10 | UNLTab.prototype.parent = 'advanced'; 11 | 12 | UNLTab.prototype.generateHtml = function () 13 | { 14 | return require('../../jade/tabs/unl.jade')(); 15 | }; 16 | 17 | UNLTab.prototype.angular = function (module) 18 | { 19 | module.controller('UNLCtrl', ['$scope', function ($scope) 20 | { 21 | $scope.addressbookmaster = angular.copy($scope.addressbook); 22 | 23 | $scope.toggle_form = function () 24 | { 25 | $scope.addform_visible = !$scope.addform_visible; 26 | }; 27 | 28 | $scope.add = function () 29 | { 30 | $scope.addressbook.push({ 31 | name: $scope.name, 32 | address: $scope.address 33 | }); 34 | }; 35 | 36 | $scope.edit = function (index) 37 | { 38 | $scope.addressbook[index].isEditMode = true; 39 | }; 40 | 41 | $scope.update = function (index) 42 | { 43 | $scope.addressbookmaster[index] = { 44 | name: $scope.addressbook[index].name, 45 | address: $scope.addressbook[index].address 46 | }; 47 | 48 | $scope.addressbook[index].isEditMode = false; 49 | }; 50 | 51 | $scope.remove = function (index) { 52 | $scope.addressbook.splice(index,1); 53 | }; 54 | 55 | $scope.cancel = function (index) 56 | { 57 | $scope.addressbook[index] = { 58 | name: $scope.addressbookmaster[index].name, 59 | address: $scope.addressbookmaster[index].address 60 | }; 61 | 62 | $scope.addressbook[index].isEditMode = false; 63 | }; 64 | }]); 65 | }; 66 | 67 | module.exports = UNLTab; 68 | -------------------------------------------------------------------------------- /src/less/bootstrap/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.2.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | // CSS Reset 12 | @import "reset.less"; 13 | 14 | // Core variables and mixins 15 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 16 | @import "mixins.less"; 17 | 18 | // Grid system and page structure 19 | @import "scaffolding.less"; 20 | @import "grid.less"; 21 | @import "layouts.less"; 22 | 23 | // Base CSS 24 | @import "type.less"; 25 | @import "code.less"; 26 | @import "forms.less"; 27 | @import "tables.less"; 28 | 29 | // Components: common 30 | @import "sprites.less"; 31 | @import "dropdowns.less"; 32 | @import "wells.less"; 33 | @import "component-animations.less"; 34 | @import "close.less"; 35 | 36 | // Components: Buttons & Alerts 37 | @import "buttons.less"; 38 | @import "button-groups.less"; 39 | @import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less 40 | 41 | // Components: Nav 42 | @import "navs.less"; 43 | @import "navbar.less"; 44 | @import "breadcrumbs.less"; 45 | @import "pagination.less"; 46 | @import "pager.less"; 47 | 48 | // Components: Popovers 49 | @import "modals.less"; 50 | @import "tooltip.less"; 51 | @import "popovers.less"; 52 | 53 | // Components: Misc 54 | @import "thumbnails.less"; 55 | @import "media.less"; 56 | @import "labels-badges.less"; 57 | @import "progress-bars.less"; 58 | @import "accordion.less"; 59 | @import "carousel.less"; 60 | @import "hero-unit.less"; 61 | 62 | // Utility classes 63 | @import "utilities.less"; // Has to be last to override when necessary 64 | -------------------------------------------------------------------------------- /src/less/ripple/combobox.less: -------------------------------------------------------------------------------- 1 | .rp-combobox { 2 | position: relative; 3 | display: inline-block; 4 | 5 | input { 6 | position: relative; 7 | z-index: 20; 8 | margin-bottom: 30px; 9 | } 10 | 11 | &.active input { 12 | border-color: #999; 13 | .border-radius(5px, 0, 0, 5px); 14 | } 15 | 16 | ul.completions { 17 | position: absolute; 18 | top: 41px; 19 | left: 0; 20 | right: 0; 21 | padding: 10px; 22 | margin: 0; 23 | list-style-type: none; 24 | border: 1px solid #999; 25 | border-top: 1px solid #ccc; 26 | background-color: #fff; 27 | .border-radius(0, 5px, 5px, 0); 28 | overflow: auto; 29 | max-height: 300px; 30 | z-index: 30; 31 | .user-select(none); 32 | 33 | li { 34 | width: auto; 35 | padding: 5px; 36 | .rounded(5px); 37 | cursor: default; 38 | } 39 | 40 | li.cursor, li:hover { 41 | background-color: #ddd; 42 | } 43 | } 44 | 45 | .select { 46 | position: absolute; 47 | top: 1px; 48 | right: 1px; 49 | height: 40px; 50 | width: 40px; 51 | z-index: 25; 52 | .bw-gradient(#eee, 230, 245); 53 | .border-radius(4px, 4px, 0, 0); 54 | border-left: 1px solid #ccc; 55 | cursor: default; 56 | .transition-duration(0.2s); 57 | 58 | &:hover { 59 | .bw-gradient(#f9f9f9, 233, 248); 60 | } 61 | 62 | &:after { 63 | .virtualel; 64 | position: absolute; 65 | top: 50%; 66 | right: 50%; 67 | margin: -2px -3px 0 0; 68 | border-top: 5px solid black; 69 | border-left: solid 4px transparent; 70 | border-right: solid 4px transparent; 71 | } 72 | } 73 | 74 | &.active .select { 75 | .border-radius(4px, 0, 0, 0); 76 | .bw-gradient(#eee, 245, 230); 77 | } 78 | } -------------------------------------------------------------------------------- /src/js/client/tabdefs.js: -------------------------------------------------------------------------------- 1 | exports["register"] = function (callback) { 2 | callback(require('../tabs/register')); 3 | }; 4 | 5 | exports["login"] = function (callback) { 6 | callback(require('../tabs/login')); 7 | }; 8 | 9 | exports["balance"] = function (callback) { 10 | callback(require('../tabs/balance')); 11 | }; 12 | 13 | exports["history"] = function (callback) { 14 | callback(require('../tabs/history')); 15 | }; 16 | 17 | exports["contacts"] = function (callback) { 18 | callback(require('../tabs/contacts')); 19 | }; 20 | 21 | exports["invite"] = function (callback) { 22 | callback(require('../tabs/invite')); 23 | }; 24 | 25 | exports["exchange"] = function (callback) { 26 | callback(require('../tabs/exchange')); 27 | }; 28 | 29 | exports["rates"] = function (callback) { 30 | callback(require('../tabs/rates')); 31 | }; 32 | 33 | exports["trust"] = function (callback) { 34 | callback(require('../tabs/trust')); 35 | }; 36 | 37 | exports["send"] = function (callback) { 38 | callback(require('../tabs/send')); 39 | }; 40 | 41 | exports["receive"] = function (callback) { 42 | callback(require('../tabs/receive')); 43 | }; 44 | 45 | exports["trade"] = function (callback) { 46 | callback(require('../tabs/trade')); 47 | }; 48 | 49 | exports["options"] = function (callback) { 50 | callback(require('../tabs/options')); 51 | }; 52 | 53 | exports["feed"] = function (callback) { 54 | callback(require('../tabs/feed')); 55 | }; 56 | exports["peers"] = function (callback) { 57 | callback(require('../tabs/peers')); 58 | }; 59 | exports["unl"] = function (callback) { 60 | callback(require('../tabs/unl')); 61 | }; 62 | exports["security"] = function (callback) { 63 | callback(require('../tabs/security')); 64 | }; 65 | 66 | exports["tx"] = function (callback) { 67 | callback(require('../tabs/tx')); 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /src/js/tabs/receive.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var ReceiveTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(ReceiveTab, Tab); 10 | 11 | ReceiveTab.prototype.mainMenu = 'receive'; 12 | 13 | ReceiveTab.prototype.angular = function (module) { 14 | module.controller('ReceiveCtrl', ['$scope', 'rpId', 15 | function ($scope, $id) 16 | { 17 | if (!$id.loginStatus) return $id.goId(); 18 | 19 | // watch the address function and detect when it changes so we can inject the qr 20 | $scope.$watch('address', function(){ 21 | if ($scope.address !== undefined) 22 | // use jquery qr code library to inject qr code into div 23 | $('#qr-code').qrcode('https://ripple.com//contact?to=' + $scope.address); 24 | }, true); 25 | 26 | // XXX: This used to be in onAfterRender. Refactor and re-enable 27 | /* 28 | this.el.find('.btn').click(function (e) { 29 | e.preventDefault(); 30 | 31 | var address = self.el.find('.address').text(); 32 | 33 | highlightAnimation(); 34 | 35 | // TODO: Actually copy (using Flash) 36 | }); 37 | 38 | this.el.find('.select').click(function (e) { 39 | e.preventDefault(); 40 | 41 | self.el.find('.address input').select(); 42 | }); 43 | 44 | function highlightAnimation() { 45 | // Trigger highlight animation 46 | self.el.find('.address') 47 | .stop() 48 | .css('background-color', '#fff') 49 | .effect('highlight', { 50 | color: "#8BC56A", 51 | easing: jQuery.easing.easeOutSine() 52 | }, 800); 53 | } 54 | */ 55 | }]); 56 | }; 57 | 58 | ReceiveTab.prototype.generateHtml = function () 59 | { 60 | return require('../../jade/tabs/receive.jade')(); 61 | }; 62 | 63 | module.exports = ReceiveTab; 64 | -------------------------------------------------------------------------------- /src/less/bootstrap/responsive-utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // IE10 Metro responsive 7 | // Required for Windows 8 Metro split-screen snapping with IE10 8 | // Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ 9 | @-ms-viewport{ 10 | width: device-width; 11 | } 12 | 13 | // Hide from screenreaders and browsers 14 | // Credit: HTML5 Boilerplate 15 | .hidden { 16 | display: none; 17 | visibility: hidden; 18 | } 19 | 20 | // Visibility utilities 21 | 22 | // For desktops 23 | .visible-phone { display: none !important; } 24 | .visible-tablet { display: none !important; } 25 | .hidden-phone { } 26 | .hidden-tablet { } 27 | .hidden-desktop { display: none !important; } 28 | .visible-desktop { display: inherit !important; } 29 | 30 | // Tablets & small desktops only 31 | @media (min-width: 768px) and (max-width: 979px) { 32 | // Hide everything else 33 | .hidden-desktop { display: inherit !important; } 34 | .visible-desktop { display: none !important ; } 35 | // Show 36 | .visible-tablet { display: inherit !important; } 37 | // Hide 38 | .hidden-tablet { display: none !important; } 39 | } 40 | 41 | // Phones only 42 | @media (max-width: 767px) { 43 | // Hide everything else 44 | .hidden-desktop { display: inherit !important; } 45 | .visible-desktop { display: none !important; } 46 | // Show 47 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior 48 | // Hide 49 | .hidden-phone { display: none !important; } 50 | } 51 | 52 | // Print utilities 53 | .visible-print { display: none !important; } 54 | .hidden-print { } 55 | 56 | @media print { 57 | .visible-print { display: inherit !important; } 58 | .hidden-print { display: none !important; } 59 | } 60 | -------------------------------------------------------------------------------- /src/jade/tabs/tx.jade: -------------------------------------------------------------------------------- 1 | section.single.ddpage.content(ng-controller="TxCtrl", ng-switch on="state") 2 | group(ng-switch-when="loading") 3 | p.literal.throbber Loading transaction details... 4 | group(ng-switch-when="error") 5 | p.literal An error occurred while loading the transaction details. 6 | group(ng-switch-when="loaded") 7 | p.literal.hash Transaction # {{transaction.hash}} 8 | hr 9 | p.literal.type Transaction type: 10 | strong {{transaction.TransactionType}} 11 | group(ng-switch on="transaction.TransactionType") 12 | group(ng-switch-when="Payment") 13 | group.clearfix 14 | dl.details.half 15 | dt Address sent from: 16 | dd {{transaction.Account}} 17 | dt Amount sent: 18 | dd {{amountSent | rpamount}} {{amountSent | rpcurrency}} 19 | dt Currency sent: 20 | dd {{amountSent | rpcurrencyfull}} 21 | dl.details.half 22 | dt Address sent to: 23 | dd {{transaction.Destination}} 24 | dt Amount received: 25 | dd {{transaction.Amount | rpamount}} {{transaction.Amount | rpcurrency}} 26 | dt Currency received: 27 | dd {{transaction.Amount | rpcurrencyfull}} 28 | hr 29 | dl.details 30 | dt Network fee paid: 31 | dd {{transaction.Fee | rpamount}} XRP 32 | dt Conversion rate: 33 | dd TODO 34 | hr 35 | dl.details 36 | dt Ledger number: 37 | dd {{transaction.inLedger}} 38 | group(ng-switch-default) 39 | group.clearfix 40 | dl.details.half 41 | dt Address sent from: 42 | dd {{transaction.Account}} 43 | dl.details.half 44 | hr 45 | p.literal Sorry, we don't have an info page layout for this 46 | | transaction type yet. -------------------------------------------------------------------------------- /src/jade/tabs/unl.jade: -------------------------------------------------------------------------------- 1 | section.panel.content(ng-controller="UNLCtrl") 2 | p.literal Your UNL should contain nodes you believe won't collude to cheat 3 | table.table 4 | tr: td 5 | form(name="addForm") 6 | label(for='unl_hanko') Domain or Hanko: 7 | .unl_key 8 | input#unl_key(name='unl_key', type='text', step='any', ng-model='unl_key', required) 9 | label(for='unl_note') Comment (Optional): 10 | .unl_note 11 | input#unl_note(name='unl_note', type='text', step='any', ng-model='unl_note', unl_note, required) 12 | .submitsection 13 | button.btn.btn-info(type='submit', ng-click='add()', ng-disabled='addForm.$invalid') Add Node 14 | table.table 15 | thead 16 | tr 17 | th # 18 | th.hanko Hanko 19 | th.comment 20 | th.action 21 | a.btn.btn-success.sign(ng-click='toggle_form()') 22 | span(ng-hide='addform_visible') + 23 | span(ng-show='addform_visible') - 24 | tbody 25 | tr(ng-show='addform_visible') 26 | td(colspan=5) 27 | tr(ng-repeat="entry in addressbook") 28 | td: inline-edit(model='entry.name', mode='entry.isEditMode') 29 | td: inline-edit(model='entry.address', mode='entry.isEditMode') 30 | td.save 31 | button.save.btn.btn-success.btn-small(ng-show='entry.isEditMode', ng-click='update($index)') Save 32 | td.command 33 | button.delete.btn.btn-danger.btn-small(ng-show='entry.isEditMode', ng-click='remove($index)') Delete 34 | button.send.btn.btn-success.btn-small(ng-hide='entry.isEditMode') Send 35 | td.action 36 | a(ng-click='edit($index)', ng-hide='entry.isEditMode') edit 37 | a(ng-click='cancel($index)', ng-show='entry.isEditMode') cancel 38 | -------------------------------------------------------------------------------- /src/less/bootstrap/tooltip.less: -------------------------------------------------------------------------------- 1 | // 2 | // Tooltips 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .tooltip { 8 | position: absolute; 9 | z-index: @zindexTooltip; 10 | display: block; 11 | visibility: visible; 12 | padding: 5px; 13 | font-size: 11px; 14 | .opacity(0); 15 | &.in { .opacity(80); } 16 | &.top { margin-top: -3px; } 17 | &.right { margin-left: 3px; } 18 | &.bottom { margin-top: 3px; } 19 | &.left { margin-left: -3px; } 20 | } 21 | 22 | // Wrapper for the tooltip content 23 | .tooltip-inner { 24 | max-width: 200px; 25 | padding: 3px 8px; 26 | color: @tooltipColor; 27 | text-align: center; 28 | text-decoration: none; 29 | background-color: @tooltipBackground; 30 | .border-radius(@baseBorderRadius); 31 | } 32 | 33 | // Arrows 34 | .tooltip-arrow { 35 | position: absolute; 36 | width: 0; 37 | height: 0; 38 | border-color: transparent; 39 | border-style: solid; 40 | } 41 | .tooltip { 42 | &.top .tooltip-arrow { 43 | bottom: 0; 44 | left: 50%; 45 | margin-left: -@tooltipArrowWidth; 46 | border-width: @tooltipArrowWidth @tooltipArrowWidth 0; 47 | border-top-color: @tooltipArrowColor; 48 | } 49 | &.right .tooltip-arrow { 50 | top: 50%; 51 | left: 0; 52 | margin-top: -@tooltipArrowWidth; 53 | border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0; 54 | border-right-color: @tooltipArrowColor; 55 | } 56 | &.left .tooltip-arrow { 57 | top: 50%; 58 | right: 0; 59 | margin-top: -@tooltipArrowWidth; 60 | border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth; 61 | border-left-color: @tooltipArrowColor; 62 | } 63 | &.bottom .tooltip-arrow { 64 | top: 0; 65 | left: 50%; 66 | margin-left: -@tooltipArrowWidth; 67 | border-width: 0 @tooltipArrowWidth @tooltipArrowWidth; 68 | border-bottom-color: @tooltipArrowColor; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/js/services/network.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NETWORK 3 | * 4 | * The network service is used to communicate with the Ripple network. 5 | * 6 | * It encapsulates a ripple.Remote instance. 7 | */ 8 | 9 | var util = require('util'); 10 | 11 | var module = angular.module('network', []); 12 | 13 | module.factory('rpNetwork', ['$rootScope', function($scope) 14 | { 15 | /** 16 | * Manage network state. 17 | * 18 | * This class is intended to manage the connection status to the 19 | * Ripple network. 20 | * 21 | * Note that code in other places *is allowed* to call the Ripple 22 | * library directly. This is not to be intended to be an abstraction 23 | * layer on top of an abstraction layer. 24 | */ 25 | var Network = function () 26 | { 27 | this.remote = new ripple.Remote(Options.server, true); 28 | this.remote.on('connected', this.handleConnect.bind(this)); 29 | this.remote.on('disconnected', this.handleDisconnect.bind(this)); 30 | 31 | this.connected = false; 32 | }; 33 | 34 | Network.prototype.init = function () 35 | { 36 | this.remote.connect(); 37 | }; 38 | 39 | /** 40 | * Setup listeners for identity state. 41 | * 42 | * This function causes the network object to start listening to 43 | * changes in the identity state and automatically subscribe to 44 | * accounts accordingly. 45 | */ 46 | Network.prototype.listenId = function (id) 47 | { 48 | var self = this; 49 | }; 50 | 51 | Network.prototype.handleConnect = function (e) 52 | { 53 | var self = this; 54 | $scope.$apply(function () { 55 | self.connected = true; 56 | $scope.connected = true; 57 | $scope.$broadcast('$netConnected'); 58 | }); 59 | }; 60 | 61 | Network.prototype.handleDisconnect = function (e) 62 | { 63 | var self = this; 64 | $scope.$apply(function () { 65 | self.connected = false; 66 | $scope.connected = false; 67 | $scope.$broadcast('$netDisconnected'); 68 | }); 69 | }; 70 | 71 | return new Network(); 72 | }]); 73 | 74 | -------------------------------------------------------------------------------- /src/less/bootstrap/labels-badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels and badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base classes 7 | .label, 8 | .badge { 9 | display: inline-block; 10 | padding: 2px 4px; 11 | font-size: @baseFontSize * .846; 12 | font-weight: bold; 13 | line-height: 14px; // ensure proper line-height if floated 14 | color: @white; 15 | vertical-align: baseline; 16 | white-space: nowrap; 17 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 18 | background-color: @grayLight; 19 | } 20 | // Set unique padding and border-radii 21 | .label { 22 | .border-radius(3px); 23 | } 24 | .badge { 25 | padding-left: 9px; 26 | padding-right: 9px; 27 | .border-radius(9px); 28 | } 29 | 30 | // Hover state, but only for links 31 | a { 32 | &.label:hover, 33 | &.badge:hover { 34 | color: @white; 35 | text-decoration: none; 36 | cursor: pointer; 37 | } 38 | } 39 | 40 | // Colors 41 | // Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute) 42 | .label, 43 | .badge { 44 | // Important (red) 45 | &-important { background-color: @errorText; } 46 | &-important[href] { background-color: darken(@errorText, 10%); } 47 | // Warnings (orange) 48 | &-warning { background-color: @orange; } 49 | &-warning[href] { background-color: darken(@orange, 10%); } 50 | // Success (green) 51 | &-success { background-color: @successText; } 52 | &-success[href] { background-color: darken(@successText, 10%); } 53 | // Info (turquoise) 54 | &-info { background-color: @infoText; } 55 | &-info[href] { background-color: darken(@infoText, 10%); } 56 | // Inverse (black) 57 | &-inverse { background-color: @grayDark; } 58 | &-inverse[href] { background-color: darken(@grayDark, 10%); } 59 | } 60 | 61 | // Quick fix for labels/badges in buttons 62 | .btn { 63 | .label, 64 | .badge { 65 | position: relative; 66 | top: -1px; 67 | } 68 | } 69 | .btn-mini { 70 | .label, 71 | .badge { 72 | top: 0; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/js/tabs/feed.js: -------------------------------------------------------------------------------- 1 | var util = require('util'); 2 | var Tab = require('../client/tab').Tab; 3 | 4 | var FeedTab = function () 5 | { 6 | Tab.call(this); 7 | }; 8 | 9 | util.inherits(FeedTab, Tab); 10 | FeedTab.prototype.parent = 'advanced'; 11 | 12 | FeedTab.prototype.generateHtml = function () 13 | { 14 | return require('../../jade/tabs/feed.jade')(); 15 | }; 16 | 17 | FeedTab.prototype.angularDeps = Tab.prototype.angularDeps.concat(['transactions']); 18 | 19 | FeedTab.prototype.angular = function (module) 20 | { 21 | module.controller('FeedCtrl', ['$scope', 'rpTransactions', 'rpNetwork', 22 | function ($scope, transactions, $network) 23 | { 24 | $network.remote.on("ledger_closed", handleMsg); 25 | $network.remote.on("net_server", handleMsg); 26 | 27 | function handleMsg(message) 28 | { 29 | //console.log(message); 30 | var today = new Date(); 31 | message.date = today.getHours()+ ":"+ today.getMinutes()+ ":"+ today.getSeconds(); 32 | 33 | if (message.type == "transaction" && $scope.transCheck) { 34 | message.msg=message.transaction.TransactionType; 35 | $scope.feed.unshift(message); 36 | } else if (message.type == "ledgerClosed" && $scope.ledgerCheck) { 37 | $scope.feed.unshift(message); 38 | } else if (message.type == "net_server" && $scope.serverCheck) { 39 | $scope.feed.unshift(message); 40 | } 41 | } 42 | 43 | $scope.feed = []; 44 | 45 | $scope.toggle_feed_transactions = function () 46 | { 47 | if ($scope.transCheck) { 48 | transactions.addListener(handleMsg); 49 | } else { 50 | transactions.removeListener(handleMsg); 51 | } 52 | }; 53 | 54 | $scope.toggle_feed_server = function () 55 | { 56 | if ($scope.serverCheck) { 57 | $network.remote.request_subscribe("server").request(); 58 | } else { 59 | $network.remote.request_unsubscribe("server").request(); 60 | } 61 | }; 62 | 63 | $scope.clear_feed = function () 64 | { 65 | $scope.feed=[]; 66 | }; 67 | }]); 68 | }; 69 | 70 | 71 | 72 | module.exports = FeedTab; 73 | -------------------------------------------------------------------------------- /compat/ie/base64/base64.js: -------------------------------------------------------------------------------- 1 | ;(function () { 2 | 3 | var 4 | object = typeof window != 'undefined' ? window : exports, 5 | chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=', 6 | INVALID_CHARACTER_ERR = (function () { 7 | // fabricate a suitable error object 8 | try { document.createElement('$'); } 9 | catch (error) { return error; }}()); 10 | 11 | // encoder 12 | // [https://gist.github.com/999166] by [https://github.com/nignag] 13 | object.btoa || ( 14 | object.btoa = function (input) { 15 | for ( 16 | // initialize result and counter 17 | var block, charCode, idx = 0, map = chars, output = ''; 18 | // if the next input index does not exist: 19 | // change the mapping table to "=" 20 | // check if d has no fractional digits 21 | input.charAt(idx | 0) || (map = '=', idx % 1); 22 | // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 23 | output += map.charAt(63 & block >> 8 - idx % 1 * 8) 24 | ) { 25 | charCode = input.charCodeAt(idx += 3/4); 26 | if (charCode > 0xFF) throw INVALID_CHARACTER_ERR; 27 | block = block << 8 | charCode; 28 | } 29 | return output; 30 | }); 31 | 32 | // decoder 33 | // [https://gist.github.com/1020396] by [https://github.com/atk] 34 | object.atob || ( 35 | object.atob = function (input) { 36 | input = input.replace(/=+$/, '') 37 | if (input.length % 4 == 1) throw INVALID_CHARACTER_ERR; 38 | for ( 39 | // initialize result and counters 40 | var bc = 0, bs, buffer, idx = 0, output = ''; 41 | // get next character 42 | buffer = input.charAt(idx++); 43 | // character found in table? initialize bit storage and add its ascii value; 44 | ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, 45 | // and if not first of each 4 characters, 46 | // convert the first 8 bits to one ascii character 47 | bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 48 | ) { 49 | // try to find character in table (0-63, not found => -1) 50 | buffer = chars.indexOf(buffer); 51 | } 52 | return output; 53 | }); 54 | 55 | }()); 56 | -------------------------------------------------------------------------------- /src/less/bootstrap/modals.less: -------------------------------------------------------------------------------- 1 | // 2 | // Modals 3 | // -------------------------------------------------- 4 | 5 | // Background 6 | .modal-backdrop { 7 | position: fixed; 8 | top: 0; 9 | right: 0; 10 | bottom: 0; 11 | left: 0; 12 | z-index: @zindexModalBackdrop; 13 | background-color: @black; 14 | // Fade for backdrop 15 | &.fade { opacity: 0; } 16 | } 17 | 18 | .modal-backdrop, 19 | .modal-backdrop.fade.in { 20 | .opacity(80); 21 | } 22 | 23 | // Base modal 24 | .modal { 25 | position: fixed; 26 | top: 50%; 27 | left: 50%; 28 | z-index: @zindexModal; 29 | width: 560px; 30 | margin: -250px 0 0 -280px; 31 | background-color: @white; 32 | border: 1px solid #999; 33 | border: 1px solid rgba(0,0,0,.3); 34 | *border: 1px solid #999; /* IE6-7 */ 35 | .border-radius(6px); 36 | .box-shadow(0 3px 7px rgba(0,0,0,0.3)); 37 | .background-clip(padding-box); 38 | // Remove focus outline from opened modal 39 | outline: none; 40 | 41 | &.fade { 42 | .transition(e('opacity .3s linear, top .3s ease-out')); 43 | top: -25%; 44 | } 45 | &.fade.in { top: 50%; } 46 | } 47 | .modal-header { 48 | padding: 9px 15px; 49 | border-bottom: 1px solid #eee; 50 | // Close icon 51 | .close { margin-top: 2px; } 52 | // Heading 53 | h3 { 54 | margin: 0; 55 | line-height: 30px; 56 | } 57 | } 58 | 59 | // Body (where all modal content resides) 60 | .modal-body { 61 | overflow-y: auto; 62 | max-height: 400px; 63 | padding: 15px; 64 | } 65 | // Remove bottom margin if need be 66 | .modal-form { 67 | margin-bottom: 0; 68 | } 69 | 70 | // Footer (for actions) 71 | .modal-footer { 72 | padding: 14px 15px 15px; 73 | margin-bottom: 0; 74 | text-align: right; // right align buttons 75 | background-color: #f5f5f5; 76 | border-top: 1px solid #ddd; 77 | .border-radius(0 0 6px 6px); 78 | .box-shadow(inset 0 1px 0 @white); 79 | .clearfix(); // clear it in case folks use .pull-* classes on buttons 80 | 81 | // Properly space out buttons 82 | .btn + .btn { 83 | margin-left: 5px; 84 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs 85 | } 86 | // but override that for button groups 87 | .btn-group .btn + .btn { 88 | margin-left: -1px; 89 | } 90 | // and override it for block buttons as well 91 | .btn-block + .btn-block { 92 | margin-left: 0; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/js/services/rippletxt.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RIPPLE.TXT 3 | * 4 | * The ripple.txt service looks up and caches ripple.txt files. 5 | * 6 | * These files are used to do DNS-based verifications autonomously on the 7 | * client-side. Quite neat when you think about it and a decent solution until 8 | * we have a network-internal nickname system. 9 | */ 10 | 11 | var module = angular.module('rippletxt', []); 12 | 13 | module.factory('rpRippleTxt', ['$q', '$rootScope', 14 | function ($q, $scope) { 15 | var txts = {}; 16 | 17 | function get(domain) { 18 | if (txts[domain]) { 19 | return txts[domain]; 20 | } else { 21 | var txtPromise = $q.defer(); 22 | 23 | txts[domain] = txtPromise; 24 | 25 | var urls = [ 26 | 'https://ripple.'+domain+'/ripple.txt', 27 | 'https://www.'+domain+'/ripple.txt', 28 | 'https://'+domain+'/ripple.txt' 29 | ].reverse(); 30 | var next = function (xhr, status) { 31 | if (!urls.length) { 32 | txts[domain] = {}; 33 | txtPromise.resolve({}); 34 | return; 35 | } 36 | var url = urls.pop(); 37 | $.ajax({ 38 | url: url, 39 | dataType: 'text', 40 | success: function (data) { 41 | $scope.$apply(function() { 42 | var sections = parse(data); 43 | txts[domain] = sections; 44 | txtPromise.resolve(sections); 45 | }); 46 | }, 47 | error: next 48 | }); 49 | }; 50 | next(); 51 | 52 | return txtPromise.promise; 53 | } 54 | } 55 | 56 | function parse(txt) { 57 | txt = txt.replace('\r\n', '\n'); 58 | txt = txt.replace('\r', '\n'); 59 | txt = txt.split('\n'); 60 | 61 | var currentSection = "", sections = {}; 62 | for (var i = 0, l = txt.length; i < l; i++) { 63 | var line = txt[i]; 64 | if (!line.length || line[0] === '#') { 65 | continue; 66 | } else if (line[0] === '[' && line[line.length-1] === ']') { 67 | currentSection = line.slice(1, line.length-1); 68 | sections[currentSection] = []; 69 | } else { 70 | line = line.replace(/^\s+|\s+$/g, ''); 71 | if (sections[currentSection]) { 72 | sections[currentSection].push(line); 73 | } 74 | } 75 | } 76 | 77 | return sections; 78 | } 79 | 80 | return { 81 | get: get, 82 | parse: parse 83 | }; 84 | }]); 85 | -------------------------------------------------------------------------------- /src/js/services/domainalias.js: -------------------------------------------------------------------------------- 1 | /** 2 | * DOMAIN ALIAS 3 | * 4 | * The domain alias service resolves ripple address to domains. 5 | * 6 | * In the AccountRoot entry of any ripple account users can provide a reference 7 | * to a domain they own. Ownership of the domain is verified via the ripple.txt 8 | * magic file. 9 | * 10 | * This service provides both the lookup in the ledger and the subsequent 11 | * verification via ripple.txt. 12 | */ 13 | 14 | var module = angular.module('domainalias', ['network', 'rippletxt']); 15 | 16 | module.factory('rpDomainAlias', ['$q', '$rootScope', 'rpNetwork', 'rpRippleTxt', 17 | function ($q, $scope, net, txt) 18 | { 19 | var aliases = {}; 20 | 21 | /** 22 | * Validates a domain against an object parsed from ripple.txt data. 23 | * 24 | * @private 25 | */ 26 | function validateDomain(domain, address, data) 27 | { 28 | // Validate domain 29 | if (!data.domain || 30 | data.domain.length !== 1 || 31 | data.domain[0] !== domain) { 32 | return false; 33 | } 34 | 35 | // Validate address 36 | if (!data.accounts) { 37 | return false; 38 | } 39 | for (var i = 0, l = data.accounts.length; i < l; i++) { 40 | if (data.accounts[i] === address) { 41 | return true; 42 | } 43 | } 44 | 45 | return false; 46 | } 47 | 48 | function getAliasForAddress(address) { 49 | if (aliases[address]) { 50 | return aliases[address]; 51 | } else { 52 | var aliasPromise = $q.defer(); 53 | 54 | net.remote.request_account_info(address) 55 | .on('success', function (data) { 56 | if (data.account_data.Domain) { 57 | $scope.$apply(function () { 58 | var domain = sjcl.codec.utf8String.fromBits(sjcl.codec.hex.toBits(data.account_data.Domain)); 59 | var txtData = txt.get(domain); 60 | if ("function" === typeof txtData.then) { 61 | txtData.then(result); 62 | } else { 63 | result(txtData); 64 | } 65 | function result(data) { 66 | var valid = validateDomain(domain, address, data); 67 | aliasPromise.resolve(valid ? domain : false); 68 | } 69 | }); 70 | } 71 | }) 72 | .on('error', function () {}) 73 | .request(); 74 | 75 | aliases[address] = aliasPromise.promise; 76 | 77 | return aliasPromise.promise; 78 | } 79 | } 80 | 81 | return { 82 | getAliasForAddress: getAliasForAddress 83 | }; 84 | }]); 85 | -------------------------------------------------------------------------------- /deps/js/store.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010-2012 Marcus Westin */ 2 | (function(){function h(){try{return d in b&&b[d]}catch(a){return!1}}function i(){try{return e in b&&b[e]&&b[e][b.location.hostname]}catch(a){return!1}}var a={},b=window,c=b.document,d="localStorage",e="globalStorage",f="__storejs__",g;a.disabled=!1,a.set=function(a,b){},a.get=function(a){},a.remove=function(a){},a.clear=function(){},a.transact=function(b,c,d){var e=a.get(b);d==null&&(d=c,c=null),typeof e=="undefined"&&(e=c||{}),d(e),a.set(b,e)},a.getAll=function(){},a.serialize=function(a){return JSON.stringify(a)},a.deserialize=function(a){if(typeof a!="string")return undefined;try{return JSON.parse(a)}catch(b){return a||undefined}};if(h())g=b[d],a.set=function(b,c){return c===undefined?a.remove(b):(g.setItem(b,a.serialize(c)),c)},a.get=function(b){return a.deserialize(g.getItem(b))},a.remove=function(a){g.removeItem(a)},a.clear=function(){g.clear()},a.getAll=function(){var b={};for(var c=0;cdocument.w=window