diff --git a/platforms/desktop b/platforms/desktop index 5f53840ba382c61e7502003c05957171a3907fb7..df50262d000506dd813763b5533eb997fdc1acd6 160000 --- a/platforms/desktop +++ b/platforms/desktop @@ -1 +1 @@ -Subproject commit 5f53840ba382c61e7502003c05957171a3907fb7 +Subproject commit df50262d000506dd813763b5533eb997fdc1acd6 diff --git a/www/api/index.html b/www/api/index.html index a70c78817d8a4e25aae14466f07189f2a0b621da..6a3f64ef96a6fa6249f4d8cb3aaa31615d421145 100644 --- a/www/api/index.html +++ b/www/api/index.html @@ -73,6 +73,7 @@ <!-- services --> <script src="../dist/dist_js/app/services/settings-services.js"></script> <script src="../dist/dist_js/app/services/network-services.js"></script> +<script src="../dist/dist_js/app/services/desktop-services.js"></script> <script src="../dist/dist_js/app/services/crypto-services.js"></script> <script src="../dist/dist_js/app/services/utils-services.js"></script> <script src="../dist/dist_js/app/services/cache-services.js"></script> diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index 8a1e3590dd9da2d0f8d1f76bbece58ed2613cc99..1e682b236a1fcabec105f4e9c4b84df5384ac48e 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -901,7 +901,8 @@ "LINK_DOC": "API documentation", "LINK_DOC_HELP": "API documentation for developers", "LINK_STANDARD_APP": "Standard version", - "LINK_STANDARD_APP_HELP": "Open standard version of {{'COMMON.APP_NAME'|translate}}" + "LINK_STANDARD_APP_HELP": "Open standard version of {{'COMMON.APP_NAME'|translate}}", + "CONNECTION_ERROR": "Peer <b>{{server}}</b> unreachable or invalid address.<br/><br/>Check your Internet connection, or contact the web site administrator." }, "HOME": { "TITLE": "{{'COMMON.APP_NAME'|translate}} API Documentation", @@ -917,6 +918,7 @@ "NAME": "Name:", "PUBKEY": "Public key of the recipient:", "COMMENT": "Order reference:", + "NODE": "Peer address:", "DEMO": { "SALT": "demo", "PASSWORD": "demo", @@ -963,6 +965,8 @@ "PARAM_REDIRECT_URL_HELP": "URL redirection after sending payment, after the payment has been sent. Can contain the following strings, which will be replaced by the values of the transaction: \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\" and \"{pubkey}\".", "PARAM_CANCEL_URL": "URL if cancelled", "PARAM_CANCEL_URL_HELP": "URL in case of cancellation. Can contain the following strings, which will be replaced: \"{comment}\", \"{amount}\" and \"{pubkey}\".", + "PARAM_PREFERRED_NODE": "Preferred Duniter peer", + "PARAM_PREFERRED_NODE_HELP": "Peer address (URL) to use preferably (\"g1.domain.com:443\" or \"https://g1.domain.com\")", "EXAMPLES_HELP": "Examples of integration:", "EXAMPLE_BUTTON": "HTML Button", "EXAMPLE_BUTTON_DEFAULT_TEXT": "Pay in {{currency|abbreviate}}", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index e9d855e7f7a290193396838a794793d7c6da3416..fe47aa82bbdba0fcdbbc4971b0b61265c60ec9c8 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -901,7 +901,8 @@ "LINK_DOC": "API documentation", "LINK_DOC_HELP": "API documentation for developers", "LINK_STANDARD_APP": "Standard version", - "LINK_STANDARD_APP_HELP": "Open standard version of {{'COMMON.APP_NAME'|translate}}" + "LINK_STANDARD_APP_HELP": "Open standard version of {{'COMMON.APP_NAME'|translate}}", + "CONNECTION_ERROR": "Peer <b>{{server}}</b> unreachable or invalid address.<br/><br/>Check your Internet connection, or contact the web site administrator." }, "HOME": { "TITLE": "{{'COMMON.APP_NAME'|translate}} API Documentation", @@ -917,6 +918,7 @@ "NAME": "Name:", "PUBKEY": "Public key of the recipient:", "COMMENT": "Order reference:", + "NODE": "Peer address:", "DEMO": { "SALT": "demo", "PASSWORD": "demo", @@ -963,6 +965,8 @@ "PARAM_REDIRECT_URL_HELP": "URL redirection after sending payment, after the payment has been sent. Can contain the following strings, which will be replaced by the values of the transaction: \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\" and \"{pubkey}\".", "PARAM_CANCEL_URL": "URL if cancelled", "PARAM_CANCEL_URL_HELP": "URL in case of cancellation. Can contain the following strings, which will be replaced: \"{comment}\", \"{amount}\" and \"{pubkey}\".", + "PARAM_PREFERRED_NODE": "Preferred Duniter peer", + "PARAM_PREFERRED_NODE_HELP": "Peer address (URL) to use preferably (\"g1.domain.com:443\" or \"https://g1.domain.com\")", "EXAMPLES_HELP": "Examples of integration:", "EXAMPLE_BUTTON": "HTML Button", "EXAMPLE_BUTTON_DEFAULT_TEXT": "Pay in {{currency|abbreviate}}", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 3b1f9ffcd6c641a7d252ccacd368cc39dba4869a..da359ee6ab9518f99a9a81c7cd595d3c6b053781 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -901,7 +901,8 @@ "LINK_DOC": "documentation API", "LINK_DOC_HELP": "Documentation pour les développeurs", "LINK_STANDARD_APP": "version classique", - "LINK_STANDARD_APP_HELP": "Ouvrir la version classique de {{'COMMON.APP_NAME'|translate}}" + "LINK_STANDARD_APP_HELP": "Ouvrir la version classique de {{'COMMON.APP_NAME'|translate}}", + "CONNECTION_ERROR": "Nœud <b>{{server}}</b> injoignable ou adresse invalide.<br/><br/>Vérifiez votre connection Internet, ou contacter l'administrateur du site</a>." }, "HOME": { "TITLE": "Documentation API {{'COMMON.APP_NAME'|translate}}", @@ -915,8 +916,9 @@ "SUMMARY": "Récapitulatif de la commande :", "AMOUNT": "Montant :", "NAME": "Nom :", - "PUBKEY": "Clé publique du destinaire :", + "PUBKEY": "Clé publique du destinataire :", "COMMENT": "Référence de la commande :", + "NODE": "Addresse du nœud :", "DEMO": { "SALT": "demo", "PASSWORD": "demo", @@ -942,6 +944,7 @@ "DEMO_DIVIDER": "Tester", "DEMO_HELP": "Pour tester ce service, cliquez sur le bouton ci-contre. Le résultat s'affichera en dessous.", "DEMO_RESULT": "Résultat retourné par l'appel :", + "DEMO_RESULT_PEER": "Nœud Duniter utilisé : ", "DEMO_SUCCEED": "<i class=\"icon ion-checkmark\"></i> Succès !", "DEMO_CANCELLED": "<i class=\"icon ion-close\"></i> Annulé par l'utilisateur", "INTEGRATE_DIVIDER": "Intégrer", @@ -960,9 +963,11 @@ "PARAM_NAME": "Nom (du destinataire ou du site web)", "PARAM_NAME_HELP": "Le nom du destinataire, ou du site web appellant. Cela peut-etre un nom lisible (\"Mon site en ligne\"), ou encore une pseudo-adresse web (\"MonSite.com\").", "PARAM_REDIRECT_URL": "Adresse web de redirection", - "PARAM_REDIRECT_URL_HELP": "Adresse web (URL) de redirection, appellé quand le paiement a été envoyé. Peut contenir les chaines suivantes, qui seront remplacée par les valeurs de la transaction : \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\" et {pubkey}.", + "PARAM_REDIRECT_URL_HELP": "Adresse web (URL) de redirection, appellé quand le paiement a été envoyé. Peut contenir les chaines suivantes, qui seront remplacée par les valeurs de la transaction : \"{tx}\", \"{hash}\", \"{comment}\", \"{amount}\", \"{pubkey}\" et \"{node}\".", "PARAM_CANCEL_URL": "Adresse web d'annulation", "PARAM_CANCEL_URL_HELP": "Adresse web (URL) en cas d'annulation du paiement, par l'utilisateur. Peut contenir les chaines suivantes, qui seront remplacée dynamiquement: \"{comment}\", \"{amount}\" et {pubkey}.", + "PARAM_PREFERRED_NODE": "Nœud Duniter préféré", + "PARAM_PREFERRED_NODE_HELP": "Adresse (URL) du nœud Duniter à utiliser de préférence (\"g1.domaine.com:443\" ou \"https://g1.domaine.com\").", "EXAMPLES_HELP": "Voici des exemples d'intégration :", "EXAMPLE_BUTTON": "Bouton HTML", "EXAMPLE_BUTTON_DEFAULT_TEXT": "Payer en {{currency|currencySymbol}}", diff --git a/www/js/api/app.js b/www/js/api/app.js index 44aa8a1af6b5bf037eed4a2d4d000d01ae5f33bc..3d2baeb296b1b4737275e1f611ba55e381862473 100644 --- a/www/js/api/app.js +++ b/www/js/api/app.js @@ -25,7 +25,7 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr }) .state('app.home', { - url: "/home?result&service&cancel", + url: "/home?result&service&cancel&node", views: { 'menuContent': { templateUrl: "templates/api/home.html", @@ -43,7 +43,7 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr .state('api.transfer', { cache: false, - url: "/payment/:pubkey?name&amount&udAmount&comment&redirect_url&cancel_url&demo", + url: "/payment/:pubkey?name&amount&udAmount&comment&preferred_node&redirect_url&cancel_url&demo&error", views: { 'menuContent': { templateUrl: "templates/api/transfer.html", @@ -114,7 +114,8 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr amount: 100, comment: 'REFERENCE', name: 'www.domain.com', - redirect_url: 'http://www.domain.com/payment?ref={comment}&tx={tx}', + preferred_node: undefined, + redirect_url: 'http://www.domain.com/payment?ref={comment}&tx={tx}&node={node}', cancel_url: 'http://www.domain.com/payment?ref={comment}&cancel' }; $scope.transferButton = { @@ -152,7 +153,7 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr $scope.transferButton.style.icon = $scope.transferButton.icons[1/*Duniter icon*/]; $scope.transferDemoUrl = $rootScope.rootPath + $state.href('api.transfer', angular.merge({}, $scope.transferData, { demo: true, - redirect_url: $rootScope.rootPath + '#/app/home?service=payment&result={tx}', + redirect_url: $rootScope.rootPath + '#/app/home?service=payment&result={tx}&node={node}', cancel_url: $rootScope.rootPath + '#/app/home?service=payment&cancel' })); @@ -169,6 +170,9 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr if (state.stateParams && state.stateParams.cancel) { $scope.result.cancelled = true; } + if (state.stateParams && state.stateParams.node) { + $scope.result.node = state.stateParams.node; + } csCurrency.get() .then(function(currency) { @@ -231,7 +235,8 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr }) .controller('ApiTransferCtrl', function ($scope, $rootScope, $timeout, $controller, $state, $q, $translate, $filter, - BMA, CryptoUtils, UIUtils, csCurrency, csTx, csWallet, csDemoWallet){ + $window, $ionicHistory, BMA, CryptoUtils, UIUtils, csSettings, csCurrency, + csPlatform, csTx, csWallet, csDemoWallet){ 'ngInject'; // Initialize the super class and extend it. @@ -244,10 +249,15 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr pubkey: undefined, name: undefined, redirect_url: undefined, - cancel_url: undefined + cancel_url: undefined, + node: undefined }; $scope.enter = function(e, state) { + $rootScope.errorState = state.stateName; + + if (!$scope.loading) return; // already enter + if (state.stateParams && state.stateParams.amount) { $scope.transferData.amount = parseFloat(state.stateParams.amount.replace(new RegExp('[.,]'), '.')).toFixed(2) * 100; } @@ -269,9 +279,89 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr if (state.stateParams && state.stateParams.demo) { $scope.demo = true; } + + if (state.stateParams && state.stateParams.preferred_node) { + var + isHttpsMode = $window.location.protocol === 'https:', + useSsl = isHttpsMode, + preferredNode = state.stateParams.preferred_node; + var matches = /^(?:(http[s]?:)\/\/)(.*)$/.exec(preferredNode); + if (matches) { + useSsl = matches[1] === 'https:'; + preferredNode = matches[2]; + } + var parts = preferredNode.split(':'); + if (parts.length >= 1) { + var port = parts[1] || (useSsl ? 443 : 80); + $scope.node = { + host: parts[0], + port: port, + useSsl: useSsl || (port == 443) + }; + + // Add a fallback node that use SSL + if (!$scope.node.useSsl) { + var node = angular.copy($scope.node); + node.useSsl = true; + node.port = 443; + csSettings.data.fallbackNodes = csSettings.data.fallbackNodes || []; + csSettings.data.fallbackNodes.splice(0,0,node); + } + } + else { + console.warn("[api] Invalid preferred node address: {0}. Using default node." + state.stateParams.preferred_node); + } + } + + // Start + return $scope.start(); }; $scope.$on('$ionicView.enter', $scope.enter); + + $scope.start = function() { + if ($scope.starting) return; + + $scope.starting = true; + $scope.loading = true; + + // Set BMA node + if (!$scope.error && $scope.node && !BMA.node.same($scope.node.host, $scope.node.port)) { + console.debug("[api] Using preferred node: {0}:{1}".format($scope.node.host, $scope.node.port)); + BMA.stop(); + BMA.copy($scope.node); + $scope.node.server = BMA.server; + } + + // Start platform (or restart) platform + // This will start the BMA node + return csPlatform.restart() + .then(csCurrency.get) + .then(function(currency) { + $scope.currency = currency; + $scope.node = currency.node; + $scope.loading = false; + $scope.error = false; + $scope.starting = false; + // Reset history cache + $ionicHistory.clearCache(); + }) + // Error during load (BMA not alive ?) + .catch(function(err) { + console.error(err && err.message || err); + $scope.error = true; + $scope.loading = false; + $scope.starting = false; + + // Make sure to retry if user choose a fallback node + var unsubscribe = BMA.api.node.on.start($scope, function() { + $scope.start(); + unsubscribe(); + }); + }) + ; + }; + function onLogin(authData) { // User cancelled @@ -285,9 +375,15 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr UIUtils.loading.show(); - wallet.start({restore: false}/*skip restore from local storage*/) + wallet.start({restore: false/*skip restore from local storage*/}) .then(function() { - return wallet.login({auth: true, authData: authData}); + return wallet.login({ + auth: true, + authData: authData, + minData: true, + sources: true, + tx: {enable: false} + }); }) .then(function(walletData) { $scope.login = true; @@ -369,6 +465,7 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr url = url.replace(/\{comment\}/g, $scope.transferData.comment||''); url = url.replace(/\{amount\}/g, $scope.transferData.amount.toString()); url = url.replace(/\{tx\}/g, encodeURI(txRes.tx)); + url = url.replace(/\{node\}/g, encodeURI(BMA.host+':'+BMA.port)); return $scope.redirectToUrl(url, 2500); }); @@ -423,9 +520,14 @@ angular.module('cesium-api', ['ionic', 'ionic-material', 'ngMessages', 'pascalpr }) - .run(function(csPlatform) { + .run(function(csSettings) { 'ngInject'; - csPlatform.start(); + csSettings.data.rememberMe = false; + csSettings.data.useLocalStorage = false; + // Force auth idle to 30s + csSettings.data.keepAuthIdle = 30; + + //csPlatform.start(); }) ; diff --git a/www/js/controllers/login-controllers.js b/www/js/controllers/login-controllers.js index 744b9cb960e7880d9479e3980a123732d7b70868..dfe8bb90889cb69bc42913f075b695ab01d31dbc 100644 --- a/www/js/controllers/login-controllers.js +++ b/www/js/controllers/login-controllers.js @@ -43,7 +43,7 @@ function LoginController($scope, $timeout, $controller, csWallet) { } -function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils, csCrypto, +function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils, csCrypto, ionicReady, UIUtils, BMA, Modals, csSettings, Device, parameters) { 'ngInject'; @@ -72,9 +72,12 @@ function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils, // modal init $scope.init = function() { - // Should auto-compute pubkey ? - $scope.autoComputePubkey = ionic.Platform.grade.toLowerCase()==='a' && - !UIUtils.screen.isSmall(); + + ionicReady().then(function(){ + // Should auto-compute pubkey ? + $scope.autoComputePubkey = ionic.Platform.grade.toLowerCase()==='a' && + !UIUtils.screen.isSmall(); + }); // Init remember me $scope.formData.rememberMe = csSettings.data.rememberMe; diff --git a/www/js/controllers/settings-controllers.js b/www/js/controllers/settings-controllers.js index 163c1d9db39d4d4a7329b2a1775bca79ec608e2f..fdcf678801cff7bf91dffadac85a9284bae2d9c0 100644 --- a/www/js/controllers/settings-controllers.js +++ b/www/js/controllers/settings-controllers.js @@ -183,7 +183,7 @@ function SettingsController($scope, $q, $window, $ionicHistory, $ionicPopup, $ti BMA.copy(nodeBMA); $scope.bma = BMA; - // Start platform is not already started + // Restart platform (or start if not already started) csPlatform.restart(); // Reset history cache diff --git a/www/js/filters.js b/www/js/filters.js index 2cd8b728884a65440d5ebb24e73d2aa8e0923d59..3cf9060aecc3d0cda3b9b53604dc0d5d8c1a9635 100644 --- a/www/js/filters.js +++ b/www/js/filters.js @@ -2,7 +2,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalprecht.translate', 'cesium.translations' ]) - .factory('filterTranslations', function($rootScope, $q, csPlatform, csSettings, csCurrency, $translate) { + .factory('filterTranslations', function($rootScope, $q, csPlatform, csSettings, csCurrency, $translate, $timeout) { 'ngInject'; var @@ -65,7 +65,10 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }; // Default action - that.start(); + // Must be started with a delay, to allow settings override, before starting platform (need by Cesium API) + $timeout(function() { + that.start(); + }); return that; }) diff --git a/www/js/platform.js b/www/js/platform.js index d393e5aef6f4c74235402eae03802921c460bd34..feef681477d5ce240a5d3c01c68abc4d524ee588 100644 --- a/www/js/platform.js +++ b/www/js/platform.js @@ -153,7 +153,18 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] .then(function(res) { if (!res) return checkBmaNodeAlive(); // Loop - return $translate('CONFIRM.USE_FALLBACK_NODE', {old: BMA.server, new: newServer}) + // Force to show port/ssl, if this is the only difference + var messageParam = {old: BMA.server, new: newServer}; + if (messageParam.old === messageParam.new) { + if (BMA.port != fallbackNode.port) { + messageParam.new += ':' + fallbackNode.port; + } + else if (BMA.useSsl == false && (fallbackNode.useSsl || fallbackNode.port==443)) { + messageParam.new += ' (SSL)'; + } + } + + return $translate('CONFIRM.USE_FALLBACK_NODE', messageParam) .then(function(msg) { return UIUtils.alert.confirm(msg); }) @@ -264,8 +275,8 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] .catch(function(err) { startPromise = null; started = false; - if($state.current.name !== 'app.home') { - $state.go('app.home', {error: 'peer'}); + if($state.current.name !== $rootScope.errorState) { + $state.go($rootScope.errorState, {error: 'peer'}); } throw err; }); @@ -310,6 +321,7 @@ angular.module('cesium.platform', ['ngIdle', 'cesium.config', 'cesium.services'] $rootScope.settings = csSettings.data; $rootScope.currency = csCurrency.data; $rootScope.device = Device; + $rootScope.errorState = 'app.home'; // Compute the root path var hashIndex = $window.location.href.indexOf('#'); diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 658a619ec652a8db6aebee46e4e89e2a6b2deb2b..01c7fe68561118bab71356c093a14ce004e803c0 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -129,8 +129,10 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. } function closeWs() { + if (!that.cache) return; + console.warn('[BMA] Closing all websockets...'); - _.keys(that.cache.wsByPath).forEach(function(key) { + _.keys(that.cache.wsByPath||{}).forEach(function(key) { var sock = that.cache.wsByPath[key]; sock.close(); }); @@ -397,7 +399,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. node: { summary: get('/node/summary', csHttp.cache.LONG), same: function(host2, port2) { - return host2 == that.host && ((!that.port && !port2) || (that.port == port2||80)); + return host2 == that.host && ((!that.port && !port2) || (that.port == port2||80)) && (that.useSsl == (port2 && port2 === 443)); }, forceUseSsl: that.forceUseSsl }, @@ -622,9 +624,12 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. }; exports.copy = function(otherNode) { - if (that.started) that.stop(); + var wasStarted = that.started; + // Stop, if need + if (wasStarted) that.stop(); that.init(otherNode.host, otherNode.port, otherNode.useSsl, that.useCache/*keep original value*/); - return that.start(); + // Restart (only if was already started) + return wasStarted ? that.start() : $q.when(); }; exports.wot.member.uids = function() { diff --git a/www/js/services/settings-services.js b/www/js/services/settings-services.js index e25e68a912f3b37338e45eedc1cb2c406c1685e6..e2d7c1449ec68b16de7ae58d6f14f2f33f5ecaaa 100644 --- a/www/js/services/settings-services.js +++ b/www/js/services/settings-services.js @@ -143,7 +143,7 @@ angular.module('cesium.settings.services', ['ngApi', 'cesium.config']) }, emitChangedEvent = function() { - var hasChanged = previousData && !angular.equals(previousData, data); + var hasChanged = angular.isUndefined(previousData) || !angular.equals(previousData, data); if (hasChanged) { previousData = angular.copy(data); return api.data.raise.changed(data); diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index cff0e7afc6a5fff90a34517d6e814cb30f9c2806..6cf42bfd43937991478a45ca31ec276e8d64ce9d 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -735,7 +735,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se // If not revoked else { - if (!data.isMember && data.requirements.meta.invalid) { + if (!data.isMember && data.requirements.meta && data.requirements.meta.invalid) { addEvent({type: 'error', message: 'ERROR.WALLET_INVALID_BLOCK_HASH', context: 'requirements'}); console.debug("Invalid membership for uid={0}: block hash changed".format(data.uid)); } diff --git a/www/templates/api/doc.html b/www/templates/api/doc.html index d195f59e3e122dc8733875f84a9d8f12426d340b..4eb7c6fb6ccaa2f9074e9c3182ad016265af3ebf 100644 --- a/www/templates/api/doc.html +++ b/www/templates/api/doc.html @@ -47,11 +47,15 @@ <div class="col gray" translate>API.DOC.TRANSFER.PARAM_NAME_HELP</div> </div> <div class="row"> - <div class="col col-20 text-italic">redirect_url</div> - <div class="col gray" translate>API.DOC.TRANSFER.PARAM_REDIRECT_URL_HELP</div> + <div class="col col-20 text-italic">preferred_node</div> + <div class="col gray" translate>API.DOC.TRANSFER.PARAM_PREFERRED_NODE_HELP</div> </div> <div class="row stable-bg"> - <div class="col col-20 text-italic dark">cancel_url</div> + <div class="col col-20 text-italic dark">redirect_url</div> + <div class="col gray" translate>API.DOC.TRANSFER.PARAM_REDIRECT_URL_HELP</div> + </div> + <div class="row"> + <div class="col col-20 text-italic">cancel_url</div> <div class="col gray" translate>API.DOC.TRANSFER.PARAM_CANCEL_URL_HELP</div> </div> </div> @@ -72,6 +76,8 @@ <h2 class="text-right balanced" translate>API.DOC.DEMO_SUCCEED</h2> <h4 class="gray" translate>API.DOC.DEMO_RESULT</h4> <p class="balanced-100-bg padding dark text-keep-lines">{{result.content}}</p> + + <h4 class="gray"><span translate>API.DOC.DEMO_RESULT_PEER</span> <b>{{result.node}}</b></h4> </div> <div class="item item-text-wrap" ng-if="result.type === 'payment' && result.cancelled"> <h2 class="text-right assertive" translate>API.DOC.DEMO_CANCELLED</h2> @@ -171,6 +177,17 @@ placeholder="{{'API.DOC.TRANSFER.PARAM_NAME'|translate}}"> </label> + <p class="padding-top"> + <i class="icon ion-key"></i> + {{'API.DOC.TRANSFER.PARAM_PREFERRED_NODE' | translate}} : + </p> + <label class="item item-input"> + <input type="text" + ng-model="transferData.preferred_node" + ng-model-options="{ debounce: 650 }" + placeholder="{{'API.DOC.TRANSFER.PARAM_PREFERRED_NODE_HELP'|translate}}"> + </label> + <p class="padding-top"> <i class="icon ion-arrow-return-left"></i> {{'API.DOC.TRANSFER.PARAM_REDIRECT_URL' | translate}} : diff --git a/www/templates/api/transfer.html b/www/templates/api/transfer.html index 8643317019de7a4872e6d3e20bf7ace5d74e1c9e..1ee7deb99e5cef7f302815b1ebc9d4124852fc09 100644 --- a/www/templates/api/transfer.html +++ b/www/templates/api/transfer.html @@ -56,10 +56,11 @@ <div class="item item-icon-left-padding item-tx no-border "> <h2 translate>API.TRANSFER.AMOUNT</h2> - <div class="badge item-note badge-calm" ng-bind-html="transferData.amount|formatAmount:{useRelative: false, currency: $root.currency.name}"></div> - <div class="badge badge-secondary" ng-bind-html="transferData.amount|formatAmount:{useRelative: true, currency: $root.currency.name}"></div> + <ion-spinner class="badge item-note" icon="android" ng-show="loading"></ion-spinner> + <div class="badge item-note badge-calm ng-hide" ng-show="!loading" ng-bind-html="transferData.amount|formatAmount:{useRelative: false, currency: currency.name}"></div> + <div class="badge badge-secondary ng-hide" ng-show="!loading" ng-bind-html="transferData.amount|formatAmount:{useRelative: true, currency: currency.name, currentUD: currency.currentUD}"></div> </div> - <div class="item item-icon-left-padding" ng-if="transferData.name"> + <div class="item item-icon-left-padding" > <h2 translate>API.TRANSFER.NAME</h2> <div class="badge item-note"> {{transferData.name}} @@ -67,7 +68,7 @@ </div> <div class="item item-icon-left-padding item-text-wrap"> <h2 translate>API.TRANSFER.PUBKEY</h2> - <div class="badge"> + <div class="badge" > <span class="hidden-xs"><br class="visible-sm visible-md"/><i class="icon ion-key"> </i>{{transferData.pubkey}}</span> <span class="visible-xs" copy-on-click="{{transferData.pubkey}}"><br class="visible-xs"/><i class="icon ion-key"></i> {{transferData.pubkey|formatPubkey}}</span> </div> @@ -76,10 +77,33 @@ <div class="item item-icon-left-padding"> <h2 translate>API.TRANSFER.COMMENT</h2> <div class="badge item-note"> - <span class="hidden-xs"><br class="visible-sm visible-md"/>{{transferData.comment}}</span> - <span class="visible-xs" copy-on-click="{{transferData.comment}}"><br/>{{transferData.comment}}</span> + <span class="hidden-xs"><br class="visible-sm visible-md"/>{{::transferData.comment}}</span> + <span class="visible-xs" copy-on-click="{{transferData.comment}}"><br/>{{::transferData.comment}}</span> </div> </div> + + <div class="item item-icon-left-padding" ng-hide="error"> + <h2 translate>API.TRANSFER.NODE</h2> + <div class="badge item-note" ng-if="!loading"> + <br class="visible-sm visible-md"/> + <i class="icon ion-locked" ng-if="node.useSsl"></i> {{node.server}} + </div> + </div> + + <div class="center padding animate-fade-in animate-show-hide ng-hide" ng-show="!loading && error"> + <div class="card card-item padding"> + <p class="item-content item-text-wrap"> + <i class="icon ion-android-alert assertive"></i> + <span class="dark" trust-as-html="'API.COMMON.CONNECTION_ERROR'|translate:node"></span> + </p> + + <!-- Retry --> + <button type="button" + class="button button-positive icon icon-left ion-refresh ink" + ng-click="start()">{{'COMMON.BTN_REFRESH'|translate}}</button> + </div> + </div> + <!-- spacer in small screen --> <div class="padding-bottom visible-xs"> </div> </div> diff --git a/www/templates/join/modal_choose_account_type.html b/www/templates/join/modal_choose_account_type.html index a5a358efc708d98fe1a0ae51a2e114e728fb329a..76b439b661d9e409ffb18935197170bc8863abaa 100644 --- a/www/templates/join/modal_choose_account_type.html +++ b/www/templates/join/modal_choose_account_type.html @@ -39,7 +39,7 @@ <div class="row responsive-sm"> <div class="col"> <div class="item card item-icon-left padding item-text-wrap stable-bg"> - <i class="icon ion-android-warning assertive"></i> + <i class="icon ion-android-warning assertive"></i> <p class="item-content item-icon-left-padding "> <span class="dark" translate>ACCOUNT.NEW.INTRO_WARNING_SECURITY</span><br/>