diff --git a/package.json b/package.json index 7cb527ff0f8d3c6e13a864b19a750c50175cf740..678572ac51c10b99da62f3cc4d3b8f934f11d199 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "@bower_components/socket.io-client": "socketio/socket.io-client#^1.7.4", "@bower_components/ui-leaflet": "angular-ui/ui-leaflet#v2.0.0", "@bower_components/underscore": "jashkenas/underscore#1.10.2", + "@bower_components/jdenticon": "dmester/jdenticon#3.1.0", "through2": "^4.0.2", "uuid": "3.2.1" }, @@ -221,4 +222,4 @@ "node": ">= 12.18.3", "yarn": ">= 1.22.0" } -} \ No newline at end of file +} diff --git a/www/index.html b/www/index.html index 46371efd7619b330b10b4d6e1f6c2f9c6487083f..a1e5f71dc31b8c38060757869aa04e67b5c36bbb 100644 --- a/www/index.html +++ b/www/index.html @@ -80,6 +80,8 @@ <script src="lib/socket.io-client/dist/socket.io.min.js"></script> <script src="lib/underscore/underscore-min.js"></script> <script src="lib/chart.js/dist/Chart.min.js"></script> + <script src="lib/jdenticon/dist/jdenticon.min.js"></script> + <!-- ionic/angular js --> <script src="lib/ionic/js/ionic.min.js"></script> diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js index 9f9efad676c8326808bf2e7f959701b58fcac998..40a5bcd7ffbddee5fcfdb8be7c03be76a56aecde 100644 --- a/www/js/controllers/wallet-controllers.js +++ b/www/js/controllers/wallet-controllers.js @@ -103,7 +103,7 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, return wallet.login() .then(function(walletData) { $scope.formData = walletData; - $scope.loading=false; // very important, to avoid TX to be display before wallet.currentUd is loaded + $scope.loading = false; // very important, to avoid TX to be display before wallet.currentUd is loaded $scope.updateView(); $scope.addListeners(); diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js index 4f109795863360d862e3fc27cc79ae9892c4fcfc..2e3c8645cbce6135e9e9365fe764b0d19a36f2df 100644 --- a/www/js/controllers/wot-controllers.js +++ b/www/js/controllers/wot-controllers.js @@ -204,13 +204,13 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i $scope.doGetPending(0, undefined, true/*skipLocationUpdate*/); } // get new comers - else if (params.type == 'newcomers' || (!csConfig.initPhase && !params.type)) { + else if (params.type === 'newcomers' || (!csConfig.initPhase && !params.type)) { $scope.doGetNewcomers(0, undefined, true/*skipLocationUpdate*/); } - else if (params.type == 'pending') { + else if (params.type === 'pending') { $scope.doGetPending(0, undefined, true/*skipLocationUpdate*/); } - else if (params.type == 'wallets') { + else if (params.type === 'wallets') { $scope.doGetWallets(0, undefined, true/*skipLocationUpdate*/); } @@ -263,7 +263,7 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i stateParams.q = text; } } - else if ($scope.search.type != 'last') { + else if ($scope.search.type !== 'last') { stateParams.type = $scope.search.type; } @@ -295,7 +295,7 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i $scope.search.type = 'text'; return csWot.search(text) .then(function(idties){ - if ($scope.search.type != 'text') return; // could have change + if ($scope.search.type !== 'text') return; // could have change if ($scope.search.text.trim() !== text) return; // search text has changed before received response if ((!idties || !idties.length) && (BMA.regexp.PUBKEY.test(text) || BMA.regexp.PUBKEY_WITH_CHECKSUM.test(text))) { @@ -366,7 +366,7 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i return searchFunction(offset, size) .then(function(res){ - if ($scope.search.type != 'pending') return false; // could have change + if ($scope.search.type !== 'pending') return false; // could have change $scope.doDisplayResult(res && res.hits, offset, size, res && res.total); // Always disable "more" on initphase $scope.search.hasMore = !csCurrency.data.initPhase && $scope.search.hasMore; @@ -397,7 +397,7 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i return csWallet.children.all() .then(function(children) { - if (!children || $scope.search.type != 'wallets') return false; // could have change + if (!children || $scope.search.type !== 'wallets') return false; // could have change var res = [csWallet].concat(children).reduce(function(res, wallet, index) { var item = { id: index, diff --git a/www/js/directives.js b/www/js/directives.js index e207a9262476cf31b7af36f58f8e8f45f5f91ff6..8f53b911f9690481c7a8221944d258e3ec3bcd61 100644 --- a/www/js/directives.js +++ b/www/js/directives.js @@ -213,6 +213,7 @@ angular.module('cesium.directives', []) // All this does is allow the message // to be sent when you tap return .directive('input', function($timeout) { + 'ngInject'; return { restrict: 'E', scope: { @@ -250,7 +251,8 @@ angular.module('cesium.directives', []) }; }) - .directive('trustAsHtml', ['$sce', '$compile', '$parse', function($sce, $compile, $parse){ + .directive('trustAsHtml', function($sce, $compile, $parse){ + 'ngInject'; return { restrict: 'A', compile: function (tElement, tAttrs) { @@ -272,12 +274,14 @@ angular.module('cesium.directives', []) }; } }; - }]) + }) /** * Close the current modal */ - .directive('modalClose', ['$ionicHistory', '$timeout', function($ionicHistory, $timeout) { + .directive('modalClose', function($ionicHistory, $timeout) { + 'ngInject'; + return { restrict: 'AC', link: function($scope, $element) { @@ -302,12 +306,14 @@ angular.module('cesium.directives', []) }); } }; - }]) + }) /** * Plugin extension point (see services/plugin-services.js) */ .directive('csExtensionPoint', function ($state, $compile, $controller, $templateCache, PluginService) { + 'ngInject'; + var getTemplate = function(extensionPoint) { var template = extensionPoint.templateUrl ? $templateCache.get(extensionPoint.templateUrl) : extensionPoint.template; if (!template) { @@ -353,6 +359,8 @@ angular.module('cesium.directives', []) }) .directive('onReadFile', function ($parse) { + 'ngInject'; + return { restrict: 'A', scope: false, @@ -382,7 +390,8 @@ angular.module('cesium.directives', []) }; }) -.directive("dropZone", function($parse) { + .directive("dropZone", function($parse) { + 'ngInject'; return { restrict: 'A', scope: false, @@ -429,8 +438,8 @@ angular.module('cesium.directives', []) // See http://embed.plnkr.co/2vgnFe/ - .directive('fileSelect', function ($parse) { - 'use strict'; + .directive('fileSelect', function($parse) { + 'ngInject'; return { restrict: 'A', @@ -484,6 +493,8 @@ angular.module('cesium.directives', []) // Un-authenticate when window closed // see: https://stackoverflow.com/questions/28197316/javascript-or-angularjs-defer-browser-close-or-tab-close-between-refresh .directive('windowExitUnauth', function($window, csSettings, csWallet) { + 'ngInject'; + return { restrict: 'AE', link: function(element, attrs){ @@ -497,4 +508,34 @@ angular.module('cesium.directives', []) }); } }; + }) + + // Jdenticon directive (to generate icon from a string) + // see: + .directive('jdenticon', function($parse) { + 'ngInject'; + + return { + restrict: 'A', + scope: false, + template: '<canvas></canvas>', + transclude: false, + link: function (scope, element, attrs) { + var value = attrs.jdenticon; + var size = attrs.jdenticonSize || 54; + var canvas = element.children('canvas')[0]; + + if (!value) { + canvas.height = 0; + canvas.width = 0; + } + else { + canvas.height = size; + canvas.width = size; + + var ctx = canvas.getContext("2d"); + jdenticon.drawIcon(ctx, value, size); + } + } + }; }); diff --git a/www/js/filters.js b/www/js/filters.js index b38b0cc2b272db1874761a404512b8b0a8064097..64a4d063485a910da22d5cd4e23eb511899e0c33 100644 --- a/www/js/filters.js +++ b/www/js/filters.js @@ -80,6 +80,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('formatAmount', function(csConfig, csSettings, csCurrency, $filter) { + 'ngInject'; var pattern = '0,0.0' + Array(csConfig.decimalCount || 4).join('0'); var patternBigNumber = '0,0.000 a'; var currencySymbol = $filter('currencySymbol'); @@ -124,6 +125,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('formatAmountNoHtml', function(csConfig, csSettings, csCurrency, $filter) { + 'ngInject'; var minValue = 1 / Math.pow(10, csConfig.decimalCount || 4); var format = '0,0.0' + Array(csConfig.decimalCount || 4).join('0'); var currencySymbol = $filter('currencySymbolNoHtml'); @@ -164,6 +166,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('currencySymbol', function(filterTranslations, $filter, csSettings) { + 'ngInject'; return function(input, useRelative) { if (!input) return ''; return (angular.isDefined(useRelative) ? useRelative : csSettings.data.useRelative) ? @@ -173,6 +176,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('currencySymbolNoHtml', function(filterTranslations, $filter, csSettings) { + 'ngInject'; return function(input, useRelative) { if (!input) return ''; return (angular.isDefined(useRelative) ? useRelative : csSettings.data.useRelative) ? @@ -182,6 +186,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('formatDecimal', function(csConfig, csCurrency) { + 'ngInject'; var minValue = 1 / Math.pow(10, csConfig.decimalCount || 4); var format = '0,0.0' + Array(csConfig.decimalCount || 4).join('0'); @@ -209,24 +214,28 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('formatDate', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)).local().format(filterTranslations.DATE_PATTERN || 'YYYY-MM-DD HH:mm') : ''; }; }) .filter('formatDateShort', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)).local().format(filterTranslations.DATE_SHORT_PATTERN || 'YYYY-MM-DD') : ''; }; }) .filter('formatDateMonth', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)).local().format(filterTranslations.DATE_MONTH_YEAR_PATTERN || 'MMM YY') : ''; }; }) .filter('formatDateForFile', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)).local().format(filterTranslations.DATE_FILE_PATTERN || 'YYYY-MM-DD') : ''; }; @@ -245,6 +254,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('formatFromNowAndDate', function(filterTranslations) { + 'ngInject'; return function(input, options) { var m = input && moment.unix(parseInt(input)); return m && (m.fromNow() + (options && options.separator || ' | ') + m.local().format(filterTranslations.DATE_PATTERN || 'YYYY-MM-DD HH:mm')) || ''; @@ -265,6 +275,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre .filter('formatDurationTime', function(filterTranslations) { + 'ngInject'; return function(input) { if (!input) return ''; var sign = input && input < 0 ? '-' : '+'; @@ -305,12 +316,14 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre /* -- median time (apply currency offset)-- */ .filter('medianDate', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input) + filterTranslations.MEDIAN_TIME_OFFSET).local().format(filterTranslations.DATE_PATTERN || 'YYYY-MM-DD HH:mm') : ''; }; }) .filter('medianDateShort', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input) + filterTranslations.MEDIAN_TIME_OFFSET).local().format(filterTranslations.DATE_SHORT_PATTERN || 'YYYY-MM-DD') : ''; }; @@ -318,24 +331,28 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre .filter('medianTime', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)+filterTranslations.MEDIAN_TIME_OFFSET).local().format('HH:mm') : ''; }; }) .filter('medianFromNow', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input) + filterTranslations.MEDIAN_TIME_OFFSET).fromNow() : ''; }; }) .filter('medianFromNowShort', function(filterTranslations) { + 'ngInject'; return function(input) { return input ? moment.unix(parseInt(input)+filterTranslations.MEDIAN_TIME_OFFSET).fromNow(true) : ''; }; }) .filter('medianFromNowAndDate', function(filterTranslations) { + 'ngInject'; return function(input, options) { var m = input && moment.unix(parseInt(input)+filterTranslations.MEDIAN_TIME_OFFSET); return m && (m.fromNow() + (options && options.separator || ' | ') + m.local().format(filterTranslations.DATE_PATTERN || 'YYYY-MM-DD HH:mm')) || ''; @@ -390,12 +407,37 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }; }) - .filter('formatPubkey', function() { - return function(input) { - return input ? input.substr(0,8) : ''; + .filter('formatPubkey', function(csCrypto) { + 'ngInject'; + return function(input, opts) { + if (!input || input.length < 43) return ''; + var result = (!opts || opts.full !== true) + // See RFC0016 + ? (input.substr(0,4) + '…' + input.substr(input.length - 4)) + : input; + // If given (e.g. already computed) use the existing CHK + if (opts && opts.checksum) { + result += ':' + opts.checksum; + } + // Crypto libs can be not loaded yet + else if (csCrypto.isStarted()){ + result += ':' + csCrypto.util.pkChecksum(input); + } + return result; }; }) + .filter('pkChecksum', function(csCrypto) { + 'ngInject'; + return function(input, opts) { + if (!input || input.length < 43) return ''; + if (opts && opts.prefix) { + return ':' + csCrypto.util.pkChecksum(input); + } + return csCrypto.util.pkChecksum(input); + }; + }) + .filter('formatHash', function() { return function(input) { return input ? input.substr(0,4) + input.substr(input.length-4) : ''; @@ -444,6 +486,7 @@ angular.module('cesium.filters', ['cesium.config', 'cesium.platform', 'pascalpre }) .filter('trustAsHtml', function($sce) { + 'ngInject'; return function(html) { return $sce.trustAsHtml(html); }; diff --git a/www/js/services/crypto-services.js b/www/js/services/crypto-services.js index 044653204a68c72959ea20fd72c9c17e2fa2dd2d..5dc11633055f603c7cd92ea3ad1e86013c0f5a04 100644 --- a/www/js/services/crypto-services.js +++ b/www/js/services/crypto-services.js @@ -405,7 +405,7 @@ angular.module('cesium.crypto.services', ['cesium.utils.services']) var naclOptions = {}; var scryptOptions = {}; if (ionic.Platform.grade.toLowerCase()!='a') { - console.info('Reduce NaCl memory to 16mb, because plateform grade is not [a] but [{0}]'.format(ionic.Platform.grade)); + console.info('Reduce NaCl memory to 16mb, because platform grade is not [a] but [{0}]'.format(ionic.Platform.grade)); naclOptions.requested_total_memory = 16 * 1048576; // 16 Mo } var loadedLib = 0; @@ -1007,6 +1007,15 @@ angular.module('cesium.crypto.services', ['cesium.utils.services']) BAD_CHECKSUM: 3002 }; + function ready() { + if (CryptoUtils.isLoaded()) return $q.when(); + return $timeout(ready, 100); + } + + function isStarted() { + return CryptoUtils.isLoaded(); + } + /* -- keyfile -- */ function readKeyFile(file, options) { @@ -1374,13 +1383,20 @@ angular.module('cesium.crypto.services', ['cesium.utils.services']) } } + /* -- Useful functions -- */ - - /* -- usefull methods -- */ - + /** + * Compute the pubkey checksum (see Duniter RFC0016) + */ function pkChecksum(pubkey) { - var signPk_int8 = CryptoUtils.util.decode_base58(pubkey); - return CryptoUtils.util.encode_base58(CryptoUtils.util.crypto_hash_sha256(CryptoUtils.util.crypto_hash_sha256(signPk_int8))).substring(0,3); + // Remove leading '1' (see https://forum.duniter.org/t/format-de-checksum/7616) + var signPk_int8 = pubkey && pubkey.length === 44 && pubkey.charAt(0) === '1' + ? CryptoUtils.util.decode_base58(pubkey.substr(1)) + : CryptoUtils.util.decode_base58(pubkey); + return CryptoUtils.util.encode_base58( + CryptoUtils.util.crypto_hash_sha256( + CryptoUtils.util.crypto_hash_sha256(signPk_int8)) + ).substring(0,3); } /* -- box (pack/unpack a record) -- */ @@ -1562,6 +1578,8 @@ angular.module('cesium.crypto.services', ['cesium.utils.services']) return { errorCodes: errorCodes, constants: constants, + ready: ready, + isStarted: isStarted, // copy CryptoUtils util: angular.extend({ pkChecksum: pkChecksum diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js index a756a437d8d7cebc61b62fe65b6cd09aa61dc729..147c2f1be127e64905bfb0de5fcc6515dd9b45e1 100644 --- a/www/js/services/device-services.js +++ b/www/js/services/device-services.js @@ -14,7 +14,6 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti MAX_HEIGHT: 400, MAX_WIDTH: 400 }, - that = this, api = new Api(this, "Device"), exports = { // workaround to quickly no is device or not (even before the ready() event) diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index 702c8f9d9033dec80fd9e56b500c2b50d7f60e4f..f392ccc0c94486484c70cd00edc5711790ae83d3 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -40,7 +40,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se resetData = function(init) { data.loaded = false; - data.pubkey= null; + data.pubkey = null; + data.checksum = null; data.qrcode=null; data.uid = null; @@ -566,12 +567,12 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se var seckey = res[0]; var pubkey = res[1]; var uid = res[2]; - if (!pubkey || pubkey == 'null') return; + if (!pubkey || pubkey === 'null') return; console.debug('[wallet] Restore {' + pubkey.substring(0, 8) + '} from local storage'); var keypair; - if (seckey && seckey.length && seckey != 'null') { + if (seckey && seckey.length && seckey !== 'null') { try { keypair = { signPk: CryptoUtils.util.decode_base58(pubkey), @@ -887,27 +888,32 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se loadPromise, // Create the QR code - loadQrCode() + loadQrCode(), + + // Compute the checksum (if need) + csCrypto.ready().then(function() { + data.checksum = data.checksum || csCrypto.util.pkChecksum(data.pubkey); + }) ]) - // Warn if wallet has been never used - see #167 .then(function() { - var unused = isNeverUsed(); + + // Warn if wallet has been never used - see #167 + var unused = alertIfUnusedWallet && isNeverUsed(); var showAlert = alertIfUnusedWallet && !isNew() && unused === true; if (!showAlert) return true; return UIUtils.loading.hide() - .then(function() { + .then(function () { return UIUtils.alert.confirm('CONFIRM.LOGIN_UNUSED_WALLET', 'CONFIRM.LOGIN_UNUSED_WALLET_TITLE', { cancelText: 'COMMON.BTN_CONTINUE', okText: 'COMMON.BTN_RETRY' }); }) - .then(function(retry) { + .then(function (retry) { if (retry) { - return logout().then(function() { + return logout().then(function () { throw 'RETRY'; }); - } - else { + } else { // Remembering to not ask for confirmation if (csSettings.data.wallet.alertIfUnusedWallet) { csSettings.data.wallet.alertIfUnusedWallet = false; @@ -924,8 +930,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se if (confirm) { return data; } - else { // cancel - + else { // user cancelled throw 'CANCELLED'; } }); @@ -2082,7 +2087,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se newChildInstance = function() { // Return max(id) + 1 - var walletId = (data.children || []).reduce(function(res, wallet) { + var walletId = (data.children || []).reduce(function(res, wallet) { return Math.max(res, wallet.id); }, 0) + 1; return service.instance(walletId, BMA); diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html index 04135d8cf557f01e7ee1e8081b48be7eee13989b..46e73710ec8d83e5b3379ad2d1015354714f21e2 100644 --- a/www/templates/wallet/view_wallet.html +++ b/www/templates/wallet/view_wallet.html @@ -130,12 +130,17 @@ <!-- Public key --> <div id="helptip-wallet-pubkey" - class="item item-icon-left item-text-wrap ink" + class="item item-icon-left item-text-wrap item-icon-right ink" on-hold="copy(formData.pubkey)" - copy-on-click="{{:rebind:formData.pubkey}}"> + copy-on-click="{{:rebind:formData.pubkey|formatPubkey: {full: true, checksum: formData.checksum} }}"> <i class="icon ion-key"></i> <span>{{:locale:'COMMON.PUBKEY'|translate}}</span> - <h4 id="pubkey" class="dark">{{:rebind:formData.pubkey}}</h4> + <h4 id="pubkey" class="dark"> + {{:rebind:formData.pubkey|formatPubkey: {full: true, checksum: formData.checksum} }} + </h4> + + <!-- icon of the pubkey --> + <i class="icon" ng-if=":rebind:formData.pubkey" jdenticon="{{:rebind:formData.pubkey}}" jdenticon-size="32"></i> </div> <!-- Uid + Registration date --> diff --git a/www/templates/wot/item_content_identity.html b/www/templates/wot/item_content_identity.html index 70b500fe41e24ae4421b563868f6bdaa9e3d3d49..02e29bcea0c447bd0719a1166adcf9e7fbac9cc7 100644 --- a/www/templates/wot/item_content_identity.html +++ b/www/templates/wot/item_content_identity.html @@ -10,13 +10,13 @@ ng-class="{'pull-right': !smallscreen}" ng-if="::item.sigDate"> <i class="ion-clock"></i> - {{::'WOT.LOOKUP.REGISTERED' | translate:item }} + {{:locale:'WOT.LOOKUP.REGISTERED' | translate:item }} </h4> <h4 class="gray" ng-class="{'pull-right': !smallscreen}" ng-if="item.memberDate"> <i class="ion-clock"></i> - {{::'WOT.LOOKUP.MEMBER_FROM' | translate:item}} + {{:locale:'WOT.LOOKUP.MEMBER_FROM' | translate:item}} </h4> <h4 class="gray"> <span class="positive" ng-if="::item.name && item.uid"> @@ -25,6 +25,7 @@ </span> <b class="ion-key"></b> {{::item.pubkey | formatPubkey}} + <span ng-if="::(!item.uid && !item.revoked)" class="assertive" translate>WOT.NOT_MEMBER_PARENTHESIS</span> <span ng-if="::item.revoked" class="assertive" translate>WOT.IDENTITY_REVOKED_PARENTHESIS</span> </h4> diff --git a/www/templates/wot/lookup_form.html b/www/templates/wot/lookup_form.html index 849b55fadb3235f69a72bcbdcea74d220a45652d..01a8005ffdc52851ee227c2c0905ecbc7ca3d1fe 100644 --- a/www/templates/wot/lookup_form.html +++ b/www/templates/wot/lookup_form.html @@ -1,4 +1,4 @@ -<div class="lookupForm"> +<div class="lookupForm" bind-notifier="{locale: $root.settings.locale.id}"> <div class="item no-padding"> @@ -22,7 +22,7 @@ <input type="text" class="visible-xs visible-sm" - placeholder="{{'WOT.SEARCH_HELP'|translate}}" + placeholder="{{:locale:'WOT.SEARCH_HELP'|translate}}" ng-model="search.text" ng-model-options="{ debounce: 650 }" ng-change="doSearch()" @@ -30,7 +30,7 @@ select-on-click> <input type="text" class="hidden-xs hidden-sm" - id="{{wotSearchTextId}}" placeholder="{{'WOT.SEARCH_HELP'|translate}}" + id="{{wotSearchTextId}}" placeholder="{{:locale:'WOT.SEARCH_HELP'|translate}}" ng-model="search.text" on-return="doSearchText()"> <div class="helptip-anchor-center"> @@ -43,7 +43,7 @@ ng-class="::{'hidden-xs hidden-sm': !showResultLabel}"> <div class="pull-left" ng-if="!search.loading && showResultLabel"> <ng-if ng-if="search.type=='newcomers'"> - <h4 translate>WOT.LOOKUP.NEWCOMERS</h4> + <h4>{{:locale:'WOT.LOOKUP.NEWCOMERS'|translate}}</h4> <small class="gray no-padding" ng-if="search.total">{{'WOT.LOOKUP.NEWCOMERS_COUNT'|translate:{count: search.total} }}</small> </ng-if> <ng-if ng-if="search.type=='pending'"> @@ -51,7 +51,7 @@ <small class="gray no-padding" ng-if="search.total">{{'WOT.LOOKUP.PENDING_COUNT'|translate:{count: search.total} }}</small> </ng-if> <h4 ng-if="search.type=='text'"> - <span translate>COMMON.RESULTS_LIST</span> + <span>{{:locale:'COMMON.RESULTS_LIST'|translate}}</span> <small class="gray" ng-if="search.total">({{search.total}})</small> </h4> </div> @@ -63,14 +63,14 @@ ng-class="{'button-text-positive': search.type=='newcomers'}" ng-click="doGetNewcomers()"> <i class="icon ion-person-stalker"></i> - {{'WOT.LOOKUP.BTN_NEWCOMERS' | translate}} + {{:locale:'WOT.LOOKUP.BTN_NEWCOMERS' | translate}} </a> <a ng-if="enableFilter" class="button button-text button-small ink" ng-class="{'button-text-positive': search.type=='pending'}" ng-click="doGetPending()" class="badge-balanced"> <i class="icon ion-clock"></i> - {{'WOT.LOOKUP.BTN_PENDING' | translate}} + {{:locale:'WOT.LOOKUP.BTN_PENDING' | translate}} </a> <a ng-if="enableWallets" class="button button-text button-small ink" @@ -78,7 +78,7 @@ ng-click="doGetWallets()" class="badge-balanced"> <i class="icon ion-card" style="left: -1px; top: 4px; position: relative; padding-left: 3px; padding-right: 3px;"></i> <b class="icon-secondary ion-card" style="left: 10px; top: -4px; font-size: 14px;"> </b> - {{'MENU.WALLETS' | translate}} + {{:locale:'MENU.WALLETS' | translate}} </a> <!-- Allow extension here --> @@ -86,14 +86,14 @@ <button class="button button-small button-stable ink" ng-click="doSearch()"> - {{'COMMON.BTN_SEARCH' | translate}} + {{:locale:'COMMON.BTN_SEARCH' | translate}} </button> <button class="button button-small button-positive {{parameters.okType}} ink" ng-if="::allowMultiple" ng-disabled="!selection.length" ng-click="next()"> - {{parameters.okText||'COMMON.BTN_NEXT' | translate}} + {{:locale:parameters.okText||'COMMON.BTN_NEXT' | translate}} </button> </div> </div> @@ -105,9 +105,9 @@ <ng-if ng-if="!search.loading"> <div class="assertive padding" ng-if="!search.results.length"> - <span ng-if="search.type=='text'" translate>COMMON.SEARCH_NO_RESULT</span> - <span ng-if="search.type=='pending'" translate>WOT.LOOKUP.NO_PENDING</span> - <span ng-if="search.type=='newcomers'" translate>WOT.LOOKUP.NO_NEWCOMERS</span> + <span ng-if="search.type=='text'">{{:locale:'COMMON.SEARCH_NO_RESULT'|translate}}</span> + <span ng-if="search.type=='pending'">{{:locale:'WOT.LOOKUP.NO_PENDING'|translate}}</span> + <span ng-if="search.type=='newcomers'">{{:locale:'WOT.LOOKUP.NO_NEWCOMERS'|translate}}</span> </div> <!-- simple selection + device --> @@ -120,14 +120,14 @@ <ng-repeat ng-repeat="item in search.results track by item.id"> <div ng-if="::item.divider" class="item item-divider" - id="helptip-wot-search-result-{{$index}}">{{::('WOT.SEARCH.DIVIDER_' + item.index)|upper|translate}}</div> + id="helptip-wot-search-result-{{$index}}">{{:locale:('WOT.SEARCH.DIVIDER_' + item.index)|upper|translate}}</div> <ion-item ng-if="::!item.divider" id="helptip-wot-search-result-{{$index}}" class="item item-border-large item-avatar item-icon-right ink" ng-click="::select(item)"> - <ng-include src="item.templateUrl || 'templates/wot/item_content_identity.html'"></ng-include> + <ng-include src="::item.templateUrl || 'templates/wot/item_content_identity.html'"></ng-include> <i class="icon ion-ios-arrow-right "></i> <ion-option-button diff --git a/www/templates/wot/view_certifications.html b/www/templates/wot/view_certifications.html index 2981a7d4b7fc5279b370938ed61c5cf5c4783338..2d3ae0a5b35a74dd3ba8cde8f27f95c87d446151 100644 --- a/www/templates/wot/view_certifications.html +++ b/www/templates/wot/view_certifications.html @@ -73,9 +73,14 @@ ng-class="{'positive': formData.isMember, 'gray': !formData.isMember}"> {{::formData.name||formData.uid}} </h4> - <h5 class="text-center gray"> - <i class="icon ion-key"></i> {{formData.pubkey|formatPubkey}} + <h5 class="text-center gray row no-padding"> + <div class="col"> + <i class="icon ion-key"></i> {{formData.pubkey|formatPubkey}} + </div> + <!-- icon of the pubkey --> + <div class="col" ng-if=":rebind:formData.pubkey" jdenticon="{{:rebind:formData.pubkey}}" jdenticon-size="32"></div> </h5> + <h5 class="assertive"> <span ng-if="::(formData.name || formData.uid) && !formData.isMember && !revoked" translate>WOT.NOT_MEMBER_PARENTHESIS</span> <b ng-if="::(formData.name || formData.uid) && !formData.isMember && revoked" translate>WOT.IDENTITY_REVOKED_PARENTHESIS</b> diff --git a/www/templates/wot/view_identity.html b/www/templates/wot/view_identity.html index 6c1b8328b19e3f9da305eb283e87cdb1fa802867..dd28c816f74e879273ae81df545c4b85d9203b21 100644 --- a/www/templates/wot/view_identity.html +++ b/www/templates/wot/view_identity.html @@ -89,12 +89,17 @@ <span class="item item-divider" translate>WOT.GENERAL_DIVIDER</span> <!-- Pubkey --> - <ion-item class="item-icon-left item-text-wrap ink" - copy-on-click="{{:rebind:formData.pubkey}}"> + <div class="item item-icon-left item-text-wrap item-icon-right ink" + ng-if=":rebind:formData.pubkey" + on-hold="copy(formData.pubkey)" + copy-on-click="{{:rebind:formData.pubkey|formatPubkey: {full: true } }}"> <i class="icon ion-key"></i> <span translate>COMMON.PUBKEY</span> - <h4 id="pubkey" class="dark text-left">{{:rebind:formData.pubkey}}</h4> - </ion-item> + <h4 id="pubkey" class="dark text-left">{{:rebind:formData.pubkey|formatPubkey: {full: true } }}</h4> + + <!-- icon of the pubkey --> + <i class="icon" jdenticon="{{::formData.pubkey}}" jdenticon-size="32"></i> + </div> <div class="item item-icon-left item-text-wrap" ng-if=":rebind:!formData.hasSelf"> diff --git a/yarn.lock b/yarn.lock index 17097a320af00a8e242ce6ac0943ad3b1c2e0ae5..6875d8ebfcf06935fe33de9c7462d73feef62786 100644 --- a/yarn.lock +++ b/yarn.lock @@ -198,6 +198,12 @@ version "0.0.0" resolved "https://codeload.github.com/driftyco/ionic-bower/tar.gz/816a8b26fae3e8305162eefe1114415503391be6" +"@bower_components/jdenticon@dmester/jdenticon#3.1.0": + version "3.1.0" + resolved "https://codeload.github.com/dmester/jdenticon/tar.gz/54fb9c1d1d66d5eb6849583cca219ae6ab986ee5" + dependencies: + canvas-renderer "~2.2.0" + "@bower_components/js-nacl@tonyg/js-nacl#1.3.2": version "1.3.2" resolved "https://codeload.github.com/tonyg/js-nacl/tar.gz/883f9d3cd9b6bbce84dc489ae4c2d87ffd653a18" @@ -1889,6 +1895,13 @@ camelcase@^3.0.0: resolved "https://nexus.e-is.pro/nexus/content/repositories/npmjs/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= +canvas-renderer@~2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/canvas-renderer/-/canvas-renderer-2.2.0.tgz#512151f5494aaac5270802fba22599785114716d" + integrity sha512-Itdq9pwXcs4IbbkRCXc7reeGBk6i6tlDtZTjE1yc+KvYkx1Mt3WLf6tidZ/Ixbm7Vmi+jpWKG0dRBor67x9yGw== + dependencies: + "@types/node" "*" + caseless@~0.11.0: version "0.11.0" resolved "https://nexus.e-is.pro/nexus/content/repositories/npmjs/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7"