From 30bcb06d9cf3892f17572af3d460004c0f3c227d Mon Sep 17 00:00:00 2001 From: Benoit Lavenier <benoit.lavenier@e-is.pro> Date: Tue, 3 Mar 2020 12:53:51 +0100 Subject: [PATCH] [fix] Blockchain explorer: optimize refresh using a block id; [fix] UI: fix top refresher background, in wallet and identity views; [fix] Websocket: make sure socket is not closed, before reuse it; [enh] ES (user and page): allow user to send like and abuse report. [enh] ES Graph: use the optimized extension controller, for extension point; [enh] ES Graph: remove stats button, on the identity view (keep it onl in the TX history) --- doc/privacy_policy.md | 4 +- scss/ionic.app.scss | 99 ++---- www/css/style.css | 11 +- www/i18n/locale-en-GB.json | 1 - www/i18n/locale-en.json | 1 - www/i18n/locale-eo-EO.json | 3 +- www/i18n/locale-es-ES.json | 1 - www/i18n/locale-fr-FR.json | 5 +- www/i18n/locale-it-IT.json | 1 - www/i18n/locale-nl-NL.json | 1 - www/index.html | 1 + www/js/controllers/wallet-controllers.js | 5 +- www/js/controllers/wot-controllers.js | 21 +- www/js/entities/block.js | 2 + www/js/services/bma-services.js | 4 +- www/js/services/wallet-services.js | 62 ++-- www/js/services/wot-services.js | 6 +- www/plugins/es/css/style.css | 16 + www/plugins/es/i18n/locale-en-GB.json | 42 ++- www/plugins/es/i18n/locale-en.json | 42 ++- www/plugins/es/i18n/locale-eo-EO.json | 46 ++- www/plugins/es/i18n/locale-es-ES.json | 2 +- www/plugins/es/i18n/locale-fr-FR.json | 60 +++- www/plugins/es/i18n/locale-it-IT.json | 2 +- www/plugins/es/i18n/locale-nl-NL.json | 2 +- .../es/js/controllers/common-controllers.js | 281 ++++++++++++++++++ .../es/js/controllers/registry-controllers.js | 18 +- .../es/js/controllers/wallet-controllers.js | 39 ++- .../es/js/controllers/wot-controllers.js | 64 +++- www/plugins/es/js/entities/notification.js | 95 +++++- www/plugins/es/js/services.js | 3 +- .../es/js/services/comment-services.js | 2 +- www/plugins/es/js/services/http-services.js | 47 +-- www/plugins/es/js/services/like-services.js | 153 ++++++++++ .../es/js/services/profile-services.js | 7 +- .../es/js/services/registry-services.js | 5 +- .../templates/common/popup_report_abuse.html | 37 +++ .../es/templates/common/view_likes.html | 25 ++ .../templates/network/item_content_peer.html | 2 +- .../notification/view_notifications.html | 2 +- .../registry/view_popover_actions.html | 15 +- .../es/templates/registry/view_record.html | 39 ++- .../templates/wallet/view_wallet_extend.html | 12 +- .../templates/wot/view_identity_extend.html | 27 +- .../templates/wot/view_popover_actions.html | 40 +++ .../js/controllers/account-controllers.js | 42 +-- .../account/view_identity_extend.html | 9 - .../account/view_identity_tx_extend.html | 4 +- .../account/view_wallet_tx_extend.html | 4 +- .../templates/currency/tab_blocks_extend.html | 2 +- .../currency/view_currency_extend.html | 6 +- .../network/view_es_peer_extend.html | 2 +- .../templates/network/view_peer_extend.html | 2 +- www/templates/blockchain/list_blocks_lg.html | 2 +- www/templates/wallet/view_wallet.html | 5 +- www/templates/wot/view_identity.html | 12 +- 56 files changed, 1167 insertions(+), 276 deletions(-) create mode 100644 www/plugins/es/js/services/like-services.js create mode 100644 www/plugins/es/templates/common/popup_report_abuse.html create mode 100644 www/plugins/es/templates/common/view_likes.html create mode 100644 www/plugins/es/templates/wot/view_popover_actions.html delete mode 100644 www/plugins/graph/templates/account/view_identity_extend.html diff --git a/doc/privacy_policy.md b/doc/privacy_policy.md index 3c35672c6..3560e3ba1 100644 --- a/doc/privacy_policy.md +++ b/doc/privacy_policy.md @@ -1,6 +1,6 @@ ## Privacy policy -Android build allow user to upload user profile (avatar, pictures) used by the Cesium+ extension. +Cesium Android allow user to upload user profile (avatar, pictures), when the Cesium+ extension has been enable in settings. ### Cesium+ profile @@ -8,4 +8,4 @@ Privacy policy are : - Profile data and avatar are public data; - Profile data and avatar on an [ES Duniter4j node](https://github.com/duniter/duniter4j); Open Cesium+ settings to known the node address; -- To totally remove your profile and avatar (if you use our official server [data.gtest.duniter.fr](http://data.gtest.duniter.fr)), please contact us at https://github.com/blavenie. \ No newline at end of file +- User can remove profile and avatar (open the Settings page, then use the options menu). \ No newline at end of file diff --git a/scss/ionic.app.scss b/scss/ionic.app.scss index c5827b92e..868ee51ba 100644 --- a/scss/ionic.app.scss +++ b/scss/ionic.app.scss @@ -910,86 +910,17 @@ html, body { * 'ion-refresher' *******/ -body { - // Set default refresher background height (for android) - --refresher-bg-height: 100px; - - // Set default refresher background - --refresher-background-color: inherit; - -} - -.refresher-positive-900-bg { - --refresher-background-color: #{$positive-900-bg}; -} - -.refresher-dark-100-bg { - --refresher-background-color: #{$dark-100-bg}; -} - .platform-android { - // Workaround to control background of 'ion-refresher' - .refresher-positive-900-bg:before, - .refresher-dark-100-bg:before { - background-color: var(--refresher-background-color); - position: absolute; - display: block; - top: 0; - width: 100%; - height: var(--refresher-bg-height, 100px); - z-index: -10; - content: " "; - } - .scroll-refresher { z-index: 50; } } -.platform-ios { - .refresher-positive-900-bg, - .refresher-dark-100-bg { - - // use light color for icon and text - //@extend .refresher-light; - - background-color: var(--refresher-background-color) !important; - - .scroll { - background-color: #fff; - bottom: auto; - min-height: 100%; - } - } -} - -// Lighter style for refresher (icon and text) -.refresher-light { - .scroll-refresher { - .ionic-refresher-content { - color: $light; - } - - .spinner { - stroke: $light; - fill: $light; - } - } -} - -.refresher-positive-900-bg, -.refresher-dark-100-bg { - @extend .refresher-light; -} - /****** * Wallet view *******/ .view-wallet { - // Set refresher background height (for android) - --refresher-bg-height: 200px; - .hero { height: 200px; @@ -1113,7 +1044,6 @@ body { *******/ @media screen and (max-width: $screen-sm-max) { .view-wallet-tx { - --refresher-bg-height: 100px; .hero { height: 100px; @@ -1123,7 +1053,6 @@ body { @media screen and (min-width: $screen-md) { .view-wallet-tx { - --refresher-bg-height: 140px; .hero { height: 140px; @@ -1230,20 +1159,16 @@ body { *******/ .view-identity { - // Set refresher background height (for android) - --refresher-bg-height: 200px; - // Default wallet color - --refresher-background-color: #{$dark-100-bg}; + --background-color: #{$dark-100-bg}; - // if member wallet, change wallet color .member { - --refresher-background-color: #{$positive-900-bg}; + --background-color: #{$positive-900-bg}; } .hero { height: 200px; - background-color: var(--refresher-background-color); + background-color: var(--background-color); } @@ -2606,3 +2531,21 @@ div[dropzone]:hover { } } } + +/* -- likes -- */ +.hero .likes { + .gray { + color: white !important; + } + a.positive, + .positive a, + .positive i, + .positive { + color: $calm !important; + } +} + +.view-wallet .hero .likes a { + user-select: none !important; + pointer-events: none; +} diff --git a/www/css/style.css b/www/css/style.css index f8bcc3291..3cb65f89e 100644 --- a/www/css/style.css +++ b/www/css/style.css @@ -145,6 +145,14 @@ display:none; } +.no-margin { + margin: 0 !important; +} + +/********** + Settings items +**********/ + .settings .item-divider { background-color: #f5f5f5; } @@ -164,9 +172,6 @@ .settings .item .badge { top: 22px; } -.no-margin { - margin: 0 !important; -} /********** Network/Peer items diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json index 60c0deb56..9aabaca37 100644 --- a/www/i18n/locale-en-GB.json +++ b/www/i18n/locale-en-GB.json @@ -694,7 +694,6 @@ "SEND_CERTIFICATION_FAILED": "Could not certify identity.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "You could not send certification, because your account is <b>not a member account</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "You could not send certification now, because your are <b>not a member</b> yet.<br/><br/>You still need certification to become a member.", - "NOT_MEMBER_FOR_CERTIFICATION": "Your account is not a member account yet.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "This account could not be certified. No registration found, or need to renew.", "LOGIN_FAILED": "Error while sign in.", "LOAD_IDENTITY_FAILED": "Could not load identity.", diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json index 725db3dbf..7213317ac 100644 --- a/www/i18n/locale-en.json +++ b/www/i18n/locale-en.json @@ -694,7 +694,6 @@ "SEND_CERTIFICATION_FAILED": "Could not certify identity.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "You could not send certification, because your account is <b>not a member account</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "You could not send certification now, because your are <b>not a member</b> yet.<br/><br/>You still need certification to become a member.", - "NOT_MEMBER_FOR_CERTIFICATION": "Your account is not a member account yet.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "This account could not be certified. No registration found, or need to renew.", "LOGIN_FAILED": "Error while sign in.", "LOAD_IDENTITY_FAILED": "Could not load identity.", diff --git a/www/i18n/locale-eo-EO.json b/www/i18n/locale-eo-EO.json index e27d28d7e..e8287d68e 100644 --- a/www/i18n/locale-eo-EO.json +++ b/www/i18n/locale-eo-EO.json @@ -435,7 +435,7 @@ "MESSAGE": "<i class=\"ion-android-time\"></i> Vi estis <b>malkonektita</b> aÅtomate, pro tro longa senaktiveco.", "BTN_RELOGIN": "RekonektiÄi", "IDLE_WARNING": "Vi estos malkonektita... {{countdown}}" - }, + }, "METHOD": { "SCRYPT_DEFAULT": "Sekreta identigilo kaj pasvorto", "SCRYPT_ADVANCED": "Sperta salumado", @@ -694,7 +694,6 @@ "SEND_CERTIFICATION_FAILED": "Atestado malsukcesa", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "Vi ne povas efektivigi atestadon, ĉar via konto <b>ne estas membro</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "Vi ne povas efektivigi atestadon, ĉar via konto ankoraÅ ne estas membro.<br/><br/>AnkoraÅ mankas al vi atestaĵoj, aÅ tiuj ĉi ankoraÅ ne estis validigitaj.", - "NOT_MEMBER_FOR_CERTIFICATION": "Via konto ankoraÅ ne estas membro.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "Konto ne atestebla. Neniu aliÄo-peto estis farita, aÅ la aliÄo ne estis revalidigita.", "LOGIN_FAILED": "Eraro dum konektiÄo.", "LOAD_IDENTITY_FAILED": "Eraro por ÅarÄi la identecon.", diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json index b34ee8085..aa1c119bb 100644 --- a/www/i18n/locale-es-ES.json +++ b/www/i18n/locale-es-ES.json @@ -643,7 +643,6 @@ "SEND_CERTIFICATION_FAILED": "Error de la certificación.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "No se puede certificar, porque su cuenta no <b>es miembro</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "No se puede certificar, porque su cuenta ya no es miembro.<br/><br/>TodavÃa faltan certificaciones, o ahora no son validas.", - "NOT_MEMBER_FOR_CERTIFICATION": "Su cuenta todavÃa no es miembro.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "Cuenta no certificable. No se ha solicitado la adhesión, o no fue renovada.", "LOGIN_FAILED": "Error durante la autentificación.", "LOAD_IDENTITY_FAILED": "Error de carga de la identidad.", diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json index 1ba9781ba..7307bce2e 100644 --- a/www/i18n/locale-fr-FR.json +++ b/www/i18n/locale-fr-FR.json @@ -692,9 +692,8 @@ "SALT_NOT_CONFIRMED": "Ne correspond pas à l'identifiant secret", "SEND_IDENTITY_FAILED": "Échec de l'inscription", "SEND_CERTIFICATION_FAILED": "Échec de la certification", - "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "Vous ne pouvez pas effectuer de certification, car votre compte n'est <b>pas membre</b>.", - "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "Vous ne pouvez pas effectuer de certification, car votre compte n'est pas encore membre.<br/><br/>Il vous manque encore des certifications, ou bien celles-ci n'ont pas encore été validées.", - "NOT_MEMBER_FOR_CERTIFICATION": "Votre compte n'est pas encore membre.", + "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "Vous ne pouvez pas effectuer de certification, car ce compte n'est <b>pas membre</b>.", + "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "Vous ne pouvez pas effectuer de certification, car ce compte n'est pas encore membre.<br/><br/>Il vous manque encore des certifications, ou bien celles-ci n'ont pas encore été validées.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "Compte non certifiable. Aucune demande d'adhésion n'a été faite, ou bien elle n'a pas été renouvelée.", "LOGIN_FAILED": "Erreur lors de la connexion.", "LOAD_IDENTITY_FAILED": "Erreur de chargement de l'identité.", diff --git a/www/i18n/locale-it-IT.json b/www/i18n/locale-it-IT.json index 4d3f3407d..9baa8dacb 100644 --- a/www/i18n/locale-it-IT.json +++ b/www/i18n/locale-it-IT.json @@ -630,7 +630,6 @@ "SEND_CERTIFICATION_FAILED": "Certificazione fallita.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "Non puoi inviare certificazioni perche tuo conto <b>non è ancora un conto membro</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "Non puoi inviare certificazioni adesso perche <b>non sei ancora membro</b>.<br/><br/>Devi ancora entrare nella WOT.", - "NOT_MEMBER_FOR_CERTIFICATION": "Tuo conto non è ancora un conto membro.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "Impossibile certificare questo conto. Nessuna richiesta di certificazione trovata o bisogna rinnovarla.", "LOGIN_FAILED": "Errore di login.", "LOAD_IDENTITY_FAILED": "Impossibile caricare la tua identità .", diff --git a/www/i18n/locale-nl-NL.json b/www/i18n/locale-nl-NL.json index 1384445cc..9949b11df 100644 --- a/www/i18n/locale-nl-NL.json +++ b/www/i18n/locale-nl-NL.json @@ -434,7 +434,6 @@ "SEND_CERTIFICATION_FAILED": "Could not certify identity.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY": "You could not send certification, because your account is <b>not a member account</b>.", "NEED_MEMBER_ACCOUNT_TO_CERTIFY_HAS_SELF": "You could not send certification now, because your are <b>not a member</b> yet.<br/><br/>You still need certification to become a member.", - "NOT_MEMBER_FOR_CERTIFICATION": "Your account is not a member account yet.", "IDENTITY_TO_CERTIFY_HAS_NO_SELF": "This account could not be certified. No registration found, or need to renew.", "LOGIN_FAILED": "Error while sign in.", "LOAD_IDENTITY_FAILED": "Could not load identity.", diff --git a/www/index.html b/www/index.html index d742b7bd3..9fc89e506 100644 --- a/www/index.html +++ b/www/index.html @@ -211,6 +211,7 @@ <script src="dist/dist_js/plugins/es/js/services/geo-services.js"></script> <script src="dist/dist_js/plugins/es/js/services/document-services.js"></script> <script src="dist/dist_js/plugins/es/js/services/network-services.js"></script> + <script src="dist/dist_js/plugins/es/js/services/like-services.js"></script> <script src="dist/dist_js/plugins/es/js/controllers/common-controllers.js"></script> <script src="dist/dist_js/plugins/es/js/controllers/app-controllers.js"></script> <script src="dist/dist_js/plugins/es/js/controllers/settings-controllers.js"></script> diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js index a7710f06a..e14831fa9 100644 --- a/www/js/controllers/wallet-controllers.js +++ b/www/js/controllers/wallet-controllers.js @@ -65,7 +65,10 @@ function WalletController($scope, $rootScope, $q, $ionicPopup, $timeout, $state, $scope.settings = csSettings.data; $scope.qrcodeId = 'qrcode-wallet-' + $scope.$id; $scope.toggleQRCode = false; - + $scope.likeData = { + likes: {}, + abuses: {} + }; var wallet; diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js index 2e95963f7..f7fc54dd4 100644 --- a/www/js/controllers/wot-controllers.js +++ b/www/js/controllers/wot-controllers.js @@ -254,7 +254,7 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i type: undefined }; - if ($scope.search.type == 'text') { + if ($scope.search.type === 'text') { var text = $scope.search.text.trim(); if (text.match(/^#[\wḡĞǦğà áâãäåçèéêëìÃîïðòóôõöùúûüýÿ]+$/)) { stateParams.hash = text.substr(1); @@ -283,16 +283,15 @@ function WotLookupController($scope, $state, $q, $timeout, $focus, $location, $i }; $scope.doSearch = function() { - $scope.search.loading = true; var text = $scope.search.text.trim(); if ((UIUtils.screen.isSmall() && text.length < 3) || !text.length) { $scope.search.results = undefined; - $scope.search.loading = false; $scope.search.type = 'none'; $scope.search.total = undefined; return $q.when(); } + $scope.search.loading = true; $scope.search.type = 'text'; return csWot.search(text) .then(function(idties){ @@ -1040,7 +1039,20 @@ function WotIdentityViewController($scope, $rootScope, $controller, $timeout, $s $scope.motion = UIUtils.motion.fadeSlideInRight; $scope.qrcodeId = 'qrcode-wot-' + $scope.$id; + // Init likes here, to be able to use in extension + $scope.options = $scope.options || {}; + $scope.options.like = { + kinds: ['LIKE', 'ABUSE'], + index: 'user', + type: 'profile' + }; + $scope.likeData = { + likes: {}, + abuses: {} + }; + $scope.$on('$ionicView.enter', function(e, state) { + var onLoadSuccess = function() { $scope.doMotion(); if (state.stateParams && state.stateParams.action) { @@ -1049,6 +1061,9 @@ function WotIdentityViewController($scope, $rootScope, $controller, $timeout, $s }, 100); $scope.removeActionParamInLocationHref(state); + + // Need by like controller + $scope.likeData.id = $scope.formData.pubkey; } $scope.showQRCode(); diff --git a/www/js/entities/block.js b/www/js/entities/block.js index 399578121..e3958e0b6 100644 --- a/www/js/entities/block.js +++ b/www/js/entities/block.js @@ -31,6 +31,8 @@ function Block(json, attributes) { that.transactionsCount = that.transactions ? that.transactions.length : 0; that.empty = that.isEmpty(); + + that.id = [that.number, that.hash].join('-'); } Block.prototype.isEmpty = function(){ diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js index 5ce668f05..cd80ab65e 100644 --- a/www/js/services/bma-services.js +++ b/www/js/services/bma-services.js @@ -147,7 +147,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. get = function (path, cacheTime) { - cacheTime = that.useCache && cacheTime; + cacheTime = that.useCache && cacheTime || 0 /* no cache*/ ; var cacheKey = path + (cacheTime ? ('#'+cacheTime) : ''); var getRequestFn = function(params) { @@ -415,7 +415,7 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium. } }, wot: { - lookup: get('/wot/lookup/:search', csHttp.cache.MEDIUM), + lookup: get('/wot/lookup/:search'), certifiedBy: get('/wot/certified-by/:pubkey'), certifiersOf: get('/wot/certifiers-of/:pubkey'), member: { diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js index c2aa7b25d..dc704cd2d 100644 --- a/www/js/services/wallet-services.js +++ b/www/js/services/wallet-services.js @@ -11,7 +11,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se var defaultBMA = BMA; var service; - function factory(id, BMA) { + function csWallet(id, BMA) { BMA = BMA || defaultBMA; var @@ -241,7 +241,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se return keepAuth ? data : angular.merge({}, data, authData); }) .catch(function(err) { - if (err == 'RETRY' && (!options || !options.authData)) { + if (err === 'RETRY' && (!options || !options.authData)) { return $timeout(function(){ return login(options); }, 300); @@ -385,7 +385,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se // store pubkey and uid store = function(pubkey) { pubkey = pubkey && typeof pubkey == 'string' ? pubkey : data.pubkey; - if (settings.useLocalStorage) { + if (settings && settings.useLocalStorage) { if (isLogin() && settings.rememberMe) { @@ -450,7 +450,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se localStorage.put(constants.STORAGE_PUBKEY, null); localStorage.put(constants.STORAGE_UID, null); - if (settings.useLocalStorage) { + if (settings && settings.useLocalStorage) { // Clean data (only in the session storage - keep local) return pubkey ? sessionStorage.put(constants.STORAGE_DATA_PREFIX + pubkey, null) : $q.when(); } @@ -467,7 +467,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se storeData = function() { if (!isLogin()) throw {message:'ERROR.NEED_LOGIN_FIRST'}; - var useEncryption = settings.useLocalStorageEncryption; + var useEncryption = settings && settings.useLocalStorageEncryption; var storageKey = constants.STORAGE_DATA_PREFIX + data.pubkey; var content; // Init only if used @@ -648,7 +648,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se _.forEach(content.children, function(child) { if (!pubkeys[child.pubkey]) { // make sure wallet is unique by pubkey pubkeys[child.pubkey] = true; - var wallet = getNewChildrenInstance(); + var wallet = newChildInstance(); wallet.data.pubkey = child.pubkey; wallet.data.localName = child.localName; wallet.data.uid = child.uid; @@ -1614,6 +1614,12 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se var keypair = res[0]; var currency = res[1]; var block = res[2]; + + // Check if member account + if (!data.isMember && !csConfig.initPhase) { + throw {message:'ERROR.ONLY_MEMBER_CAN_EXECUTE_THIS_ACTION'}; + } + // Create the self part to sign var cert = 'Version: '+ constants.CERT_VERSION +'\n' + 'Type: Certification\n' + @@ -1948,8 +1954,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se }, createNewChildWallet = function(options) { - var walletId = getChildrenWalletCount()+1; - var wallet = service.instance(walletId); + var wallet = newChildInstance(); addChildWallet(wallet, options); return wallet; }, @@ -1988,7 +1993,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se removeChildWalletById = function(id, options) { data.children = data.children || []; - var childIndex = _.findIndex(data.children, function(child) {return child.id == id;}); + var childIndex = _.findIndex(data.children, function(child) {return child.id === id;}); if (childIndex === -1) { console.warn('[wallet] Unable to remove child wallet {'+id+'} (not found)'); return; @@ -2006,7 +2011,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se }, getChildWalletById = function(id) { - return (id !== 'default') && _.find(data.children|| [], function(child) {return child.id == id;}) || undefined; + return (id !== 'default') && _.find(data.children|| [], function(child) {return child.id === id;}) || undefined; }, getChildWalletByPubkey = function(pubkey) { @@ -2021,12 +2026,13 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se return angular.isDefined(data.childrenCount) ? data.childrenCount : (data.children && data.children.length || 0); }, - getNewChildrenInstance = function() { + newChildInstance = function() { // Return max(id) + 1 - var walletId = (data.children && data.children.reduce(function(res, wallet) { + var walletId = (data.children && data.children.reduce(function(res, wallet) { return Math.max(res, wallet.id); }, 0) || data.childrenCount || 0 )+ 1; - return service.instance(walletId, BMA); + var childrenWallet = service.instance(walletId, BMA); + return childrenWallet; }, getAllChildrenWallet = function() { @@ -2036,6 +2042,20 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se }); }, + getAllPubkeys = function() { + if (!data.pubkey) throw new Error('User not login!'); + return (data.children || []).reduce(function(res, wallet) { + return wallet.data.pubkey ? res.concat(wallet.data.pubkey) : res; + }, [data.pubkey]) + } + + getByPubkey = function(pubkey) { + if (!pubkey) throw new Error("Missing 'pubkey' argument !"); + if (!data.pubkey) throw new Error('User not login!'); + if (data.pubkey === pubkey) return exports; // main wallet + return getChildWalletByPubkey(pubkey); + } + downloadChildrenWalletFile = function() { return $q.all([ getAllChildrenWallet(), @@ -2144,7 +2164,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se checkAuthIdle = function(isAuthResult) { isAuthResult = angular.isDefined(isAuthResult) ? isAuthResult : isAuth(); - var newEnableAuthIdle = isAuthResult && settings.keepAuthIdle > 0 && settings.keepAuthIdle != csSettings.constants.KEEP_AUTH_IDLE_SESSION; + var newEnableAuthIdle = isAuthResult && settings && settings.keepAuthIdle > 0 && settings.keepAuthIdle != csSettings.constants.KEEP_AUTH_IDLE_SESSION; var changed = (enableAuthIdle != newEnableAuthIdle); // need start/top watching @@ -2170,7 +2190,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se } // Make sure to store seckey, in the session storage for secret key -fix #372 - var storeSecKey = isAuthResult && settings.keepAuthIdle == csSettings.constants.KEEP_AUTH_IDLE_SESSION && true; + var storeSecKey = isAuthResult && settings && settings.keepAuthIdle == csSettings.constants.KEEP_AUTH_IDLE_SESSION && true; if (storeSecKey) { sessionStorage.put(constants.STORAGE_SECKEY, CryptoUtils.util.encode_base58(data.keypair.signSk)); } @@ -2181,7 +2201,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se }; function getWalletSettings(settings) { - return { + return settings && { useLocalStorage: settings.useLocalStorage, useLocalStorageEncryption: settings.useLocalStorageEncryption, rememberMe: settings.rememberMe, @@ -2192,7 +2212,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se function onSettingsChanged(allSettings) { var newSettings = getWalletSettings(allSettings); var hasChanged = !angular.equals(settings, newSettings); - if (!hasChanged) return; // skip + if (!hasChanged || !settings) return; // skip var useEncryptionChanged = !angular.equals(settings.useLocalStorageEncryption, newSettings.useLocalStorageEncryption); var useStorageChanged = !angular.equals(settings.useLocalStorage, newSettings.useLocalStorage) || useEncryptionChanged; @@ -2394,6 +2414,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se recoverId: recoverId, downloadRevocation: downloadRevocation, downloadKeyFile: downloadKeyFile, + pubkeys: getAllPubkeys, + getByPubkey: getByPubkey, membership: { inside: membership(true), out: membership(false) @@ -2412,7 +2434,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se setParent: setParentWallet, count: getChildrenWalletCount, hasPubkey: hasChildrenWithPubkey, - instance: getNewChildrenInstance, + instance: newChildInstance, downloadFile: downloadChildrenWalletFile }, api: api @@ -2420,8 +2442,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se return exports; } - service = factory('default', BMA); - service.instance = factory; + service = csWallet('default', BMA); + service.instance = csWallet; return service; }); diff --git a/www/js/services/wot-services.js b/www/js/services/wot-services.js index a04095080..4ad2f3f98 100644 --- a/www/js/services/wot-services.js +++ b/www/js/services/wot-services.js @@ -5,7 +5,7 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c .factory('csWot', function($rootScope, $q, $timeout, BMA, Api, CacheFactory, csConfig, csCurrency, csSettings, csCache) { 'ngInject'; - function factory(id) { + function csWot(id) { var api = new Api(this, "csWot-" + id), @@ -1209,8 +1209,8 @@ angular.module('cesium.wot.services', ['ngApi', 'cesium.bma.services', 'cesium.c }; } - var service = factory('default', BMA); + var service = csWot('default', BMA); - service.instance = factory; + service.instance = csWot; return service; }); diff --git a/www/plugins/es/css/style.css b/www/plugins/es/css/style.css index c95bc0e82..edeb37ef8 100644 --- a/www/plugins/es/css/style.css +++ b/www/plugins/es/css/style.css @@ -272,6 +272,22 @@ padding-top: 1px; } +/********** + Common > report abuse +**********/ + +.popup-report-abuse .popup { + width: 370px !important; +} +.popup-report-abuse .popup .item-toggle .toggle { + right: 0 !important; +} +.popup-report-abuse .popup .item-toggle .input-label { + width: 280px; + max-width: 100%; + white-space: normal; +} + /********** Add specific Icons **********/ diff --git a/www/plugins/es/i18n/locale-en-GB.json b/www/plugins/es/i18n/locale-en-GB.json index 489525697..eec0d9c4f 100644 --- a/www/plugins/es/i18n/locale-en-GB.json +++ b/www/plugins/es/i18n/locale-en-GB.json @@ -3,8 +3,15 @@ "CATEGORY": "Category", "CATEGORIES": "Categories", "CATEGORY_SEARCH_HELP": "Search", + "COMMENT_HELP": "Comments", "LAST_MODIFICATION_DATE": "Updated on ", "SUBMIT_BY": "Submitted by", + "BTN_LIKE": "I like", + "BTN_LIKE_REMOVE": "I don't like anymore", + "LIKES_TEXT": "{{total}} {{total > 1 ? 'people' : 'person'}} liked this page", + "ABUSES_TEXT": "{{total}} {{total > 1 ? 'people' : 'person'}} reported a problem on this page", + "BTN_REPORT_ABUSE_DOTS": "Report a problem or an abuse...", + "BTN_REMOVE_REPORTED_ABUSE": "Cancel my problem report", "BTN_PUBLISH": "Publish", "BTN_PICTURE_DELETE": "Delete", "BTN_PICTURE_FAVORISE": "Default", @@ -20,6 +27,15 @@ "NO_RESULT": "No notification", "SHOW_ALL": "Show all", "LOAD_NOTIFICATIONS_FAILED": "Could not load notifications" + }, + "REPORT_ABUSE": { + "TITLE": "Report a problem", + "SUB_TITLE": "Please explain briefly the problem:", + "REASON_HELP": "I explain the problem...", + "ASK_DELETE": "Request removal?", + "CONFIRM": { + "SENT": "Request sent. Thnak you!" + } } }, "MENU": { @@ -118,6 +134,8 @@ "REPLY_TO_DELETED_COMMENT": "In response to a deleted comment", "REPLY_COUNT": "{{replyCount}} responses", "DELETED_COMMENT": "Comment deleted", + "MODIFIED_ON": "modified on {{time|formatDate}}", + "MODIFIED_PARENTHESIS": "(modified then)", "ERROR": { "FAILED_SAVE_COMMENT": "Saving comment failed", "FAILED_REMOVE_COMMENT": "Deleting comment failed" @@ -497,11 +515,31 @@ "TX_RECEIVED_MULTI": "You received a payment from <b>{{params[1]}}</b>.", "CERT_SENT": "Your <b>certification</b> to <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> was executed.", "CERT_RECEIVED": "You have <b>received a certification</b> from <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "USER": { + "LIKE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> like your profile", + "FOLLOW_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> follows your activity", + "STAR_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> rated you ({{params[3]}} <i class=\"ion-star\">)", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> asks you for a moderation on the profile: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> reported a profile to be deleted: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has requested moderation on your profile" + }, + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has commented on your referencing: <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his comment on your referencing: <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has replied to your comment on the referencing: <b>{{params[2]}}</b>", - "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his answer to your comment, on the referencing: <b>{{params[2]}}</b>" + "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his answer to your comment, on the referencing: <b>{{params[2]}}</b>", + "FOLLOW_NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has commented on the page: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his comment on the page: <b>{{params[2]}}</b>", + "FOLLOW_NEW": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> added a page: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> updated the page: <b>{{params[2]}}</b>", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> asks you for a moderation on the page: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> reported a page to be deleted: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has requested moderation on your page: <b>{{params[2]}}</b>" + } + }, + "LIKE": { + "ERROR": { + "FAILED_TOGGLE_LIKE": "Unable to execute this action." } }, "CONFIRM": { diff --git a/www/plugins/es/i18n/locale-en.json b/www/plugins/es/i18n/locale-en.json index 489525697..eec0d9c4f 100644 --- a/www/plugins/es/i18n/locale-en.json +++ b/www/plugins/es/i18n/locale-en.json @@ -3,8 +3,15 @@ "CATEGORY": "Category", "CATEGORIES": "Categories", "CATEGORY_SEARCH_HELP": "Search", + "COMMENT_HELP": "Comments", "LAST_MODIFICATION_DATE": "Updated on ", "SUBMIT_BY": "Submitted by", + "BTN_LIKE": "I like", + "BTN_LIKE_REMOVE": "I don't like anymore", + "LIKES_TEXT": "{{total}} {{total > 1 ? 'people' : 'person'}} liked this page", + "ABUSES_TEXT": "{{total}} {{total > 1 ? 'people' : 'person'}} reported a problem on this page", + "BTN_REPORT_ABUSE_DOTS": "Report a problem or an abuse...", + "BTN_REMOVE_REPORTED_ABUSE": "Cancel my problem report", "BTN_PUBLISH": "Publish", "BTN_PICTURE_DELETE": "Delete", "BTN_PICTURE_FAVORISE": "Default", @@ -20,6 +27,15 @@ "NO_RESULT": "No notification", "SHOW_ALL": "Show all", "LOAD_NOTIFICATIONS_FAILED": "Could not load notifications" + }, + "REPORT_ABUSE": { + "TITLE": "Report a problem", + "SUB_TITLE": "Please explain briefly the problem:", + "REASON_HELP": "I explain the problem...", + "ASK_DELETE": "Request removal?", + "CONFIRM": { + "SENT": "Request sent. Thnak you!" + } } }, "MENU": { @@ -118,6 +134,8 @@ "REPLY_TO_DELETED_COMMENT": "In response to a deleted comment", "REPLY_COUNT": "{{replyCount}} responses", "DELETED_COMMENT": "Comment deleted", + "MODIFIED_ON": "modified on {{time|formatDate}}", + "MODIFIED_PARENTHESIS": "(modified then)", "ERROR": { "FAILED_SAVE_COMMENT": "Saving comment failed", "FAILED_REMOVE_COMMENT": "Deleting comment failed" @@ -497,11 +515,31 @@ "TX_RECEIVED_MULTI": "You received a payment from <b>{{params[1]}}</b>.", "CERT_SENT": "Your <b>certification</b> to <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> was executed.", "CERT_RECEIVED": "You have <b>received a certification</b> from <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "USER": { + "LIKE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> like your profile", + "FOLLOW_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> follows your activity", + "STAR_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> rated you ({{params[3]}} <i class=\"ion-star\">)", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> asks you for a moderation on the profile: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> reported a profile to be deleted: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has requested moderation on your profile" + }, + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has commented on your referencing: <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his comment on your referencing: <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has replied to your comment on the referencing: <b>{{params[2]}}</b>", - "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his answer to your comment, on the referencing: <b>{{params[2]}}</b>" + "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his answer to your comment, on the referencing: <b>{{params[2]}}</b>", + "FOLLOW_NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has commented on the page: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has modified his comment on the page: <b>{{params[2]}}</b>", + "FOLLOW_NEW": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> added a page: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> updated the page: <b>{{params[2]}}</b>", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> asks you for a moderation on the page: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> reported a page to be deleted: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> has requested moderation on your page: <b>{{params[2]}}</b>" + } + }, + "LIKE": { + "ERROR": { + "FAILED_TOGGLE_LIKE": "Unable to execute this action." } }, "CONFIRM": { diff --git a/www/plugins/es/i18n/locale-eo-EO.json b/www/plugins/es/i18n/locale-eo-EO.json index fe8978016..8572520b2 100644 --- a/www/plugins/es/i18n/locale-eo-EO.json +++ b/www/plugins/es/i18n/locale-eo-EO.json @@ -3,8 +3,14 @@ "CATEGORY": "Kategorio", "CATEGORIES": "Kategorioj", "CATEGORY_SEARCH_HELP": "Serĉado", + "COMMENT_HELP": "Komento", "LAST_MODIFICATION_DATE": "Äœisdatigita la", "SUBMIT_BY": "Submetita de", + "BTN_LIKE": "Mi Åatas", + "LIKES_TEXT": "{{total}} persono{{total > 1 ? 'j' : ''}} Åatis tiun ĉi paÄon", + "ABUSES_TEXT": "{{total}} persono{{total > 1 ? 'j' : ''}} atentigis pri problemo", + "BTN_REPORT_ABUSE_DOTS": "Atentigi pri problemo aÅ misuzo...", + "BTN_REMOVE_REPORTED_ABUSE": "Nuligi mian atentigon", "BTN_PUBLISH": "Publikigi", "BTN_PICTURE_DELETE": "Forigi", "BTN_PICTURE_FAVORISE": "Precipa", @@ -20,6 +26,15 @@ "NO_RESULT": "Neniu avizo", "SHOW_ALL": "Vidi ĉion", "LOAD_NOTIFICATIONS_FAILED": "Malsukceso por ÅarÄi la avizojn" + }, + "REPORT_ABUSE": { + "TITLE": "Atentigi pri problemo", + "SUB_TITLE": "Bonvolu klarigi rapide la problemon:", + "REASON_HELP": "Mi klarigas la problemon...", + "ASK_DELETE": "Peti la forigon?", + "CONFIRM": { + "SENT": "Atentigo sendita. Dankon!" + } } }, "MENU": { @@ -118,6 +133,8 @@ "REPLY_TO_DELETED_COMMENT": "Responde al forigita komento", "REPLY_COUNT": "{{replyCount}} respondoj", "DELETED_COMMENT": "Komento forigita", + "MODIFIED_ON": "modifita la {{time|formatDate}}", + "MODIFIED_PARENTHESIS": "(modifita poste)", "ERROR": { "FAILED_SAVE_COMMENT": "Eraro dum la konservo de la komento", "FAILED_REMOVE_COMMENT": "Eraro dum la forigo de la komento" @@ -464,6 +481,7 @@ "TITLE": "Serĉado de dokumentoj", "BTN_ACTIONS": "Agoj", "SEARCH_HELP": "Sendanto:AAA*, tempo:1508406169", + "LAST_DOCUMENTS_DOTS": "Lastaj dokumentoj:", "LAST_DOCUMENTS": "Lastaj dokumentoj", "SHOW_QUERY": "Vidi la informpeton", "HIDE_QUERY": "KaÅi la informpeton", @@ -472,6 +490,8 @@ "HEADER_RECIPIENT": "Ricevonto", "READ": "Legita", "BTN_REMOVE": "Forigi tiun ĉi dokumenton", + "BTN_COMPACT": "Densigi", + "HAS_CREATE_OR_UPDATE_PROFILE": "kreis aÅ modifis sian profilon", "POPOVER_ACTIONS": { "TITLE": "Agoj", "REMOVE_ALL": "Forigi tiujn ĉi dokumentojn..." @@ -523,6 +543,13 @@ "RECIPIENT_IS_MANDATORY": "Adresito estas deviga por la ĉifrado." } }, + "ES_PEER": { + "NAME": "Nomo", + "DOCUMENTS": "Dokumentoj", + "SOFTWARE": "Programo", + "DOCUMENT_COUNT": "Nombro de dokumentoj", + "EMAIL_SUBSCRIPTION_COUNT": "{{emailSubscription}} abonantoj pri avizoj per retmesaÄoj" + }, "EVENT": { "NODE_STARTED": "Via nodo ES API <b>{{params[0]}}</b> ekis", "NODE_BMA_DOWN": "La nodo <b>{{params[0]}}:{{params[1]}}</b> (uzata de via nodo ES API) estas <b>neatingebla</b>.", @@ -538,11 +565,26 @@ "TX_RECEIVED_MULTI": "Vi <b>ricevis pagon</b> de <b>{{params[1]}}</b>.", "CERT_SENT": "Via <b>atestado</b> al <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> efektiviÄis.", "CERT_RECEIVED": "Vi <b>ricevis atestaĵon</b> de <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "USER": { + "LIKE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> Åatas vian profilon", + "FOLLOW_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> sekvas viajn agojn", + "STAR_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> notis vin ({{params[3]}} <b class=\"ion-star\">)", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> petas de vi moderigon pri la profilo: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> atentigis pri profilo foriginda: <b>{{params[2]}}</b>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> atentigis pri via profilo" + }, + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> komentis vian anoncon: <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> modifis sian komenton pri via anonco: <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> respondis al via komento pri la anonco: <b>{{params[2]}}</b>", - "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> modifis sian respondon al via komento pri la anonco: <b>{{params[2]}}</b>" + "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> modifis sian respondon al via komento pri la anonco: <b>{{params[2]}}</b>", + "FOLLOW_NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> komentis la paÄon: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> modifis sian komenton ĉe la paÄo: <b>{{params[2]}}</b>", + "FOLLOW_NEW": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> aldonis la paÄon: <b>{{params[2]}}</b>", + "FOLLOW_UPDATE": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> modifis la paÄon: <b>{{params[2]}}</b>", + "MODERATION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> petas de vis moderigon pri la paÄo: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> atentigis pri paÄo foriginda: <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> atentigis pri via paÄo: <b>{{params[2]}}</b>" } }, "CONFIRM": { diff --git a/www/plugins/es/i18n/locale-es-ES.json b/www/plugins/es/i18n/locale-es-ES.json index 49be7a994..50077c822 100644 --- a/www/plugins/es/i18n/locale-es-ES.json +++ b/www/plugins/es/i18n/locale-es-ES.json @@ -499,7 +499,7 @@ "TX_RECEIVED_MULTI": "Ha <b>recibido un pago</b> de <b>{{params[1]}}</b>.", "CERT_SENT": "Su <b>certificación</b> a <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> fue efectuada.", "CERT_RECEIVED": "Ha <b>recibido una certificación</b> de <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha comentado su referencia : <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha modificado su comentario sobre su referencia : <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha contestado a su comentario sobre el referencia : <b>{{params[2]}}</b>", diff --git a/www/plugins/es/i18n/locale-fr-FR.json b/www/plugins/es/i18n/locale-fr-FR.json index 2b3175d28..34c229111 100644 --- a/www/plugins/es/i18n/locale-fr-FR.json +++ b/www/plugins/es/i18n/locale-fr-FR.json @@ -3,8 +3,15 @@ "CATEGORY": "Catégorie", "CATEGORIES": "Catégories", "CATEGORY_SEARCH_HELP": "Recherche", + "COMMENT_HELP": "Commentaire", "LAST_MODIFICATION_DATE": "Mise à jour le", "SUBMIT_BY": "Soumis par", + "BTN_LIKE": "J'aime", + "BTN_LIKE_REMOVE": "Je n'aime plus", + "LIKES_TEXT": "{{total}} personne{{total > 1 ? 's' : ''}} {{total > 1 ? 'ont' : 'a'}} aimé cette page", + "ABUSES_TEXT": "{{total}} personne{{total > 1 ? 's' : ''}} {{total > 1 ? 'ont' : 'a'}} signalé un problème", + "BTN_REPORT_ABUSE_DOTS": "Signaler un problème ou un abus...", + "BTN_REMOVE_REPORTED_ABUSE": "Annuler mon signalement", "BTN_PUBLISH": "Publier", "BTN_PICTURE_DELETE": "Supprimer", "BTN_PICTURE_FAVORISE": "Principale", @@ -20,6 +27,15 @@ "NO_RESULT": "Aucune notification", "SHOW_ALL": "Voir tout", "LOAD_NOTIFICATIONS_FAILED": "Erreur de chargement des notifications" + }, + "REPORT_ABUSE": { + "TITLE": "Signaler un problème", + "SUB_TITLE": "Merci d'expliquer succintement le problème :", + "REASON_HELP": "J'explique le problème...", + "ASK_DELETE": "Demander la suppression ?", + "CONFIRM": { + "SENT": "Signalement envoyé. Merci !" + } } }, "MENU": { @@ -118,6 +134,8 @@ "REPLY_TO_DELETED_COMMENT": "En réponse à un commentaire supprimé", "REPLY_COUNT": "{{replyCount}} réponses", "DELETED_COMMENT": "Commentaire supprimé", + "MODIFIED_ON": "modifié le {{time|formatDate}}", + "MODIFIED_PARENTHESIS": "(modifié ensuite)", "ERROR": { "FAILED_SAVE_COMMENT": "Erreur lors de la sauvegarde du commentaire", "FAILED_REMOVE_COMMENT": "Erreur lors de la suppression du commentaire" @@ -136,7 +154,7 @@ "MESSAGE_RECEIVED": "Vous avez <b>reçu un message</b><br/>de" }, "LIST": { - "INBOX": "Boite de réception", + "INBOX": "Boîte de réception", "OUTBOX": "Messages envoyés", "LAST_INBOX": "Nouveaux messages", "LAST_OUTBOX": "Messages envoyés", @@ -341,7 +359,7 @@ "LOAD_CATEGORY_FAILED": "Erreur de chargement de la liste des activités", "LOAD_RECORD_FAILED": "Erreur lors du chargement de la page", "LOOKUP_RECORDS_FAILED": "Erreur lors de l'exécution de la recherche", - "REMOVE_RECORD_FAILED": "Erreur de la suppression de la page", + "REMOVE_RECORD_FAILED": "Erreur lors de la suppression de la page", "SAVE_RECORD_FAILED": "Erreur lors de la sauvegarde", "RECORD_NOT_EXISTS": "Page inexistante", "GEO_LOCATION_NOT_FOUND": "Ville ou code postal non trouvé" @@ -448,9 +466,9 @@ "DELETE_SUBSCRIPTION_FAILED": "Erreur lors de la suppression de l'abonnement" }, "MODAL_EMAIL": { - "TITLE" : "Notification par email", - "HELP" : "Remplissez ce formulaire pour <b>être notifié par email</b> des événements de votre compte.<br/>Votre adresse email sera chiffrée pour n'être visible que par le prestataire de service.", - "EMAIL_LABEL" : "Votre email :", + "TITLE": "Notification par email", + "HELP": "Remplissez ce formulaire pour <b>être notifié par email</b> des événements de votre compte.<br/>Votre adresse email sera chiffrée pour n'être visible que par le prestataire de service.", + "EMAIL_LABEL": "Votre email :", "EMAIL_HELP": "jean.dupond@domaine.com", "FREQUENCY_LABEL": "Fréquence des notifications :", "FREQUENCY_DAILY": "Journalier", @@ -531,7 +549,7 @@ "DOCUMENTS": "Documents", "SOFTWARE": "Logiciel", "DOCUMENT_COUNT": "Nombre de documents", - "EMAIL_SUBSCRIPTION_COUNT": "{{emailSubscription}} abonnés aux notifications par email" + "EMAIL_SUBSCRIPTION_COUNT": "{{emailSubscription}} abonné{{emailSubscription ? 's' : ''}} aux notifications par email" }, "EVENT": { "NODE_STARTED": "Votre noeud ES API <b>{{params[0]}}</b> est démarré", @@ -548,11 +566,31 @@ "TX_RECEIVED_MULTI": "Vous avez <b>reçu un paiement</b> de <b>{{params[1]}}</b>.", "CERT_SENT": "Votre <b>certification</b> à <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a été effectuée.", "CERT_RECEIVED": "Vous avez <b>reçu une certification</b> de <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { - "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a commenté votre référencement : <b>{{params[2]}}</b>", - "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a modifié son commentaire sur votre référencement : <b>{{params[2]}}</b>", - "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a répondu à votre commentaire sur le référencement : <b>{{params[2]}}</b>", - "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a modifié sa réponse à votre commentaire sur le référencement : <b>{{params[2]}}</b>" + "USER": { + "LIKE_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> aime votre profil", + "FOLLOW_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> suit votre activité", + "STAR_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> vous a noté ({{params[3]}} <b class=\"ion-star\">)", + "MODERATION_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> vous demande une modération sur le profil : <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> demande la suppression d'un profil : <b>{{params[2]}}</b>", + "ABUSE_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a signalé votre profil" + }, + "PAGE": { + "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a commenté votre page : <b>{{params[2]}}</b>", + "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a modifié son commentaire sur votre page : <b>{{params[2]}}</b>", + "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a répondu à votre commentaire sur la page : <b>{{params[2]}}</b>", + "UPDATE_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> a modifié sa réponse à votre commentaire sur la page : <b>{{params[2]}}</b>", + "FOLLOW_NEW_COMMENT": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a commenté la page : <b>{{params[2]}}</b>", + "FOLLOW_UPDATE_COMMENT": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a modifié son commentaire sur la page : <b>{{params[2]}}</b>", + "FOLLOW_NEW": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a ajouté la page : <b>{{params[2]}}</b>", + "FOLLOW_UPDATE": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a modifié la page : <b>{{params[2]}}</b>", + "MODERATION_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> vous demande une modération sur la page : <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "DELETION_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a signalé une page à supprimer : <b>{{params[2]}}</b><br/><b class=\"dark ion-quote\"> </b><span class=\"text-italic\">{{params[3]}}</span>", + "ABUSE_RECEIVED": "<span class=\"positive\"><i class=\"icon ion-person\"></i> {{name||params[1]}}</span> a signalé votre page : <b>{{params[2]}}</b>" + } + }, + "LIKE": { + "ERROR": { + "FAILED_TOGGLE_LIKE": "Impossible d'executer cette action." } }, "CONFIRM": { diff --git a/www/plugins/es/i18n/locale-it-IT.json b/www/plugins/es/i18n/locale-it-IT.json index 9227ffe45..e0e79b488 100644 --- a/www/plugins/es/i18n/locale-it-IT.json +++ b/www/plugins/es/i18n/locale-it-IT.json @@ -518,7 +518,7 @@ "TX_RECEIVED_MULTI": "Ha ricevuto un pagamento da <b>{{params[1]}}</b>.", "CERT_SENT": "Sua <b>certificazione</b> a favore di <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> è stata eseguita.", "CERT_RECEIVED": "Ha ricevuto <b>una certificazione</b> da parte di <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha scritto un commento sul suo riferimento: <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha modificato il suo commento sul suo riferimento: <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> ha risposto al suo commento sul riferimento: <b>{{params[2]}}</b>", diff --git a/www/plugins/es/i18n/locale-nl-NL.json b/www/plugins/es/i18n/locale-nl-NL.json index 4d6894532..4b04e73f6 100644 --- a/www/plugins/es/i18n/locale-nl-NL.json +++ b/www/plugins/es/i18n/locale-nl-NL.json @@ -239,7 +239,7 @@ "TX_RECEIVED_MULTI": "Je hebt een <b>betaling ontvangen</b> van <b>{{params[1]}}</b>.", "CERT_SENT": "Je <b>certificatie</b> van <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\" ><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> is uitgevoerd.", "CERT_RECEIVED": "Je hebt een <b>certificatie ontvangen</b> van <span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid}\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span>.", - "REGISTRY": { + "PAGE": { "NEW_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> heeft gereageerd op jouw referentie: <b>{{params[2]}}</b>", "UPDATE_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> heeft zijn/aar reactie op jouw referentie bewerkt: <b>{{params[2]}}</b>", "NEW_REPLY_COMMENT": "<span ng-class=\"{'gray': !notification.uid, 'positive':notification.uid }\"><i class=\"icon\" ng-class=\"{'ion-person': notification.uid, 'ion-key': !notification.uid}\"></i> {{name||uid||params[1]}}</span> hheeft gereageerd op jouw commentaar op referentie: <b>{{params[2]}}</b>", diff --git a/www/plugins/es/js/controllers/common-controllers.js b/www/plugins/es/js/controllers/common-controllers.js index 415602f89..0d96ac610 100644 --- a/www/plugins/es/js/controllers/common-controllers.js +++ b/www/plugins/es/js/controllers/common-controllers.js @@ -21,6 +21,8 @@ angular.module('cesium.es.common.controllers', ['ngResource', 'cesium.es.service .controller('ESSearchPositionItemCtrl', ESSearchPositionItemController) .controller('ESSearchPositionModalCtrl', ESSearchPositionModalController) + + .controller('ESLikesCtrl', ESLikesController) ; @@ -973,3 +975,282 @@ function ESSearchPositionModalController($scope, $q, $translate, esGeo, paramete }; } + + +function ESLikesController($scope, $q, $timeout, $translate, $ionicPopup, UIUtils, Modals, csWallet, esHttp, esLike) { + 'ngInject'; + + $scope.entered = false; + $scope.abuseData = {}; + $scope.abuseLevels = [ + {value: 1, label: 'LOW'}, + {value: 2, label: 'LOW'} + ]; + $scope.staring = false; + $scope.options = $scope.options || {}; + $scope.options.like = $scope.options.like || { + kinds: esLike.constants.KINDS, + index: undefined, + type: undefined, + id: undefined + }; + + $scope.$on('$recordView.enter', function(e, state) { + // First enter + if (!$scope.entered) { + $scope.entered = false; + // Nothing to do: main controller will trigger '$recordView.load' event + } + // second call (e.g. if cache) + else if ($scope.id) { + $scope.loadLikes($scope.id); + } + }); + + $scope.$on('$recordView.load', function(event, id) { + $scope.id = id || $scope.id; + if ($scope.id) { + $scope.loadLikes($scope.id); + } + }); + + // Init Like service + $scope.initLikes = function() { + if (!$scope.likeData) { + throw new Error("Missing 'likeData' in scope. Cannot load likes counter"); + } + if (!$scope.options.like.service) { + if (!$scope.options.like.index || !$scope.options.like.type) { + throw new Error("Missing 'options.like.index' or 'options.like.type' in scope. Cannot load likes counter"); + } + $scope.options.like.service = esLike.instance($scope.options.like.index, $scope.options.like.type); + } + if (!$scope.options.like.kinds) { + // Get scope's kinds (e.g. defined in the parent scope) + $scope.options.like.kinds = _.filter(esLike.constants.KINDS, function (kind) { + var key = kind.toLowerCase() + 's'; + return angular.isDefined($scope.likeData[key]); + }); + } + }; + + $scope.loadLikes = function(id) { + if ($scope.likeData.loading) return;// Skip + + id = id || $scope.likeData.id; + $scope.initLikes(); + + var kinds = $scope.options.like.kinds || []; + if (!kinds.length) return; // skip + + $scope.likeData.loading = true; + var now = Date.now(); + console.debug("[ES] Loading counter of {0}... ({1})".format(id.substring(0,8), kinds)); + + var issuers = csWallet.isLogin() ? csWallet.pubkeys() : undefined; + + return $q.all(_.map(kinds, function(kind) { + var key = kind.toLowerCase() + 's'; + return $scope.options.like.service.count(id, {issuers: issuers, kind: kind}) + .then(function (res) { + // Store result to scope + if ($scope.likeData[key]) { + angular.merge($scope.likeData[key], res); + } + }); + })) + .then(function () { + $scope.likeData.id = id; + console.debug("[ES] Loading counter of {0} [OK] in {1}ms".format(id.substring(0,8), Date.now()-now)); + + if (_.contains(kinds, 'VIEW') && !$scope.canEdit) { + $scope.markAsView(); + } + + // Publish to parent scope (to be able to use it in action popover's buttons) + if ($scope.$parent) { + console.debug("[ES] [likes] Adding data and functions to parent scope"); + $scope.$parent.toggleLike = $scope.toggleLike; + $scope.$parent.reportAbuse = $scope.reportAbuse; + } + + $scope.likeData.loading = false; + }) + .catch(function (err) { + console.error(err && err.message || err); + $scope.likeData.loading = false; + }); + }; + + $scope.toggleLike = function(event, options) { + $scope.initLikes(); + if (!$scope.likeData.id) throw new Error("Missing 'likeData.id' in scope. Cannot apply toggle"); + + options = options || {}; + options.kind = options.kind && options.kind.toUpperCase() || 'LIKE'; + var key = options.kind.toLowerCase() + 's'; + + $scope.likeData[key] = $scope.likeData[key] || {}; + + // Avoid too many call + if ($scope.likeData[key].loading === true || $scope.likeData.loading) { + event.preventDefault(); + return $q.reject(); + } + + // Select the wallet, if many + if (!options.pubkey) { + return (csWallet.children.count() ? Modals.showSelectWallet({displayBalance: false}) : $q.when(csWallet)) + .then(function(wallet) { + if (!wallet) throw 'CANCELLED'; + options.pubkey = wallet.data.pubkey; + return $scope.toggleLike(event, options); // Loop + }); + } + + var wallet = csWallet.getByPubkey(options.pubkey); + if (!wallet) return; + + $scope.likeData[key].loading = true; + return wallet.auth({minData: true}) + .then(function(walletData) { + if (!walletData) { + UIUtils.loading.hide(); + return; + } + + // Check if member account + if (!walletData.isMember) { + // TODO: enable this + //throw {message: "ERROR.ONLY_MEMBER_CAN_EXECUTE_THIS_ACTION"}; + } + + // Apply like + options.id = $scope.likeData.id; + return $scope.options.like.service.toggle($scope.likeData.id, options); + }) + .then(function(delta) { + UIUtils.loading.hide(); + if (delta !== 0) { + $scope.likeData[key].total = ($scope.likeData[key].total || 0) + delta; + $scope.likeData[key].wasHitByPubkey = $scope.likeData[key].wasHitByPubkey || {}; + $scope.likeData[key].wasHitByPubkey[options.pubkey] = delta > 0; + $scope.likeData[key].wasHitCount += delta; + } + $timeout(function() { + $scope.likeData[key].loading = false; + $scope.$broadcast('$$rebind::like'); // notify binder + }, 1000); + }) + .catch(function(err) { + $scope.likeData[key].loading = false; + if (err === 'CANCELLED') return; // User cancelled + console.error(err); + UIUtils.onError('LIKE.ERROR.FAILED_TOGGLE_LIKE')(err); + event.preventDefault(); + }); + }; + + $scope.setAbuseForm = function(form) { + $scope.abuseForm = form; + }; + + $scope.showAbuseCommentPopover = function(event) { + return $translate(['COMMON.REPORT_ABUSE.TITLE', 'COMMON.REPORT_ABUSE.SUB_TITLE','COMMON.BTN_SEND', 'COMMON.BTN_CANCEL']) + .then(function(translations) { + + UIUtils.loading.hide(); + + return $ionicPopup.show({ + templateUrl: 'plugins/es/templates/common/popup_report_abuse.html', + title: translations['COMMON.REPORT_ABUSE.TITLE'], + subTitle: translations['COMMON.REPORT_ABUSE.SUB_TITLE'], + cssClass: 'popup-report-abuse', + scope: $scope, + buttons: [ + { + text: translations['COMMON.BTN_CANCEL'], + type: 'button-stable button-clear gray' + }, + { + text: translations['COMMON.BTN_SEND'], + type: 'button button-positive ink', + onTap: function(e) { + $scope.abuseForm.$submitted=true; + if(!$scope.abuseForm.$valid || !$scope.abuseData.comment) { + //don't allow the user to close unless he enters a uid + e.preventDefault(); + } else { + return $scope.abuseData; + } + } + } + ] + }); + }) + .then(function(res) { + $scope.abuseData = {}; + if (!res || !res.comment) { // user cancel + UIUtils.loading.hide(); + return undefined; + } + return res; + }); + }; + + $scope.reportAbuse = function(event, options) { + if (!$scope.likeData || !$scope.likeData.abuses || $scope.likeData.abuses.wasHitCount) return; // skip + if ($scope.likeData.abuses.wasHitCount) return; // already report + + options = options || {}; + + // Select the wallet, if many + if (!options.pubkey) { + return (csWallet.children.count() ? Modals.showSelectWallet({displayBalance: false}) : $q.when(csWallet)) + .then(function(wallet) { + if (!wallet) throw 'CANCELLED'; + options.pubkey = wallet.data.pubkey; + return $scope.reportAbuse(event, options); // Loop + }); + } + + var wallet = csWallet.getByPubkey(options.pubkey); + + // Check if member account + if (!wallet || !wallet.isMember()) { + UIUtils.alert.info("ERROR.ONLY_MEMBER_CAN_EXECUTE_THIS_ACTION"); + return; + } + + if (!options.comment) { + // Ask a comment + return $scope.showAbuseCommentPopover(event) + // Loop, with options.comment filled + .then(function(res) { + if (!res || !res.comment) return; // Empty comment: skip + options.comment = res.comment; + options.level = res.level || (res.delete && 5) || undefined; + return $scope.reportAbuse(event, options) // Loop, with the comment + }); + } + + // Send abuse report + options.kind = 'ABUSE'; + return $scope.toggleLike(event, options) + .then(function() { + UIUtils.toast.show('COMMON.REPORT_ABUSE.CONFIRM.SENT') + }) + }; + + csWallet.api.data.on.reset($scope, function() { + _.forEach($scope.options.like.kinds||[], function(kind) { + var key = kind.toLowerCase() + 's'; + if ($scope.likeData[key]) { + $scope.likeData[key].wasHitByPubkey = {}; + $scope.likeData[key].wasHitCount = 0; + } + }) + $scope.$broadcast('$$rebind::like'); // notify binder + }, this); + +} diff --git a/www/plugins/es/js/controllers/registry-controllers.js b/www/plugins/es/js/controllers/registry-controllers.js index 04b3c29fb..7d1cc4c22 100644 --- a/www/plugins/es/js/controllers/registry-controllers.js +++ b/www/plugins/es/js/controllers/registry-controllers.js @@ -775,7 +775,7 @@ function ESWalletPagesController($scope, $controller, $timeout, UIUtils, esModal } -function ESRegistryRecordViewController($scope, $rootScope, $state, $q, $timeout, $ionicPopover, $ionicHistory, $translate, +function ESRegistryRecordViewController($scope, $rootScope, $state, $q, $timeout, $ionicPopover, $ionicHistory, $translate, $controller, $anchorScroll, csConfig, csWallet, esRegistry, UIUtils, esHttp) { 'ngInject'; @@ -788,6 +788,21 @@ function ESRegistryRecordViewController($scope, $rootScope, $state, $q, $timeout $scope.loading = true; $scope.motion = UIUtils.motion.fadeSlideIn; + // Init likes here, to be able to use in extension + $scope.options = $scope.options || {}; + $scope.options.like = { + kinds: ['LIKE', 'ABUSE'], + index: 'page', + type: 'record' + }; + $scope.likeData = { + likes: {}, + abuses: {} + }; + + // Initialize the super class and extend it. + angular.extend(this, $controller('ESLikesCtrl', {$scope: $scope})); + $scope.$on('$ionicView.beforeEnter', function (event, viewData) { // Enable back button (workaround need for navigation outside tabs - https://stackoverflow.com/a/35064602) viewData.enableBack = UIUtils.screen.isSmall() ? true : viewData.enableBack; @@ -954,6 +969,7 @@ function ESRegistryRecordViewController($scope, $rootScope, $state, $q, $timeout $scope.actionsPopover.hide(); $scope.actionsPopover = null; } + return true; }; $scope.showSharePopover = function(event) { diff --git a/www/plugins/es/js/controllers/wallet-controllers.js b/www/plugins/es/js/controllers/wallet-controllers.js index ad1ba4bfb..eb1d12a5b 100644 --- a/www/plugins/es/js/controllers/wallet-controllers.js +++ b/www/plugins/es/js/controllers/wallet-controllers.js @@ -8,9 +8,13 @@ angular.module('cesium.es.wallet.controllers', ['cesium.es.services']) PluginServiceProvider .extendStates(['app.view_wallet', 'app.view_wallet_by_id'], { points: { + 'hero': { + templateUrl: "plugins/es/templates/wallet/view_wallet_extend.html", + controller: 'ESWalletLikesCtrl' + }, 'after-general': { templateUrl: "plugins/es/templates/wallet/view_wallet_extend.html", - controller: 'ESWalletCtrl' + controller: 'ESWalletViewCtrl' } } }) @@ -30,11 +34,13 @@ angular.module('cesium.es.wallet.controllers', ['cesium.es.services']) }) - .controller('ESWalletCtrl', ESWalletController) + .controller('ESWalletViewCtrl', ESWalletViewController) + + .controller('ESWalletLikesCtrl', ESWalletLikesController) ; -function ESWalletController($scope, $controller, $state, esModals, csWallet) { +function ESWalletViewController($scope, $controller, $state, csWallet, esModals) { 'ngInject'; // Initialize the super class and extend it. @@ -44,7 +50,7 @@ function ESWalletController($scope, $controller, $state, esModals, csWallet) { /* -- modals -- */ - $scope.showNewPageModal = function() { + $scope.showNewPageModal = function(event) { var wallet = ($state.params && $state.params.id) ? csWallet.children.get($state.params.id) : csWallet; if (!wallet) { UIUtils.alert.error('ERROR.UNKNOWN_WALLET_ID'); @@ -55,3 +61,28 @@ function ESWalletController($scope, $controller, $state, esModals, csWallet) { }; } + +function ESWalletLikesController($scope, $controller, UIUtils, esHttp, esProfile) { + 'ngInject'; + + $scope.options = $scope.options || {}; + $scope.options.like = $scope.options.like || { + index: 'user', + type: 'profile', + service: esProfile.like + }; + $scope.canEdit = true; // Avoid to change like counter itself + + // Initialize the super class and extend it. + angular.extend(this, $controller('ESLikesCtrl', {$scope: $scope})); + + // Initialize the super class and extend it. + angular.extend(this, $controller('ESExtensionCtrl', {$scope: $scope})); + + // Load likes, when profile loaded + $scope.$watch('formData.pubkey', function(pubkey) { + if (pubkey) { + $scope.loadLikes(pubkey); + } + }); +} diff --git a/www/plugins/es/js/controllers/wot-controllers.js b/www/plugins/es/js/controllers/wot-controllers.js index 44f9461da..fd7c9fd9d 100644 --- a/www/plugins/es/js/controllers/wot-controllers.js +++ b/www/plugins/es/js/controllers/wot-controllers.js @@ -27,6 +27,14 @@ angular.module('cesium.es.wot.controllers', ['cesium.es.services']) .extendStates(['app.wot_identity', 'app.wot_identity_uid'], { points: { + 'hero': { + templateUrl: "plugins/es/templates/wot/view_identity_extend.html", + controller: 'ESWotIdentityViewCtrl' + }, + 'general': { + templateUrl: "plugins/es/templates/wot/view_identity_extend.html", + controller: 'ESWotIdentityViewCtrl' + }, 'after-general': { templateUrl: "plugins/es/templates/wot/view_identity_extend.html", controller: 'ESWotIdentityViewCtrl' @@ -35,6 +43,10 @@ angular.module('cesium.es.wot.controllers', ['cesium.es.services']) templateUrl: "plugins/es/templates/wot/view_identity_extend.html", controller: 'ESWotIdentityViewCtrl' }, + 'after-buttons': { + templateUrl: "plugins/es/templates/wot/view_identity_extend.html", + controller: 'ESWotIdentityViewCtrl' + }, 'buttons-top-fab': { templateUrl: "plugins/es/templates/wot/view_identity_extend.html", controller: 'ESWotIdentityViewCtrl' @@ -55,8 +67,6 @@ angular.module('cesium.es.wot.controllers', ['cesium.es.services']) } }) ; - - } }) @@ -88,9 +98,21 @@ function ESWotLookupExtendController($scope, $controller, $state) { } function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIUtils, Modals, csWallet, - esModals, esWallet, esInvitation) { + esHttp, esModals, esWallet, esProfile, esInvitation) { 'ngInject'; + $scope.options = $scope.options || {}; + $scope.options.like = $scope.options.like || { + kinds: esHttp.constants.like.KINDS, + index: 'user', + type: 'profile', + service: esProfile.like + }; + $scope.smallscreen = angular.isDefined($scope.smallscreen) ? $scope.smallscreen : UIUtils.screen.isSmall(); + + // Initialize the super class and extend it. + angular.extend(this, $controller('ESLikesCtrl', {$scope: $scope})); + // Initialize the super class and extend it. angular.extend(this, $controller('ESExtensionCtrl', {$scope: $scope})); @@ -100,6 +122,7 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU $scope.showNewMessageModal = function(confirm) { + // note: not need to select wallet here, because message modal will do it, if need return csWallet.login({minData: true, method: 'default'}) .then(function() { UIUtils.loading.hide(); @@ -122,8 +145,8 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU destPub: $scope.formData.pubkey, destUid: $scope.formData.name||$scope.formData.uid }) - .then(function(send) { - if (send) UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT'); + .then(function(sent) { + if (sent) UIUtils.toast.show('MESSAGE.INFO.MESSAGE_SENT'); }); }); }; @@ -196,6 +219,7 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU var identities; return (csWallet.children.count() ? Modals.showSelectWallet({displayBalance: false}) : $q.when(csWallet)) .then(function(wallet) { + if (!wallet) throw 'CANCELLED'; return wallet.auth({minData: true}); }) .then(function(walletData) { @@ -287,6 +311,15 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU }); }; + /* -- likes -- */ + + // Load likes, when profile loaded + $scope.$watch('formData.pubkey', function(pubkey) { + if (pubkey) { + $scope.loadLikes(pubkey); + } + }); + /* -- Popover -- */ $scope.showCertificationActionsPopover = function(event) { @@ -305,6 +338,26 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU $scope.certificationActionsPopover.hide(); $scope.certificationActionsPopover = null; } + return true; + }; + + $scope.showActionsPopover = function (event) { + UIUtils.popover.show(event, { + templateUrl: 'plugins/es/templates/wot/view_popover_actions.html', + scope: $scope, + autoremove: true, + afterShow: function(popover) { + $scope.actionsPopover = popover; + } + }); + }; + + $scope.hideActionsPopover = function() { + if ($scope.actionsPopover) { + $scope.actionsPopover.hide(); + $scope.actionsPopover = null; + } + return true; }; if ($scope.extensionPoint === 'buttons-top-fab') { @@ -323,4 +376,3 @@ function ESWotIdentityViewController($scope, $ionicPopover, $q, $controller, UIU $scope.showSuggestCertificationModal(); }, 1000);*/ } - diff --git a/www/plugins/es/js/entities/notification.js b/www/plugins/es/js/entities/notification.js index f928c3200..eee62d735 100644 --- a/www/plugins/es/js/entities/notification.js +++ b/www/plugins/es/js/entities/notification.js @@ -2,7 +2,8 @@ function EsNotification(json, markAsReadCallback) { var messagePrefixes = { - 'registry': 'EVENT.REGISTRY.' + 'user': 'EVENT.USER.', + 'page': 'EVENT.PAGE.' }; var that = this; @@ -49,7 +50,7 @@ function EsNotification(json, markAsReadCallback) { // TX else if (json.code.startsWith('TX_')) { that.avatarIcon = 'ion-card'; - that.icon = (json.code == 'TX_SENT') ? 'ion-paper-airplane dark' : 'ion-archive balanced'; + that.icon = (json.code === 'TX_SENT') ? 'ion-paper-airplane dark' : 'ion-archive balanced'; that.medianTime = that.time; pubkeys = json.params.length > 0 ? json.params[0] : null; if (pubkeys && pubkeys.indexOf(',') == -1) { @@ -61,13 +62,13 @@ function EsNotification(json, markAsReadCallback) { // Certifications else if (json.code.startsWith('CERT_')) { - that.avatarIcon = (json.code == 'CERT_RECEIVED') ? 'ion-ribbon-b' : 'ion-ribbon-a'; - that.icon = (json.code == 'CERT_RECEIVED') ? 'ion-ribbon-b balanced' : 'ion-ribbon-a gray'; + that.avatarIcon = (json.code === 'CERT_RECEIVED') ? 'ion-ribbon-b' : 'ion-ribbon-a'; + that.icon = (json.code === 'CERT_RECEIVED') ? 'ion-ribbon-b balanced' : 'ion-ribbon-a gray'; that.pubkey = json.params.length > 0 ? json.params[0] : null; that.medianTime = that.time; that.state = 'app.wallet_cert'; that.stateParams = { - type: (json.code == 'CERT_RECEIVED') ? 'received' : 'given' + type: (json.code === 'CERT_RECEIVED') ? 'received' : 'given' }; } @@ -76,15 +77,62 @@ function EsNotification(json, markAsReadCallback) { that.avatarIcon = 'ion-email'; that.icon = 'ion-email dark'; pubkeys = json.params.length > 0 ? json.params[0] : null; - if (pubkeys && pubkeys.indexOf(',') == -1) { + if (pubkeys && pubkeys.indexOf(',') === -1) { that.pubkey = pubkeys; } that.id = json.reference.id; // Do not care about notification ID, because notification screen use message _id } + // user profile record + else if (json.reference && json.reference.index === 'user' && json.reference.type === 'profile') { + that.pubkey = json.params.length > 0 ? json.params[0] : null; + that.state = 'app.wot_identity'; + that.stateParams = { + pubkey: that.pubkey, + uid: json.params && json.params[3], + }; + if (json.code.startsWith('LIKE_')) { + that.avatarIcon = 'ion-person'; + that.icon = 'ion-ios-heart positive'; + } + else if (json.code.startsWith('STAR_')) { + that.avatarIcon = 'ion-person'; + that.icon = 'ion-star gray'; + } + else if (json.code.startsWith('FOLLOW_')) { + that.avatarIcon = 'ion-person'; + that.icon = 'ion-ios-people gray'; + } + else if (json.code.startsWith('ABUSE_')) { + that.avatarIcon = 'ion-person'; + that.icon = 'ion-android-warning assertive'; + } + else if (json.code.startsWith('MODERATION_')) { + that.state = 'app.wot_identity'; + that.stateParams = { + pubkey: json.reference.id, + uid: json.params && json.params[3], + }; + that.avatarIcon = 'ion-alert-circled'; + that.icon = 'ion-alert-circled energized'; + + // If deletion has been asked, change the message + var level = json.params && json.params[4] || 0; + if (json.code === 'MODERATION_RECEIVED' && level == 5) { + that.message = 'EVENT.USER.DELETION_RECEIVED'; + that.icon = 'ion-trash-a assertive'; + } + } + else { + that.icon = 'ion-person dark'; + } + + } + // page record - else if (json.reference && json.reference.index == 'page') { - that.avatarIcon = 'ion-ios-book'; + else if (json.reference && json.reference.index === 'page') { + that.pubkey = json.params.length > 0 ? json.params[0] : null; + that.avatarIcon = 'ion-social-buffer'; if (json.reference.anchor) { that.icon = 'ion-ios-chatbubble-outline dark'; that.state = 'app.view_page_anchor'; @@ -95,26 +143,47 @@ function EsNotification(json, markAsReadCallback) { }; } else { - that.icon = 'ion-ios-book dark'; + that.icon = 'ion-social-buffer dark'; that.state = 'app.view_page'; that.stateParams = { id: json.reference.id, - title: json.params[1]}; + title: json.params[1] + }; + } + + if (json.code.startsWith('LIKE_')) { + that.icon = 'ion-ios-heart positive'; + } + else if (json.code.startsWith('FOLLOW_')) { + that.avatarIcon = 'ion-person'; + } + else if (json.code.startsWith('ABUSE_')) { + that.icon = 'ion-alert-circled energized'; + } + else if (json.code.startsWith('MODERATION_')) { + that.avatarIcon = 'ion-alert-circled'; + that.icon = 'ion-alert-circled energized'; + + // If deletion has been asked, change the message + if (json.code === 'MODERATION_RECEIVED' && level == 5) { + that.message = 'EVENT.PAGE.DELETION_RECEIVED'; + that.icon = 'ion-trash-a assertive'; + } } } // info message - else if (json.type == 'INFO') { + else if (json.type === 'INFO') { that.avatarIcon = 'ion-information'; that.icon = 'ion-information-circled positive'; } // warn message - else if (json.type == 'WARN') { + else if (json.type === 'WARN') { that.avatarIcon = 'ion-alert-circled'; that.icon = 'ion-alert-circled energized'; } // error message - else if (json.type == 'ERROR') { + else if (json.type === 'ERROR') { that.avatarIcon = 'ion-close'; that.icon = 'ion-close-circled assertive'; } diff --git a/www/plugins/es/js/services.js b/www/plugins/es/js/services.js index 0bb32bb2e..ff48151ce 100644 --- a/www/plugins/es/js/services.js +++ b/www/plugins/es/js/services.js @@ -20,6 +20,7 @@ angular.module('cesium.es.services', [ 'cesium.es.tx.services', 'cesium.es.geo.services', 'cesium.es.document.services', - 'cesium.es.network.services' + 'cesium.es.network.services', + 'cesium.es.like.services' ]) ; diff --git a/www/plugins/es/js/services/comment-services.js b/www/plugins/es/js/services/comment-services.js index 5044924bb..b5f5c40d4 100644 --- a/www/plugins/es/js/services/comment-services.js +++ b/www/plugins/es/js/services/comment-services.js @@ -1,7 +1,7 @@ angular.module('cesium.es.comment.services', ['ngResource', 'cesium.services', 'cesium.es.http.services', 'cesium.es.profile.services']) - .factory('esComment', function($rootScope, $q, UIUtils, BMA, esHttp, csWallet, csWot) { + .factory('esComment', function($rootScope, $q, esHttp, csWallet, csWot) { 'ngInject'; function EsComment(index) { diff --git a/www/plugins/es/js/services/http-services.js b/www/plugins/es/js/services/http-services.js index b4a7e6e01..a1fa44289 100644 --- a/www/plugins/es/js/services/http-services.js +++ b/www/plugins/es/js/services/http-services.js @@ -213,8 +213,14 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic that.ws = function(path) { return function() { var sock = that.cache.wsByPath[path]; - if (!sock) { + if (!sock || sock.isClosed()) { sock = csHttp.ws(that.host, that.port, path, that.useSsl); + + // When close, remove from cache + sock.onclose = function() { + delete that.cache.wsByPath[path]; + }; + that.cache.wsByPath[path] = sock; } return sock; @@ -504,13 +510,13 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic function postRecord(path, options) { options = options || {}; var postRequest = that.post(path); - return function(record, options) { - options = options || {}; - var wallet = options.wallet || (options.walletId && csWallet.children.get(options.walletId)) || - ((!options.pubkey || csWallet.isUserPubkey(options.pubkey)) && csWallet) || - (options.pubkey && csWallet.children.getByPubkey(options.pubkey)); + return function(record, params) { + params = params || {}; + var wallet = params.wallet || (params.walletId && csWallet.children.get(params.walletId)) || + ((!params.pubkey || csWallet.isUserPubkey(params.pubkey)) && csWallet) || + (params.pubkey && csWallet.children.getByPubkey(params.pubkey)); - var keypair = options.keypair || wallet && wallet.data && wallet.data.keypair; + var keypair = params.keypair || wallet && wallet.data && wallet.data.keypair; if (!keypair && !wallet) { throw new Error('Missing wallet or keypair, to sign record'); @@ -518,15 +524,15 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic // Create the POSt request params, // but BEFORE, remove protected options - delete options.wallet; - delete options.walletId; - delete options.keypair; - var params = angular.copy(options); + delete params.wallet; + delete params.walletId; + delete params.keypair; + var params = angular.copy(params); params.pubkey = params.pubkey || wallet.data.pubkey; return (wallet.isAuth() ? $q.when(wallet.data) : wallet.auth({silent: true, minData: true})) .then(function() { - if (options.creationTime && !record.creationTime) { + if (params.creationTime && !record.creationTime) { record.creationTime = moment().utc().unix(); } // Always update the time - fix #572 @@ -577,11 +583,14 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic }; } - function countRecord(index, type) { - return that.get("/{0}/{1}/_search?size=0".format(index, type)) - .then(function(res) { - return res && res.hits && res.hits.total; - }); + function countRecords(index, type, cacheTime) { + var getRequest = that.get("/{0}/{1}/_search?size=0".format(index, type), cacheTime); + return function(params) { + return getRequest(params) + .then(function(res) { + return res && res.hits && res.hits.total; + }); + }; } function removeRecord(index, type) { @@ -755,7 +764,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic record: { post: postRecord, remove: removeRecord, - count : countRecord + count : countRecords }, image: { fromAttachment: imageFromAttachment, @@ -785,7 +794,7 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic service.lightInstance = function(host, port, useSsl, timeout) { port = port || 80; - useSsl = angular.isDefined(useSsl) ? useSsl : (port == 443); + useSsl = angular.isDefined(useSsl) ? useSsl : (+port === 443); function countHits(path, params) { return csHttp.get(host, port, path)(params) diff --git a/www/plugins/es/js/services/like-services.js b/www/plugins/es/js/services/like-services.js new file mode 100644 index 000000000..8d0b489c7 --- /dev/null +++ b/www/plugins/es/js/services/like-services.js @@ -0,0 +1,153 @@ +angular.module('cesium.es.like.services', ['ngResource', 'cesium.services', + 'cesium.es.http.services']) + + .factory('esLike', function($q, csWallet, esHttp) { + 'ngInject'; + + function EsLike(index, type) { + + var + raw = { + getSearch: esHttp.get('/like/record/_search?_source=false&q=:q'), + searchBaseQueryString: 'index:{0} AND type:{1} AND id:'.format(index, type), + postSearch: esHttp.post("/like/record/_search"), + postRecord: esHttp.record.post('/{0}/{1}/:id/_like'.format(index, type)), + removeRecord: esHttp.record.remove('like', 'record') + }, + constants = { + KINDS: ['LIKE', 'ABUSE'] + } + ; + + function getLikeIds(id, options) { + options = options || {}; + options.kind = options.kind || 'LIKE'; + var queryString = raw.searchBaseQueryString + id; + if (options.kind) queryString += ' AND kind:' + options.kind.toUpperCase(); + if (options.issuer) queryString += ' AND issuer:' + options.issuer; + + return raw.getSearch({q: queryString}) + .then(function(res) { + return (res && res.hits && res.hits.hits || []).map(function(hit) { + return hit._id; + }); + }); + } + + function addLike(id, options) { + options = options || {}; + options.kind = options.kind && options.kind.toUpperCase() || 'LIKE'; + if (!csWallet.isLogin()) return $q.reject('Wallet must be login before sending record to ES node'); + var record = { + version: 2, + index: index, + type: type, + id: id, + kind: options.kind + }; + if (options.comment) record.comment = options.comment; + if (angular.isDefined(options.level)) record.level = options.level; + + return raw.postRecord(record, options); + } + + function toggleLike(id, options) { + options = options || {}; + options.kind = options.kind || 'LIKE'; + var pubkey = options.pubkey || options.wallet && options.wallet.data.pubkey || (csWallet.isLogin() && csWallet.data.pubkey); + if (!pubkey) return $q.reject('User not log in!'); + options.wallet = options.wallet || csWallet.getByPubkey(pubkey); + return getLikeIds(id, {kind: options.kind, issuer: pubkey}) + .then(function(existingLikeIds) { + // User already like: so remove it + if (existingLikeIds && existingLikeIds.length) { + return $q.all(_.map(existingLikeIds, function(likeId) { + return removeLike(likeId, options) + })) + // Return the deletion, as a delta + .then(function() { + return -1 * existingLikeIds.length; + }); + } + // User not like, so add it + else { + return addLike(id, options) + // Return the insertion, as a delta + .then(function() { + return +1; + }); + } + }); + } + + function removeLike(id, options) { + if (!id) throw new Error("Missing 'id' argument"); + return raw.removeRecord(id, options); + } + + function countLike(id, options) { + options = options || {}; + options.kind = options.kind || 'LIKE'; + + var request = { + query: { + bool: { + filter: [ + {term: {index: index}}, + {term: {type: type}}, + {term: {id: id}}, + {term: {kind: options.kind.toUpperCase()}} + ] + } + }, + size: 0 + }; + + // To known if the user already like, add 'should' on issuers + var issuers = options.issuer ? [options.issuer] : options.issuers; + if (issuers && issuers.length) { + request.query.bool.should = {terms: {issuer: issuers}}; + request.size = issuers.length; + request._source = ["issuer"]; + } + + return raw.postSearch(request) + .then(function(res) { + var hits = res && res.hits; + var result = { + total: hits && hits.total || 0, + wasHitByPubkey: {}, + wasHitCount: 0 + }; + + // Check is issuer is return (because of size=1 and should filter) + _.forEach(issuers, function(issuer) { + var issuerHitIndex = hits ? _.findIndex(hits.hits || [], function(hit) { + return hit._source.issuer === issuer; + }) : -1; + + result.wasHitByPubkey[issuer] = issuerHitIndex !== -1 || false; + result.wasHitCount += issuerHitIndex !== -1 ? 1 : 0; + }) + + return result; + }) + } + + // Expose functions + return { + index: index, + type: type, + constants: constants, + toggle: toggleLike, + add: addLike, + remove: removeLike, + count: countLike + }; + } + + return { + instance: EsLike + }; + }) +; diff --git a/www/plugins/es/js/services/profile-services.js b/www/plugins/es/js/services/profile-services.js index c36f3123b..95cbe011e 100644 --- a/www/plugins/es/js/services/profile-services.js +++ b/www/plugins/es/js/services/profile-services.js @@ -1,4 +1,4 @@ -angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http.services']) +angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http.services', 'cesium.es.like.services']) .config(function(PluginServiceProvider, csConfig) { 'ngInject'; @@ -10,7 +10,7 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http }) - .factory('esProfile', function($rootScope, $q, esHttp, SocialUtils, csWot, csWallet, csPlatform, esSettings) { + .factory('esProfile', function($rootScope, $q, esHttp, SocialUtils, csWot, csWallet, csPlatform, esSettings, esLike) { 'ngInject'; var @@ -385,9 +385,10 @@ angular.module('cesium.es.profile.services', ['cesium.services', 'cesium.es.http get: getProfile, add: esHttp.record.post('/user/profile', {tagFields: ['title', 'description']}), update: esHttp.record.post('/user/profile/:id/_update', {tagFields: ['title', 'description']}), + remove: esHttp.record.remove("user","profile"), avatar: esHttp.get('/user/profile/:id?_source=avatar'), fillAvatars: fillAvatars, - remove: esHttp.record.remove("user","profile") + like: esLike.instance('user', 'profile') }; }) ; diff --git a/www/plugins/es/js/services/registry-services.js b/www/plugins/es/js/services/registry-services.js index 800da207c..1007bfff1 100644 --- a/www/plugins/es/js/services/registry-services.js +++ b/www/plugins/es/js/services/registry-services.js @@ -1,4 +1,4 @@ -angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', 'cesium.es.http.services']) +angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', 'cesium.es.http.services', 'cesium.es.like.services']) .config(function(PluginServiceProvider, csConfig) { 'ngInject'; @@ -10,7 +10,7 @@ angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', }) -.factory('esRegistry', function($rootScope, $q, csPlatform, csSettings, csWallet, csWot, esHttp, esComment, esGeo) { +.factory('esRegistry', function($rootScope, $q, csPlatform, csSettings, csWallet, csWot, esHttp, esComment, esLike, esGeo) { 'ngInject'; var @@ -289,6 +289,7 @@ angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', picture: { all: esHttp.get('/page/record/:id?_source=pictures') }, + like: esLike.instance('page', 'record'), comment: esComment.instance('page') }; that.currency = { diff --git a/www/plugins/es/templates/common/popup_report_abuse.html b/www/plugins/es/templates/common/popup_report_abuse.html new file mode 100644 index 000000000..6e2c9f93f --- /dev/null +++ b/www/plugins/es/templates/common/popup_report_abuse.html @@ -0,0 +1,37 @@ +<form name="abuseForm" ng-submit=""> + <div class="list" ng-init="setAbuseForm(abuseForm)"> + + <!-- reason --> + <label class="item item-input" + ng-class="{'item-input-error': abuseForm.$submitted && abuseForm.comment.$invalid}"> + <textarea class="padding" style="background-color: transparent;" + name="comment" type="text" placeholder="{{'COMMON.REPORT_ABUSE.REASON_HELP' | translate}}" + rows="3" + ng-model="abuseData.comment" + ng-minlength="8" + required></textarea> + </label> + <div class="form-errors" + ng-if="abuseForm.$submitted && abuseForm.comment.$error" + ng-messages="abuseForm.comment.$error"> + <div class="form-error" ng-message="required"> + <span translate="ERROR.FIELD_REQUIRED"></span> + </div> + <div class="form-error" ng-message="minlength"> + <span translate="ERROR.FIELD_TOO_SHORT"></span> + </div> + </div> + + <div class="item item-toggle item-text-wrap dark"> + <div class="input-label" translate>COMMON.REPORT_ABUSE.ASK_DELETE</div> + <label class="toggle toggle-royal"> + <input type="checkbox" ng-model="abuseData.delete" > + <div class="track"> + <div class="handle"></div> + </div> + </label> + </div> + </div> +</form> + + diff --git a/www/plugins/es/templates/common/view_likes.html b/www/plugins/es/templates/common/view_likes.html new file mode 100644 index 000000000..5441724dd --- /dev/null +++ b/www/plugins/es/templates/common/view_likes.html @@ -0,0 +1,25 @@ + +<div class="likes"> + + <!-- likes --> + <ng-if ng-if="likeData.likes && likeData.likes.total"> + <span ng-class="{'gray': !likeData.likes.wasHitCount, 'positive': likeData.likes.wasHitCount}"> + <a title="{{'COMMON.LIKES_TEXT'|translate: likeData.likes }}" + ng-click="!canEdit && toggleLike($event, {kind: 'like'})"> + {{likeData.likes.total}} + <i class="icon ion-heart"></i> + </a> + </span> + </ng-if> + + <!-- abuses --> + <ng-if ng-if="likeData.abuses && likeData.abuses.total"> + <span class="gray" ng-if="likeData.likes && likeData.likes.total"> | </span> + <a ng-class="{'assertive': likeData.abuses.wasHitCount}" + ng-click="!canEdit && reportAbuse($event)" + title="{{'COMMON.ABUSES_TEXT'|translate: likeData.abuses }}"> + {{likeData.abuses.total}} + <i class="icon ion-android-warning"></i> + </a> + </ng-if> +</div> diff --git a/www/plugins/es/templates/network/item_content_peer.html b/www/plugins/es/templates/network/item_content_peer.html index efbad7b39..69de08a63 100644 --- a/www/plugins/es/templates/network/item_content_peer.html +++ b/www/plugins/es/templates/network/item_content_peer.html @@ -28,7 +28,7 @@ </span> <span ng-if=":rebind:peer.hasEndpoint('ES_SUBSCRIPTION_API')" title="{{'ES_PEER.EMAIL_SUBSCRIPTION_COUNT'|translate: peer.docCount }}"> - <i class="ion-email"></i> {{:rebind:peer.docCount.emailSubscription || '?'}} + <i class="ion-email"></i> {{:rebind:peer.docCount.emailSubscription}} </span> </div> <div ng-if=":rebind:peer.isTor()"> diff --git a/www/plugins/es/templates/notification/view_notifications.html b/www/plugins/es/templates/notification/view_notifications.html index b77c2b9fe..98226cfec 100644 --- a/www/plugins/es/templates/notification/view_notifications.html +++ b/www/plugins/es/templates/notification/view_notifications.html @@ -10,7 +10,7 @@ </button> </ion-nav-buttons> - <ion-content class="padding no-padding-xs no-padding-sm" scroll="true"> + <ion-content scroll="true"> <ion-refresher pulling-text="{{'COMMON.BTN_REFRESH' | translate}}" on-refresh="refresh(true)"> </ion-refresher> diff --git a/www/plugins/es/templates/registry/view_popover_actions.html b/www/plugins/es/templates/registry/view_popover_actions.html index 4a972edb2..3f69517d1 100644 --- a/www/plugins/es/templates/registry/view_popover_actions.html +++ b/www/plugins/es/templates/registry/view_popover_actions.html @@ -5,18 +5,29 @@ <ion-content scroll="false"> <div class="list item-text-wrap"> - <a class="item item-icon-left ink" + <a class="item item-icon-left ink visible-xs visible-sm" ng-click="showSharePopover($event)"> <i class="icon ion-android-share-alt"></i> {{'COMMON.BTN_SHARE' | translate}} </a> - <a class="item item-icon-left assertive ink" + <a class="item item-icon-left assertive ink visible-xs visible-sm" ng-if="canEdit" ng-click="delete()"> <i class="icon ion-trash-a"></i> {{'COMMON.BTN_DELETE' | translate}} </a> + + <!-- report abuse --> + <ng-if ng-if="!canEdit && likeData.abuses"> + <button class="item item-icon-left ink" + ng-disabled="!!likeData.abuses.wasHitCount" + ng-class="{'gray': !!likeData.abuses.wasHitCount}" + ng-click="hideActionsPopover() && reportAbuse($event)"> + <i class="icon ion-android-warning"></i> + {{'COMMON.BTN_REPORT_ABUSE_DOTS' | translate}} + </button> + </ng-if> </div> </ion-content> </ion-popover-view> diff --git a/www/plugins/es/templates/registry/view_record.html b/www/plugins/es/templates/registry/view_record.html index 74cecad9d..03730c7cb 100644 --- a/www/plugins/es/templates/registry/view_record.html +++ b/www/plugins/es/templates/registry/view_record.html @@ -23,15 +23,28 @@ <i class="avatar cion-page-{{formData.type}}" ng-if="!formData.avatar"></i> <i class="avatar" ng-style="{{avatarStyle}}" ng-if="formData.avatar"></i> <h3><span class="dark" ng-bind-html="formData.title"></span></h3> - <h4> </h4> + <h4 class="gray"> + <span ng-if="formData.city" class="gray hidden-xs hidden-sm"> + <i class="icon ion-location"></i> <span ng-bind-html="formData.city"></span> + </span> + <!-- likes --> + <small ng-include="'plugins/es/templates/common/view_likes.html'"></small> + </h4> + </div> + <h4 class="content dark" ng-if="loading"> <ion-spinner icon="android"></ion-spinner> </h4> - <h4 class="content gray hidden-xs hidden-sm" ng-if="formData.city"> - <i class="icon ion-location"></i> - <span ng-bind-html="formData.city"></span> - </h4> + </div> + + <!-- Top fab button --> + <div class="visible-xs visible-sm"> + <!-- like --> + <button class="button button-fab button-fab-top-right button-stable" + ng-click="toggleLike($event)"> + <i class="icon ion-heart" ng-class="{'gray': !likeData.likes.wasHitCount, 'calm': likeData.likes.wasHitCount}"></i> + </button> </div> <div class="row no-padding-xs no-padding-sm"> @@ -66,7 +79,7 @@ {{issuer.pubkey|formatPubkey}} </span> </a> - <span > + <span> {{formData.time|formatFromNow}} <h4 class="gray hidden-xs">| {{formData.time | formatDate}} @@ -81,6 +94,14 @@ <button class="button button-stable button-small-padding icon ion-android-share-alt" ng-click="showSharePopover($event)"> </button> + <!-- Like button --> + <button class="button button-stable button-small-padding ink-dark" + ng-if="!canEdit" + title="{{'COMMON.BTN_LIKE' | translate }}" + ng-click="toggleLike($event)"> + <i class="icon ion-heart" ng-class="{'gray': !likeData.likes.wasHitCount, 'calm': likeData.likes.wasHitCount}"></i> + </button> + <button class="button button-calm ink-dark" ng-if="showTransfer" ng-click="showTransferModal({pubkey:formData.pubkey, uid: formData.title})"> @@ -97,6 +118,12 @@ ng-click="edit()"> {{'COMMON.BTN_EDIT' | translate}} </button> + + <!-- options --> + <button class="button button-stable button-small-padding icon ion-android-more-vertical" + ng-if="!canEdit" + ng-click="showActionsPopover($event)"> + </button> </div> <div class="item"> diff --git a/www/plugins/es/templates/wallet/view_wallet_extend.html b/www/plugins/es/templates/wallet/view_wallet_extend.html index 7fe4439c4..ef2db1aa6 100644 --- a/www/plugins/es/templates/wallet/view_wallet_extend.html +++ b/www/plugins/es/templates/wallet/view_wallet_extend.html @@ -1,4 +1,12 @@ -<ng-if ng-if=":state:enable"> +<ng-if ng-if=":state:enable && extensionPoint === 'hero'" > + <!-- likes --> + <small class="light" style="display: inline-block;" + ng-include="'plugins/es/templates/common/view_likes.html'" + ng-init="canEdit=true"></small> +</ng-if> + +<ng-if ng-if=":state:enable && extensionPoint === 'after-general'"> + <!-- profile --> <div class="item item-divider item-divider-top-border"> <span> @@ -93,7 +101,7 @@ <a class="badge button button-text button-small button-small-padding " ng-if="!formData.pages.count" - ng-click="showNewPageModal()"> + ng-click="showNewPageModal($event)"> <i class="icon ion-edit"></i> <span translate>REGISTRY.BTN_NEW</span> </a> diff --git a/www/plugins/es/templates/wot/view_identity_extend.html b/www/plugins/es/templates/wot/view_identity_extend.html index a5aa6df8a..0c47c382b 100644 --- a/www/plugins/es/templates/wot/view_identity_extend.html +++ b/www/plugins/es/templates/wot/view_identity_extend.html @@ -1,9 +1,8 @@ -<!-- Buttons section --> -<ng-if ng-if=":state:enable && extensionPoint === 'buttons'"> - <button class="button button-stable button-small-padding icon ion-compose" - ng-click="showNewMessageModal()" - title="{{'MESSAGE.BTN_WRITE' | translate}}"> - </button> +<!-- Hero --> +<ng-if ng-if=":state:enable && extensionPoint === 'hero'"> + <!-- likes --> + <small class="light" style="display: inline-block;" + ng-include="'plugins/es/templates/common/view_likes.html'"></small> </ng-if> <!-- Top fab buttons --> @@ -16,6 +15,22 @@ </button> </ng-if> +<!-- Buttons section --> +<ng-if ng-if=":state:enable && extensionPoint === 'buttons'"> + <button class="button button-stable button-small-padding icon ion-compose" + ng-click="showNewMessageModal()" + title="{{'MESSAGE.BTN_WRITE' | translate}}"> + </button> +</ng-if> + +<!-- End of buttons section --> +<ng-if ng-if=":state:enable && extensionPoint === 'after-buttons'"> + <!-- options --> + <button class="button button-stable button-small-padding icon ion-android-more-vertical" + ng-click="showActionsPopover($event)"> + </button> +</ng-if> + <!-- General section --> <ng-if ng-if=":state:enable && extensionPoint === 'after-general'"> diff --git a/www/plugins/es/templates/wot/view_popover_actions.html b/www/plugins/es/templates/wot/view_popover_actions.html new file mode 100644 index 000000000..c3ba6ad5f --- /dev/null +++ b/www/plugins/es/templates/wot/view_popover_actions.html @@ -0,0 +1,40 @@ +<ion-popover-view class="fit has-header"> + <ion-header-bar> + <h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1> + </ion-header-bar> + <ion-content scroll="false"> + <div class="list item-text-wrap"> + + <a class="item item-icon-left ink visible-xs visible-sm" + ng-click="showSharePopover($event)"> + <i class="icon ion-android-share-alt"></i> + {{'COMMON.BTN_SHARE' | translate}} + </a> + + <!--<a class="item item-icon-left assertive ink " + ng-if="canEdit" + ng-click="delete()"> + <i class="icon ion-trash-a"></i> + {{'COMMON.BTN_DELETE' | translate}} + </a>--> + + <!-- Like --> + <a class="item item-icon-left ink" + ng-if="!canEdit && likeData.likes" + ng-click="hideActionsPopover() && toggleLike($event)"> + <i class="icon " ng-class="{'ion-heart-broken': likeData.likes.wasHit, 'ion-heart': !likeData.likes.wasHit}"></i> + {{(likeData.likes.wasHit ? 'COMMON.BTN_LIKE_REMOVE' : 'COMMON.BTN_LIKE' )| translate}} + </a> + + <!-- report abuse --> + <a class="item item-icon-left ink" + ng-if="!canEdit && likeData.abuses" + ng-disabled="!!likeData.abuses.wasHitCount" + ng-class="{'gray': !!likeData.abuses.wasHitCount}" + ng-click="hideActionsPopover() && reportAbuse($event)"> + <i class="icon ion-android-warning"></i> + {{'COMMON.BTN_REPORT_ABUSE_DOTS' | translate}} + </a> + </div> + </ion-content> +</ion-popover-view> diff --git a/www/plugins/graph/js/controllers/account-controllers.js b/www/plugins/graph/js/controllers/account-controllers.js index 5f5b3fa9b..5504af3a9 100644 --- a/www/plugins/graph/js/controllers/account-controllers.js +++ b/www/plugins/graph/js/controllers/account-controllers.js @@ -12,7 +12,7 @@ angular.module('cesium.graph.account.controllers', ['chart.js', 'cesium.graph.se points: { 'buttons': { templateUrl: "plugins/graph/templates/account/view_wallet_tx_extend.html", - controller: 'GpExtendCtrl' + controller: 'ESExtensionCtrl' } } }) @@ -21,16 +21,7 @@ angular.module('cesium.graph.account.controllers', ['chart.js', 'cesium.graph.se points: { 'buttons': { templateUrl: "plugins/graph/templates/account/view_wallet_tx_extend.html", - controller: 'GpExtendCtrl' - } - } - }) - - .extendState('app.wot_identity', { - points: { - 'buttons': { - templateUrl: "plugins/graph/templates/account/view_identity_extend.html", - controller: 'GpExtendCtrl' + controller: 'ESExtensionCtrl' } } }) @@ -39,7 +30,7 @@ angular.module('cesium.graph.account.controllers', ['chart.js', 'cesium.graph.se points: { 'buttons': { templateUrl: "plugins/graph/templates/account/view_identity_tx_extend.html", - controller: 'GpExtendCtrl' + controller: 'ESExtensionCtrl' } } }) @@ -81,40 +72,13 @@ angular.module('cesium.graph.account.controllers', ['chart.js', 'cesium.graph.se } }) - .controller('GpExtendCtrl', GpExtendController) - .controller('GpAccountBalanceCtrl', GpAccountBalanceController) .controller('GpAccountSumTxCtrl', GpAccountSumTxController) .controller('GpAccountCertificationCtrl', GpAccountCertificationController) - ; -function GpExtendController($scope, PluginService, esSettings, $state, csWallet) { - 'ngInject'; - - $scope.extensionPoint = PluginService.extensions.points.current.get(); - $scope.enable = esSettings.isEnable(); - - esSettings.api.state.on.changed($scope, function(enable) { - $scope.enable = enable; - }); - - $scope.showIdentityStats = function() { - if ($scope.formData && $scope.formData.pubkey) { - $state.go('app.wot_identity_stats', {pubkey: $scope.formData.pubkey}); - } - }; - - $scope.showWalletStats = function() { - if (csWallet.isLogin()) { - $state.go('app.wot_identity_stats', {pubkey: csWallet.data.pubkey}); - } - }; -} - - function GpAccountBalanceController($scope, $controller, $q, $state, $filter, $translate, csWot, gpData, gpColor, csWallet) { 'ngInject'; diff --git a/www/plugins/graph/templates/account/view_identity_extend.html b/www/plugins/graph/templates/account/view_identity_extend.html deleted file mode 100644 index 65ff216db..000000000 --- a/www/plugins/graph/templates/account/view_identity_extend.html +++ /dev/null @@ -1,9 +0,0 @@ -<!-- Buttons section --> -<ng-if ng-if="extensionPoint === 'buttons'"> - - <button class="button button-stable button-small-padding icon ion-stats-bars" - ng-click="showIdentityStats()" - title="{{'GRAPH.ACCOUNT.BTN_SHOW_STATS' | translate}}"> - </button> - -</ng-if> diff --git a/www/plugins/graph/templates/account/view_identity_tx_extend.html b/www/plugins/graph/templates/account/view_identity_tx_extend.html index 65ff216db..1c4463581 100644 --- a/www/plugins/graph/templates/account/view_identity_tx_extend.html +++ b/www/plugins/graph/templates/account/view_identity_tx_extend.html @@ -1,8 +1,8 @@ <!-- Buttons section --> -<ng-if ng-if="extensionPoint === 'buttons'"> +<ng-if ng-if=":state:enable && extensionPoint === 'buttons'"> <button class="button button-stable button-small-padding icon ion-stats-bars" - ng-click="showIdentityStats()" + ui-sref="app.wot_identity_stats({pubkey: formData.pubkey})" title="{{'GRAPH.ACCOUNT.BTN_SHOW_STATS' | translate}}"> </button> diff --git a/www/plugins/graph/templates/account/view_wallet_tx_extend.html b/www/plugins/graph/templates/account/view_wallet_tx_extend.html index b8cd1c04a..1c4463581 100644 --- a/www/plugins/graph/templates/account/view_wallet_tx_extend.html +++ b/www/plugins/graph/templates/account/view_wallet_tx_extend.html @@ -1,8 +1,8 @@ <!-- Buttons section --> -<ng-if ng-if="extensionPoint === 'buttons'"> +<ng-if ng-if=":state:enable && extensionPoint === 'buttons'"> <button class="button button-stable button-small-padding icon ion-stats-bars" - ng-click="showWalletStats()" + ui-sref="app.wot_identity_stats({pubkey: formData.pubkey})" title="{{'GRAPH.ACCOUNT.BTN_SHOW_STATS' | translate}}"> </button> diff --git a/www/plugins/graph/templates/currency/tab_blocks_extend.html b/www/plugins/graph/templates/currency/tab_blocks_extend.html index f6c4c5e19..11fa547c8 100644 --- a/www/plugins/graph/templates/currency/tab_blocks_extend.html +++ b/www/plugins/graph/templates/currency/tab_blocks_extend.html @@ -1,5 +1,5 @@ <!-- buttons --> -<ng-if ng-if="enable && extensionPoint === 'buttons'"> +<ng-if ng-if=":state:enable && extensionPoint === 'buttons'"> <div class="item item-divider"> <a class="badge button button-text button-small button-small-padding ink" ui-sref="app.currency.tab_blocks_stats"> <i class="icon ion-stats-bars"></i> diff --git a/www/plugins/graph/templates/currency/view_currency_extend.html b/www/plugins/graph/templates/currency/view_currency_extend.html index 088160024..5b6317b37 100644 --- a/www/plugins/graph/templates/currency/view_currency_extend.html +++ b/www/plugins/graph/templates/currency/view_currency_extend.html @@ -1,6 +1,6 @@ <!-- section actual parameters --> -<ng-if ng-if="enable && extensionPoint === 'parameters-actual'" > +<ng-if ng-if=":state:enable && extensionPoint === 'parameters-actual'" > <ng-if ng-if="!smallscreen"> <div class="item padding-left padding-right no-padding-xs no-padding-sm" @@ -26,7 +26,7 @@ </ng-if> <!-- section Wot --> -<ng-if ng-if="enable && extensionPoint === 'wot-actual'" > +<ng-if ng-if=":state:enable && extensionPoint === 'wot-actual'" > <ng-if ng-if="!smallscreen"> <div class="item padding-left padding-right no-padding-xs no-padding-sm" @@ -51,7 +51,7 @@ </ng-if> <!-- section Wot --> -<ng-if ng-if="enable && extensionPoint === 'network-actual'" > +<ng-if ng-if=":state:enable && extensionPoint === 'network-actual'" > <div class="item padding-left padding-right no-padding-xs no-padding-sm" ng-if="!smallscreen" diff --git a/www/plugins/graph/templates/network/view_es_peer_extend.html b/www/plugins/graph/templates/network/view_es_peer_extend.html index e150d7795..71a1891fe 100644 --- a/www/plugins/graph/templates/network/view_es_peer_extend.html +++ b/www/plugins/graph/templates/network/view_es_peer_extend.html @@ -1,5 +1,5 @@ <!-- Buttons section --> -<ng-if ng-if="enable && extensionPoint === 'general'"> +<ng-if ng-if=":state:enable && extensionPoint === 'general'"> <a class="item item-icon-left item-icon-right item-text-wrap ink" ng-if="isReachable" diff --git a/www/plugins/graph/templates/network/view_peer_extend.html b/www/plugins/graph/templates/network/view_peer_extend.html index f4f62451b..2e07444c2 100644 --- a/www/plugins/graph/templates/network/view_peer_extend.html +++ b/www/plugins/graph/templates/network/view_peer_extend.html @@ -1,5 +1,5 @@ <!-- Buttons section --> -<ng-if ng-if="enable && extensionPoint === 'general'"> +<ng-if ng-if=":state:enable && extensionPoint === 'general'"> <a class="item item-icon-left item-icon-right item-text-wrap ink" ui-sref="app.view_peer_stats({pubkey: node.pubkey})"> diff --git a/www/templates/blockchain/list_blocks_lg.html b/www/templates/blockchain/list_blocks_lg.html index 8c9d6763e..8d8d1ca97 100644 --- a/www/templates/blockchain/list_blocks_lg.html +++ b/www/templates/blockchain/list_blocks_lg.html @@ -22,7 +22,7 @@ BLOCKCHAIN.LOOKUP.NO_BLOCK </div> <!-- blocks --> - <ng-repeat ng-repeat="block in search.results" + <ng-repeat ng-repeat="block in search.results track by block.id" ng-include="!block.empty ? 'templates/blockchain/item_block_lg.html' : 'templates/blockchain/item_block_empty_lg.html'"> </ng-repeat> </ion-list> diff --git a/www/templates/wallet/view_wallet.html b/www/templates/wallet/view_wallet.html index 18d39744f..0b1e7d4cb 100644 --- a/www/templates/wallet/view_wallet.html +++ b/www/templates/wallet/view_wallet.html @@ -63,8 +63,9 @@ </a> </h3> - <h4 class="assertive"> - <span ng-if=":rebind:(formData.name || formData.uid) && !formData.isMember" translate>WOT.NOT_MEMBER_PARENTHESIS</span> + <h4> + <span class="assertive" ng-if=":rebind:(formData.name || formData.uid) && !formData.isMember" translate>WOT.NOT_MEMBER_PARENTHESIS</span> + <cs-extension-point name="hero"></cs-extension-point> </h4> </div> <h4 class="content light" ng-if="loading"> diff --git a/www/templates/wot/view_identity.html b/www/templates/wot/view_identity.html index 055a26520..3a6604907 100644 --- a/www/templates/wot/view_identity.html +++ b/www/templates/wot/view_identity.html @@ -3,8 +3,7 @@ </ion-nav-title> <ion-content scroll="true" - class="refresher-light" - ng-class="{'member refresher-positive-900-bg': !loading && formData.isMember, 'refresher-dark-100-bg': loading || !formData.isMember}"> + ng-class="{'member': !loading && formData.isMember}"> <ion-refresher pulling-text="{{'COMMON.BTN_REFRESH' | translate}}" on-refresh="doUpdate(true)"> @@ -25,9 +24,10 @@ <h3 class="light" ng-if=":rebind:formData.uid">{{:rebind:formData.uid}}</h3> <h3 class="light" ng-if=":rebind:!formData.uid"><i class="ion-key"></i> {{:rebind:formData.pubkey | formatPubkey}}</h3> </ng-if> - <h4 class="assertive"> - <ng-if ng-if=":rebind:(formData.name || formData.uid) && !formData.isMember && revoked" translate>WOT.IDENTITY_REVOKED_PARENTHESIS</ng-if> - <ng-if ng-if=":rebind:(formData.name || formData.uid) && formData.isMember && revoked" translate>WOT.MEMBER_PENDING_REVOCATION_PARENTHESIS</ng-if> + <h4> + <ng-if class="assertive" ng-if=":rebind:(formData.name || formData.uid) && !formData.isMember && revoked" translate>WOT.IDENTITY_REVOKED_PARENTHESIS</ng-if> + <ng-if class="assertive" ng-if=":rebind:(formData.name || formData.uid) && formData.isMember && revoked" translate>WOT.MEMBER_PENDING_REVOCATION_PARENTHESIS</ng-if> + <cs-extension-point name="hero"></cs-extension-point> </h4> </div> @@ -65,6 +65,8 @@ ng-click="showTransferModal({pubkey:formData.pubkey, uid: formData.name||formData.uid})"> {{'COMMON.BTN_SEND_MONEY' | translate}} </button> + + <cs-extension-point name="after-buttons"></cs-extension-point> </div> <!-- fab buttons --> -- GitLab