From fcf00ae13ecf4e1540698ef030a5a82a7d452c4b Mon Sep 17 00:00:00 2001 From: blavenie <benoit.lavenier@e-is.pro> Date: Thu, 12 Oct 2017 15:34:00 +0200 Subject: [PATCH] [fix] Page: fix deletion [enh] Page: edit avatar using a modal [enh] Page: add fields for position (lat/lon) [fix] Comment: send new comment when not auth : hide loading toast --- www/plugins/es/i18n/locale-en-GB.json | 3 +- www/plugins/es/i18n/locale-en.json | 3 +- www/plugins/es/i18n/locale-fr-FR.json | 3 +- .../es/js/controllers/common-controllers.js | 198 ++++++++++++ .../es/js/controllers/profile-controllers.js | 178 +--------- .../es/js/controllers/registry-controllers.js | 303 +++++++++++++++--- .../es/js/services/comment-services.js | 4 +- www/plugins/es/js/services/http-services.js | 4 +- .../es/js/services/registry-services.js | 11 +- .../es/templates/common/edit_position.html | 102 ++++++ .../es/templates/group/edit_group.html | 2 +- .../es/templates/registry/edit_record.html | 67 ++-- .../es/templates/registry/view_record.html | 4 +- .../es/templates/user/edit_profile.html | 105 +----- .../es/templates/user/modal_edit_avatar.html | 57 ++-- 15 files changed, 641 insertions(+), 403 deletions(-) create mode 100644 www/plugins/es/templates/common/edit_position.html diff --git a/www/plugins/es/i18n/locale-en-GB.json b/www/plugins/es/i18n/locale-en-GB.json index 6f3ae1c34..3e4ee8c6c 100644 --- a/www/plugins/es/i18n/locale-en-GB.json +++ b/www/plugins/es/i18n/locale-en-GB.json @@ -269,7 +269,8 @@ "FAILED_REMOVE_COMMENT": "Deleting comment failed" }, "INFO": { - "RECORD_REMOVED" : "Reference successfully deleted" + "RECORD_REMOVED" : "Page successfully deleted", + "RECORD_SAVED": "Page successfully saved" } }, "PROFILE": { diff --git a/www/plugins/es/i18n/locale-en.json b/www/plugins/es/i18n/locale-en.json index 6f3ae1c34..3e4ee8c6c 100644 --- a/www/plugins/es/i18n/locale-en.json +++ b/www/plugins/es/i18n/locale-en.json @@ -269,7 +269,8 @@ "FAILED_REMOVE_COMMENT": "Deleting comment failed" }, "INFO": { - "RECORD_REMOVED" : "Reference successfully deleted" + "RECORD_REMOVED" : "Page successfully deleted", + "RECORD_SAVED": "Page successfully saved" } }, "PROFILE": { diff --git a/www/plugins/es/i18n/locale-fr-FR.json b/www/plugins/es/i18n/locale-fr-FR.json index 9df790aa5..50e803dd3 100644 --- a/www/plugins/es/i18n/locale-fr-FR.json +++ b/www/plugins/es/i18n/locale-fr-FR.json @@ -320,7 +320,8 @@ "FAILED_REMOVE_COMMENT": "Erreur lors de la suppression du commentaire" }, "INFO": { - "RECORD_REMOVED" : "Page supprimée" + "RECORD_REMOVED" : "Page supprimée", + "RECORD_SAVED": "Page sauvegardée" } }, "PROFILE": { diff --git a/www/plugins/es/js/controllers/common-controllers.js b/www/plugins/es/js/controllers/common-controllers.js index 5ea4c65b3..284ece732 100644 --- a/www/plugins/es/js/controllers/common-controllers.js +++ b/www/plugins/es/js/controllers/common-controllers.js @@ -12,6 +12,10 @@ angular.module('cesium.es.common.controllers', ['ngResource', 'cesium.es.service .controller('ESCategoryModalCtrl', ESCategoryModalController) + .controller('ESAvatarModalCtrl', ESAvatarModalController) + + .controller('ESPositionEditCtrl', ESPositionEditController) + ; @@ -358,3 +362,197 @@ function ESSocialsViewController($scope) { }; } + + + +function ESAvatarModalController($scope) { + + $scope.formData = { + initCrop: false, + imageCropStep: 0, + imgSrc: undefined, + result: undefined, + resultBlob: undefined + }; + + $scope.openFileSelector = function() { + var fileInput = angular.element(document.querySelector('.modal-avatar #fileInput')); + if (fileInput && fileInput.length > 0) { + fileInput[0].click(); + } + }; + + $scope.fileChanged = function(e) { + + var files = e.target.files; + var fileReader = new FileReader(); + fileReader.readAsDataURL(files[0]); + + fileReader.onload = function(e) { + $scope.formData.imgSrc = this.result; + $scope.$apply(); + }; + }; + + $scope.doNext = function() { + if ($scope.formData.imageCropStep == 2) { + $scope.doCrop(); + } + else if ($scope.formData.imageCropStep == 3) { + $scope.closeModal($scope.formData.result); + } + }; + + $scope.doCrop = function() { + $scope.formData.initCrop = true; + }; + + $scope.clear = function() { + $scope.formData = { + initCrop: false, + imageCropStep: 1, + imgSrc: undefined, + result: undefined, + resultBlob: undefined + }; + }; + +} + + +function ESPositionEditController($scope, $q, $translate, + csConfig, UIUtils, esGeo, ModalUtils) { + 'ngInject'; + + // The default country used for address localisation + var defaultCountry = csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.defaultCountry; + + //$scope.formData = $scope.formData || {}; + //$scope.formData.geoPoint = $scope.formData.geoPoint || {}; + + $scope.localizeByAddress = function() { + + return UIUtils.loading.show() + .then($scope.searchPositions) + .then(function(res) { + UIUtils.loading.hide(); + + if (!res) return; // no result, or city value just changed + if (res.length == 1) { + return res[0]; + } + + return ModalUtils.show('plugins/es/templates/common/modal_category.html', 'ESCategoryModalCtrl as ctrl', + { + categories : res, + title: 'PROFILE.MODAL_LOCATIONS.TITLE' + }, + {focusFirstInput: true} + ); + }) + .then(function(res) { + if (res && res.lat && res.lon) { + $scope.formData.geoPoint = $scope.formData.geoPoint || {}; + $scope.formData.geoPoint.lat = parseFloat(res.lat); + $scope.formData.geoPoint.lon = parseFloat(res.lon); + } + }) + .catch(UIUtils.onError('PROFILE.ERROR.ADDRESS_LOCATION_FAILED')); + }; + + $scope.searchPositions = function(query) { + + // Build the query + if (!query) { + if (!$scope.formData.city) { + return $q.when(); // nothing to search + } + + var cityPart = $scope.formData.city.split(','); + var city = cityPart[0]; + + var country = cityPart.length > 1 ? cityPart[1].trim() : defaultCountry; + var street = $scope.formData.address ? angular.copy($scope.formData.address.trim()) : undefined; + if (street) { + // Search with AND without street + return $q.all([ + $scope.searchPositions({ + street: street, + city: city, + country: country + }), + $scope.searchPositions({ + city: city, + country: country + }) + ]) + .then(function(res){ + return res[0].concat(res[1]); + }); + } + else { + return $scope.searchPositions({ + city: city, + country: country + }); + } + } + + var queryString = (query.street ? query.street + ', ' : '') + + query.city + + (query.country ? ', ' + query.country : ''); + // Execute the given query + return $q.all([ + $translate('PROFILE.MODAL_LOCATIONS.RESULT_DIVIDER', {address: queryString}), + esGeo.point.searchByAddress(query) + ]) + .then(function(res) { + var dividerText = res[0]; + res = res[1]; + if (!res) return $q.when(); // no result + + // Ask user to choose + var parent = {name: dividerText}; + var hits = res.reduce(function(res, hit){ + if (hit.class == 'waterway') return res; + return res.concat({ + name: hit.display_name, + parent: parent, + lat: hit.lat, + lon: hit.lon + }); + }, [parent]); + + if (hits.length == 1) return $q.when(); // no result (after filtering) + + return hits; + }); + }; + + $scope.localizeMe = function() { + return esGeo.point.current() + .then(function(position) { + if (!position || !position.lat || !position.lon) return; + $scope.formData.geoPoint = $scope.formData.geoPoint || {}; + $scope.formData.geoPoint.lat = parseFloat(position.lat); + $scope.formData.geoPoint.lon = parseFloat(position.lon); + }) + .catch(UIUtils.onError('PROFILE.ERROR.GEO_LOCATION_FAILED')); + }; + + $scope.removeLocalisation = function() { + if ($scope.formData.geoPoint) { + $scope.formData.geoPoint.lat = null; + $scope.formData.geoPoint.lon = null; + } + }; + + $scope.onCityChanged = function() { + if ($scope.loading) return; + var hasGeoPoint = $scope.formData.geoPoint && $scope.formData.geoPoint.lat && $scope.formData.geoPoint.lon; + if (!hasGeoPoint) { + return $scope.localizeByAddress(); + } + }; + +} diff --git a/www/plugins/es/js/controllers/profile-controllers.js b/www/plugins/es/js/controllers/profile-controllers.js index 1fb02982b..76b0bce0e 100644 --- a/www/plugins/es/js/controllers/profile-controllers.js +++ b/www/plugins/es/js/controllers/profile-controllers.js @@ -20,26 +20,25 @@ angular.module('cesium.es.profile.controllers', ['cesium.es.services']) .controller('ESViewEditProfileCtrl', ESViewEditProfileController) - .controller('ESAvatarModalCtrl', ESAvatarModalController) ; -function ESViewEditProfileController($scope, $rootScope, $q, $timeout, $state, $focus, $translate, $ionicHistory, - csConfig, UIUtils, esHttp, esProfile, esGeo, ModalUtils, Device) { +function ESViewEditProfileController($scope, $rootScope, $q, $timeout, $state, $focus, $translate, $controller, $ionicHistory, + UIUtils, esHttp, esProfile, ModalUtils, Device) { 'ngInject'; - // The default country used for address localisation - var defaultCountry = csConfig.plugins && csConfig.plugins.es && csConfig.plugins.es.defaultCountry; + // Initialize the super class and extend it. + angular.extend(this, $controller('ESPositionEditCtrl', {$scope: $scope})); - $scope.loading = true; - $scope.dirty = false; - $scope.walletData = null; $scope.formData = { title: null, description: null, socials: [], geoPoint: {} }; + $scope.loading = true; + $scope.dirty = false; + $scope.walletData = null; $scope.avatar = null; $scope.existing = false; $scope.socialData = { @@ -100,7 +99,7 @@ function ESViewEditProfileController($scope, $rootScope, $q, $timeout, $state, $ } }) .catch(function(err) { - + // Silent }); } } @@ -108,7 +107,9 @@ function ESViewEditProfileController($scope, $rootScope, $q, $timeout, $state, $ $scope.load = function(walletData) { $scope.loading = true; // to avoid the call of doSave() - return esProfile.get(walletData.pubkey, {raw: true}) + return esProfile.get(walletData.pubkey, { + raw: true + }) .then(function(profile) { if (profile) { $scope.avatar = esHttp.image.fromAttachment(profile.source.avatar); @@ -336,164 +337,7 @@ function ESViewEditProfileController($scope, $rootScope, $q, $timeout, $state, $ }); }; - $scope.localizeByAddress = function() { - - return UIUtils.loading.show() - .then($scope.searchPositions) - .then(function(res) { - UIUtils.loading.hide(); - - if (!res) return; // no result, or city value just changed - if (res.length == 1) { - return res[0]; - } - - return ModalUtils.show('plugins/es/templates/common/modal_category.html', 'ESCategoryModalCtrl as ctrl', - { - categories : res, - title: 'PROFILE.MODAL_LOCATIONS.TITLE' - }, - {focusFirstInput: true} - ); - }) - .then(function(res) { - if (res && res.lat && res.lon) { - $scope.formData.geoPoint = $scope.formData.geoPoint || {}; - $scope.formData.geoPoint.lat = parseFloat(res.lat); - $scope.formData.geoPoint.lon = parseFloat(res.lon); - } - }) - .catch(UIUtils.onError('PROFILE.ERROR.ADDRESS_LOCATION_FAILED')); - }; - - $scope.searchPositions = function(query) { - - // Build the query - if (!query) { - if (!$scope.formData.city) { - return $q.when(); // nothing to search - } - - var cityPart = $scope.formData.city.split(','); - var city = cityPart[0]; - - var country = cityPart.length > 1 ? cityPart[1].trim() : defaultCountry; - var street = $scope.formData.address ? angular.copy($scope.formData.address.trim()) : undefined; - if (street) { - // Search with AND without street - return $q.all([ - $scope.searchPositions({ - street: street, - city: city, - country: country - }), - $scope.searchPositions({ - city: city, - country: country - }) - ]) - .then(function(res){ - return res[0].concat(res[1]); - }); - } - else { - return $scope.searchPositions({ - city: city, - country: country - }); - } - } - - var queryString = (query.street ? query.street + ', ' : '') + - query.city + - (query.country ? ', ' + query.country : ''); - // Execute the given query - return $q.all([ - $translate('PROFILE.MODAL_LOCATIONS.RESULT_DIVIDER', {address: queryString}), - esGeo.point.searchByAddress(query) - ]) - .then(function(res) { - var dividerText = res[0]; - res = res[1]; - if (!res) return $q.when(); // no result - - // Ask user to choose - var parent = {name: dividerText}; - var hits = res.reduce(function(res, hit){ - if (hit.class == 'waterway') return res; - return res.concat({ - name: hit.display_name, - parent: parent, - lat: hit.lat, - lon: hit.lon - }); - }, [parent]); - - if (hits.length == 1) return $q.when(); // no result (after filtering) - - return hits; - }); - }; - - $scope.localizeMe = function() { - return esGeo.point.current() - .then(function(position) { - if (!position || !position.lat || !position.lon) return; - $scope.formData.geoPoint = $scope.formData.geoPoint || {}; - $scope.formData.geoPoint.lat = parseFloat(position.lat); - $scope.formData.geoPoint.lon = parseFloat(position.lon); - }) - .catch(UIUtils.onError('PROFILE.ERROR.GEO_LOCATION_FAILED')); - }; - - $scope.removeLocalisation = function() { - if ($scope.formData.geoPoint) { - $scope.formData.geoPoint.lat = null; - $scope.formData.geoPoint.lon = null; - } - }; - - $scope.onCityChanged = function() { - if ($scope.loading) return; - var hasGeoPoint = $scope.formData.geoPoint && $scope.formData.geoPoint.lat && $scope.formData.geoPoint.lon; - if (!hasGeoPoint) { - return $scope.localizeByAddress(); - } - }; } -function ESAvatarModalController($scope) { - - $scope.openFileSelector = function() { - var fileInput = angular.element(document.querySelector('.modal-avatar #fileInput')); - if (fileInput && fileInput.length > 0) { - fileInput[0].click(); - } - }; - - $scope.fileChanged = function(e) { - - var files = e.target.files; - var fileReader = new FileReader(); - fileReader.readAsDataURL(files[0]); - - fileReader.onload = function(e) { - $scope.imgSrc = this.result; - $scope.$apply(); - }; - }; - - $scope.doCrop = function() { - $scope.initCrop = true; - }; - - $scope.clear = function() { - $scope.imageCropStep = 1; - delete $scope.imgSrc; - delete $scope.result; - delete $scope.resultBlob; - }; - -} diff --git a/www/plugins/es/js/controllers/registry-controllers.js b/www/plugins/es/js/controllers/registry-controllers.js index 5f9e87abf..fd644d2bf 100644 --- a/www/plugins/es/js/controllers/registry-controllers.js +++ b/www/plugins/es/js/controllers/registry-controllers.js @@ -6,7 +6,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. $stateProvider .state('app.registry_lookup', { - url: "/registry?q&category&location&type&reload", + url: "/page?q&category&location&type&reload", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/lookup.html", @@ -19,7 +19,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. }) .state('app.registry_lookup_lg', { - url: "/registry/lg?q&category&location&type&reload", + url: "/page/lg?q&category&location&type&reload", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/lookup_lg.html", @@ -29,7 +29,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. }) .state('app.view_page', { - url: "/page/:id/:title?refresh", + url: "/page/view/:id/:title?refresh", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/view_record.html", @@ -39,7 +39,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. }) .state('app.view_page_anchor', { - url: "/page/:id/:title/:anchor", + url: "/page/view/:id/:title/:anchor", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/view_record.html", @@ -50,7 +50,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. .state('app.registry_add_record', { cache: false, - url: "/registry/add/:type", + url: "/page/add/:type", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/edit_record.html", @@ -65,7 +65,7 @@ angular.module('cesium.es.registry.controllers', ['cesium.es.services', 'cesium. .state('app.registry_edit_record', { cache: false, - url: "/registry/edit/:id/:title", + url: "/page/edit/:id/:title", views: { 'menuContent': { templateUrl: "plugins/es/templates/registry/edit_record.html", @@ -408,6 +408,10 @@ function ESRegistryRecordViewController($scope, $state, $q, $timeout, $ionicPopo $scope.formData = data.record; $scope.canEdit = csWallet.isUserPubkey($scope.formData.issuer); $scope.issuer = data.issuer; + // avatar + $scope.avatar = $scope.formData.avatar; + $scope.avatarStyle= $scope.formData.avatar && {'background-image':'url("'+$scope.avatar.src+'")'}; + UIUtils.loading.hide(); $scope.loading = false; // Set Motion (only direct children, to exclude .lazy-load children) @@ -438,19 +442,13 @@ function ESRegistryRecordViewController($scope, $state, $q, $timeout, $ionicPopo // Load pictures esRegistry.record.picture.all({id: id}) .then(function(hit) { - var pictures; - if (hit._source.pictures) { - pictures = hit._source.pictures.reduce(function(res, pic) { + + $scope.pictures = hit._source.pictures && hit._source.pictures.reduce(function(res, pic) { return res.concat(esHttp.image.fromAttachment(pic.file)); }, []); - if (pictures.length > 0) { - pictures.splice(0,1); // Remove the avatar - } - } - $scope.pictures = pictures; // Set Motion - if (pictures.length > 0) { + if ($scope.pictures.length > 0) { $scope.motion.show({ selector: '.lazy-load .item.card-gallery, .lazy-load .item', startVelocity: 3000 @@ -550,15 +548,25 @@ function ESRegistryRecordViewController($scope, $state, $q, $timeout, $ionicPopo } -function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, Device, - $ionicHistory, ModalUtils, $focus, esHttp) { +function ESRegistryRecordEditController($scope, $timeout, $state, $q, $ionicHistory, $focus, $translate, $controller, + Device, UIUtils, ModalUtils, esHttp, esRegistry) { 'ngInject'; + // Initialize the super class and extend it. + angular.extend(this, $controller('ESPositionEditCtrl', {$scope: $scope})); + + $scope.formData = { + title: null, + description: null, + socials: [], + geoPoint: {} + }; - $scope.walletData = {}; - $scope.formData = {}; + $scope.loading = true; + $scope.dirty = false; + $scope.walletData = null; $scope.id = null; + $scope.avatar = null; $scope.pictures = []; - $scope.loading = true; $scope.setForm = function(form) { $scope.form = form; @@ -573,11 +581,12 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, } else { if (state.stateParams && state.stateParams.type) { - $scope.formData.type=state.stateParams.type; + $scope.updateView({ + record: { + type: state.stateParams.type + } + }); } - $scope.loading = false; - UIUtils.loading.hide(); - $scope.motion.show(); } // removeIf(device) $focus('registry-record-title'); @@ -585,42 +594,158 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, }); }); + $scope.$on('$stateChangeStart', function (event, next, nextParams, fromState) { + if ($scope.dirty && !$scope.saving) { + + // stop the change state action + event.preventDefault(); + + if (!$scope.loading) { + $scope.loading = true; + return UIUtils.alert.confirm('CONFIRM.SAVE_BEFORE_LEAVE', + 'CONFIRM.SAVE_BEFORE_LEAVE_TITLE', { + cancelText: 'COMMON.BTN_NO', + okText: 'COMMON.BTN_YES_SAVE' + }) + .then(function(confirmSave) { + $scope.loading = false; + if (confirmSave) { + $scope.form.$submitted=true; + return $scope.save(false/*silent*/, true/*haswait debounce*/) + .then(function(saved){ + if (saved) { + $scope.dirty = false; + } + return saved; // change state only if not error + }); + } + else { + $scope.dirty = false; + return true; // ok, change state + } + }) + .then(function(confirmGo) { + if (confirmGo) { + // continue to the order state + $ionicHistory.nextViewOptions({ + historyRoot: true + }); + $state.go(next.name, nextParams); + } + }) + .catch(function(err) { + // Silent + }); + } + } + }); + $scope.load = function(id) { + $scope.loading = true; esRegistry.record.load(id, { raw: true }) .then(function (data) { - $scope.formData = data.record; - $scope.id= data.id; + if (data && data.record) { + $scope.updateView(data); + } + else { + $scope.updateView({record: {}}); + } + }) + .catch(function(err) { + UIUtils.loading.hide(10); + $scope.loading = false; + UIUtils.onError('REGISTRY.ERROR.LOAD_RECORD_FAILED')(err); + }); + }; - $scope.pictures = data.record.pictures || []; - delete data.record.pictures; // remove, as already stored in $scope.pictures + $scope.updateView = function(data) { + $scope.formData = data.record || {}; + $scope.id= data.id; - $scope.loading = false; - UIUtils.loading.hide(); + // avatar + $scope.avatar = $scope.formData.avatar; + if ($scope.avatar) { + $scope.avatarStyle = $scope.avatar && {'background-image':'url("'+$scope.avatar.src+'")'}; + $scope.avatarClass = {}; + } + else { + $scope.avatarStyle = undefined; + $scope.avatarClass = {}; + $scope.avatarClass['cion-page-' + $scope.formData.type] = !$scope.avatar; + } - $scope.motion.show({ - selector: '.animate-ripple .item, .card-gallery', - startVelocity: 3000 - }); - }) - .catch(UIUtils.onError('REGISTRY.ERROR.LOAD_RECORD_FAILED')); + // geo point + $scope.formData.geoPoint = $scope.formData.geoPoint || {}; + + // pictures + $scope.pictures = data.record && data.record.pictures || []; + delete data.record.pictures; // remove, as already stored in $scope.pictures + + $scope.motion.show({ + selector: '.animate-ripple .item, .card-gallery', + startVelocity: 3000 + }); + UIUtils.loading.hide(); + + // Update loading - done with a delay, to avoid trigger onFormDataChanged() + $timeout(function() { + $scope.loading = false; + }, 1000); }; + $scope.onFormDataChanged = function() { + if ($scope.loading) return; + $scope.dirty = true; + }; + $scope.$watch('formData', $scope.onFormDataChanged, true); + + + $scope.needCategory = function() { return $scope.formData.type && ($scope.formData.type=='company' || $scope.formData.type=='shop'); }; - $scope.save = function() { + $scope.save = function(silent, hasWaitDebounce) { $scope.form.$submitted=true; if($scope.saving || // avoid multiple save !$scope.form.$valid || (($scope.formData.type === 'shop' || $scope.formData.type === 'company') && (!$scope.formData.category || !$scope.formData.category.id))) { - return; + return $q.reject(); + } + + if (!hasWaitDebounce) { + console.debug('[ES] [page] Waiting debounce end, before saving...'); + return $timeout(function() { + return $scope.save(silent, true); + }, 650); } + $scope.saving = true; - return UIUtils.loading.show() + console.debug('[ES] [page] Saving record...'); + + var showSuccessToast = function() { + if (!silent) { + // removeIf(no-device) + UIUtils.loading.hide(); + // endRemoveIf(no-device) + + return $translate('REGISTRY.INFO.RECORD_SAVED') + .then(function(message){ + UIUtils.toast.show(message); + }); + } + }; + + var promise = $q.when(); + // removeIf(no-device) + if (!silent) { + promise = UIUtils.loading.show(); + } + // endRemoveIf(no-device) + return promise .then(function(){ var json = $scope.formData; if (!$scope.needCategory()) { @@ -628,35 +753,54 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, } json.time = esHttp.date.now(); - // Resize pictures + // geo point + if (json.geoPoint && json.geoPoint.lat && json.geoPoint.lon) { + json.geoPoint.lat = parseFloat(json.geoPoint.lat); + json.geoPoint.lon = parseFloat(json.geoPoint.lon); + } + else{ + json.geoPoint = null; + } + + // Social url must be unique in socials links - Fix #306: + if (json.socials && json.socials.length) { + json.socials = _.uniq(json.socials, false, function(social) { + return social.url; + }); + } + + // Pictures json.picturesCount = $scope.pictures.length; if (json.picturesCount > 0) { - json.pictures = $scope.pictures.reduce(function(res, pic) { + json.pictures = $scope.pictures.reduce(function (res, pic) { return res.concat({file: esHttp.image.toAttachment(pic)}); }, []); - return UIUtils.image.resizeSrc($scope.pictures[0].src, true) // resize thumbnail + } + else { + json.pictures = []; + } + + // Avatar + if ($scope.avatar && $scope.avatar.src) { + return UIUtils.image.resizeSrc($scope.avatar.src, true) // resize to thumbnail .then(function(imageSrc) { - json.thumbnail = esHttp.image.toAttachment({src: imageSrc}); + json.avatar = esHttp.image.toAttachment({src: imageSrc}); return json; }); } else { - if (json.thumbnail) { - // Workaround to allow content deletion, because of a bug in the ES attachment-mapper: - // get error (in ES node) : MapperParsingException[No content is provided.] - AttachmentMapper.parse(AttachmentMapper.java:471 - json.thumbnail = { - _content: '', - _content_type: '' - }; - } - json.pictures = []; + // Workaround to allow content deletion, because of a bug in the ES attachment-mapper: + // get error (in ES node) : MapperParsingException[No content is provided.] - AttachmentMapper.parse(AttachmentMapper.java:471 + json.avatar = { + _content: '', + _content_type: '' + }; return json; } }) .then(function(json){ // Create if (!$scope.id) { - json.creationTime = esHttp.date.now(); return esRegistry.record.add(json); } // Update @@ -664,8 +808,13 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, }) .then(function(id) { + console.info("[ES] [page] Record successfully saved."); $scope.id = $scope.id || id; $scope.saving = false; + $scope.dirty = false; + + showSuccessToast(); + $ionicHistory.clearCache($ionicHistory.currentView().stateId); // clear current view $ionicHistory.nextViewOptions({historyRoot: true}); return $state.go('app.view_page', {id: $scope.id, refresh: true}); @@ -685,6 +834,26 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, .catch(UIUtils.onError('ERROR.TAKE_PICTURE_FAILED')); }; + + + $scope.rotateAvatar = function(){ + if (!$scope.avatar || !$scope.avatar.src || $scope.rotating) return; + + $scope.rotating = true; + + return UIUtils.image.rotateSrc($scope.avatar.src) + .then(function(imageData){ + $scope.avatar.src = imageData; + $scope.avatarStyle={'background-image':'url("'+imageData+'")'}; + $scope.dirty = true; + $scope.rotating = false; + }) + .catch(function(err) { + console.error(err); + $scope.rotating = false; + }); + }; + $scope.fileChanged = function(event) { UIUtils.loading.show(); return $q(function(resolve, reject) { @@ -715,11 +884,39 @@ function ESRegistryRecordEditController($scope, esRegistry, UIUtils, $state, $q, }; /* -- modals -- */ + $scope.showAvatarModal = function() { + if (Device.camera.enable) { + return Device.camera.getPicture() + .then(function(imageData) { + if (!imageData) return; + $scope.avatar = {src: "data:image/png;base64," + imageData}; + $scope.avatarStyle={'background-image':'url("'+imageData+'")'}; + $scope.dirty = true; + $scope.avatarClass = {}; + }) + .catch(UIUtils.onError('ERROR.TAKE_PICTURE_FAILED')); + } + else { + return ModalUtils.show('plugins/es/templates/user/modal_edit_avatar.html','ESAvatarModalCtrl', + {}) + .then(function(imageData) { + if (!imageData) return; + $scope.avatar = {src: imageData}; + $scope.avatarStyle={'background-image':'url("'+imageData+'")'}; + $scope.dirty = true; + $scope.avatarClass = {}; + }); + } + }; + $scope.showRecordTypeModal = function() { ModalUtils.show('plugins/es/templates/registry/modal_record_type.html') .then(function(type){ if (type) { $scope.formData.type = type; + if (!$scope.avatar) { + $scope.avatarClass['cion-page-' + type] = true; + } } }); }; diff --git a/www/plugins/es/js/services/comment-services.js b/www/plugins/es/js/services/comment-services.js index 7be2621ab..6f98c4505 100644 --- a/www/plugins/es/js/services/comment-services.js +++ b/www/plugins/es/js/services/comment-services.js @@ -168,8 +168,8 @@ angular.module('cesium.es.comment.services', ['ngResource', 'cesium.services', data.result.splice(index, 1); delete data.mapById[comment.id]; // Send deletion request - if (comment.issuer === csWallet.data.pubkey) { - exports.raw.remove(comment.id, csWallet.data.keypair) + if (csWallet.isUserPubkey(comment.issuer)) { + exports.raw.remove(comment.id) .catch(function(err){ console.error(err); throw new Error('MARKET.ERROR.FAILED_REMOVE_COMMENT'); diff --git a/www/plugins/es/js/services/http-services.js b/www/plugins/es/js/services/http-services.js index 9f1fa42c7..4de5bf990 100644 --- a/www/plugins/es/js/services/http-services.js +++ b/www/plugins/es/js/services/http-services.js @@ -282,9 +282,9 @@ angular.module('cesium.es.http.services', ['ngResource', 'ngApi', 'cesium.servic }; } - function removeRecord(index, type, walletData) { + function removeRecord(index, type) { return function(id) { - return (!walletData ? csWallet.auth() : $q.when(walletData)) + return (csWallet.isAuth() ? $q.when(csWallet.data) : csWallet.auth({silent: true, minData: true})) .then(function(walletData) { var obj = { diff --git a/www/plugins/es/js/services/registry-services.js b/www/plugins/es/js/services/registry-services.js index 0e00954cb..630fe31f6 100644 --- a/www/plugins/es/js/services/registry-services.js +++ b/www/plugins/es/js/services/registry-services.js @@ -7,10 +7,7 @@ angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', var fields = { - commons: ["category", "title", "description", "issuer", "time", "address", "city", "thumbnail._content_type", "picturesCount", "type", "socials", "pubkey"], - comment: { - commons: ["issuer", "time", "message"], - } + commons: ["title", "description", "issuer", "time", "address", "city", "creationTime", "avatar._content_type", "picturesCount", "type", "category", "socials", "pubkey"] }; var exports = { @@ -76,7 +73,7 @@ angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', } // thumbnail - record.thumbnail = esHttp.image.fromHit(hit, 'thumbnail'); + record.avatar = esHttp.image.fromHit(hit, 'avatar'); // pictures if (hit._source.pictures && hit._source.pictures.reduce) { @@ -170,9 +167,9 @@ angular.module('cesium.es.registry.services', ['ngResource', 'cesium.services', exports.record = { search: search, load: loadData, - add: esHttp.record.post('/page/record', {tagFields: ['title', 'description']}), + add: esHttp.record.post('/page/record', {tagFields: ['title', 'description'], creationTime: true}), update: esHttp.record.post('/page/record/:id/_update', {tagFields: ['title', 'description']}), - remove: esHttp.record.remove('registry', 'record'), + remove: esHttp.record.remove('page', 'record'), fields: { commons: fields.commons }, diff --git a/www/plugins/es/templates/common/edit_position.html b/www/plugins/es/templates/common/edit_position.html new file mode 100644 index 000000000..04f495c32 --- /dev/null +++ b/www/plugins/es/templates/common/edit_position.html @@ -0,0 +1,102 @@ +<div class="item item-divider" translate>REGISTRY.LOCATION_DIVIDER</div> + +<!-- address --> +<ion-item class="item-input item-floating-label item-button-right"> + <span class="input-label">{{'PROFILE.ADDRESS' | translate}}</span> + <textarea placeholder="{{'PROFILE.ADDRESS_HELP' | translate}}" + ng-model="formData.address" + ng-model-options="{ debounce: 350 }" + rows="4" cols="10"> + </textarea> +</ion-item> + +<!-- city --> +<div class="item item-input item-floating-label"> + <span class="input-label" translate>PROFILE.CITY</span> + <input type="text" placeholder="{{'PROFILE.CITY_HELP'|translate}}" + ng-model="formData.city" + ng-model-options="{ updateOn: 'blur' }" + ng-change="onCityChanged()"> +</div> + +<!-- Position (lat/lon) --> +<div class="row responsive-md responsive-sm no-padding"> + + <!-- lat --> + <div class="col no-padding"> + <label class="item item-input item-floating-label" + ng-class="{'item-input-error': form.$submitted && form.latitude.$invalid}"> + <span class="input-label" translate>PROFILE.LATITUDE</span> + <input class="no-padding-right" + name="latitude" + type="number" placeholder="{{'PROFILE.LATITUDE_HELP'|translate}}" + ng-model="formData.geoPoint.lat" + ng-model-options="{ debounce: 350 }" + ng-change="onFormDataChanged()" + min="-90" max="90"> + </label> + <div class="form-errors" + ng-show="form.$submitted && form.latitude.$error" + ng-messages="form.latitude.$error"> + <div class="form-error" ng-message="min"> + <span translate="ERROR.FIELD_MIN" translate-values="{min: -90}"></span> + </div> + <div class="form-error" ng-message="max"> + <span translate="ERROR.FIELD_MAX" translate-values="{max: 90}"></span> + </div> + </div> + </div> + + <div class="col-10 no-padding hidden-xs"> + + </div> + + <!-- lon --> + <div class="col no-padding"> + <label class="item item-input item-floating-label" + ng-class="{'item-input-error': form.$submitted && form.longitude.$invalid}"> + <span class="input-label" translate>PROFILE.LONGITUDE</span> + <input class="no-padding-right" + name="longitude" + type="number" placeholder="{{'PROFILE.LONGITUDE_HELP'|translate}}" + ng-model="formData.geoPoint.lon" + ng-model-options="{ debounce: 350 }" + ng-change="onFormDataChanged()" + min="-180" max="180"> + </label> + <div class="form-errors" + ng-show="form.$submitted && form.longitude.$error" + ng-messages="form.longitude.$error"> + <div class="form-error" ng-message="min"> + <span translate="ERROR.FIELD_MIN" translate-values="{min: -180}"></span> + </div> + <div class="form-error" ng-message="max"> + <span translate="ERROR.FIELD_MAX" translate-values="{max: 180}"></span> + </div> + </div> + </div> + + <div class="col col-40"> + <div class="row text-center"> + + <a class="col button button-stable button-small-padding icon ion-refresh" + title="{{'PROFILE.BTN_GEOLOC_ADDRESS'|translate}}" + ng-disabled="!formData.city" + ng-click="localizeByAddress()"> + </a> + + <a class="col button button-stable button-small-padding icon ion-android-locate" + title="{{'PROFILE.BTN_GEOLOC_ME'|translate}}" + ng-click="localizeMe()"> + </a> + + <a class="col button button-stable button-small-padding icon ion-close" + title="{{'PROFILE.BTN_REMOVE_GEOLOC'|translate}}" + ng-disabled="!formData.geoPoint || (!formData.geoPoint.lat && !formData.geoPoint.lon)" + ng-click="removeLocalisation()"> + </a> + </div> + </div> +</div> + +<cs-extension-point name="after-position"></cs-extension-point> diff --git a/www/plugins/es/templates/group/edit_group.html b/www/plugins/es/templates/group/edit_group.html index 7b0b08938..0f3563489 100644 --- a/www/plugins/es/templates/group/edit_group.html +++ b/www/plugins/es/templates/group/edit_group.html @@ -85,7 +85,7 @@ </div> <!-- social networks --> - <ng-include src="'plugins/es/templates/common/edit_socials.html'"></ng-include> + <ng-include src="'plugins/es/templates/common/edit_socials.html'" ng-controller="ESSocialsEditCtrl"></ng-include> </div> diff --git a/www/plugins/es/templates/registry/edit_record.html b/www/plugins/es/templates/registry/edit_record.html index e8f1438f7..9660fecc2 100644 --- a/www/plugins/es/templates/registry/edit_record.html +++ b/www/plugins/es/templates/registry/edit_record.html @@ -12,24 +12,44 @@ </ion-nav-buttons> <ion-content scroll="true"> + + <div class="positive-900-bg hero"> + <div class="content"> + <i class="avatar" + ng-class="avatarClass" + ng-style="avatarStyle"> + <button class="button button-positive button-large button-clear flat icon ion-camera visible-xs visible-sm" + style="display: inline-block;" + ng-click="showAvatarModal()"></button> + <button ng-if="avatar.src" + class="button button-positive button-large button-clear flat visible-xs visible-sm" + style="display: inline-block; left: 85px; bottom:15px;" + ng-click="rotateAvatar()"> + <i class="icon-secondary ion-image" style="left: 24px; top: 3px; font-size: 24px;"></i> + <i class="icon-secondary ion-forward" style="left: 26px; top: -13px;"></i> + </button> + <button class="button button-positive button-large button-clear icon ion-camera hidden-xs hidden-sm" + ng-click="showAvatarModal()"></button> + </i> + <h3 class="light"> + <span ng-if="!loading && formData.title">{{formData.title}}</span> + <span ng-if="!loading && !id && !formData.title" translate>REGISTRY.EDIT.TITLE_NEW</span> + </h3> + <h4 class="light"> + <ion-spinner ng-if="loading" icon="android"></ion-spinner> + </h4> + </div> + </div> + <div class="row no-padding"> <div class="col col-20 hidden-xs hidden-sm"> </div> <div class="col"> - <!-- loading --> - <div class="center padding" ng-if="loading"> - <ion-spinner icon="android"></ion-spinner> - </div> <form name="recordForm" novalidate="" ng-submit="save()"> <div class="list {{::motion.ionListClass}}" ng-init="setForm(recordForm)"> - - <div class="item hidden-xs"> - <h1 ng-if="id" ng-bind-html="formData.title"></h1> - <h1 ng-if="!id" translate>REGISTRY.EDIT.TITLE_NEW</h1> - </div> <div class="item" ng-if="id"> <h4 class="gray"> <i class="icon ion-calendar"></i> @@ -94,34 +114,11 @@ <div class="item item-divider" translate>REGISTRY.LOCATION_DIVIDER</div> - <!-- address --> - <div class="item item-floating-label" ng-if="location.enable"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_ADDRESS</span> - <div class="item-input-inset"> - <label class="item-input-wrapper"> - <input type="text" placeholder="{{'REGISTRY.EDIT.RECORD_ADDRESS_HELP'|translate}}" ng-model="formData.address"> - </label> - <button class="button button-small button-positive" ng-click="localize()" ng-if="location.enable"> - <i class="icon ion-android-locate"></i> - </button> - </div> - </div> - <div class="item item-input item-floating-label" ng-if="!location.enable"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_ADDRESS</span> - <textarea placeholder="{{'REGISTRY.EDIT.RECORD_ADDRESS_HELP' | translate}}" - ng-model="formData.address" - ng-model-options="{ debounce: 350 }" - rows="4" cols="10"> - </textarea> - </div> - - <div class="item item-input item-floating-label"> - <span class="input-label" translate>REGISTRY.EDIT.RECORD_CITY</span> - <textarea placeholder="{{'REGISTRY.EDIT.RECORD_CITY_HELP'|translate}}" ng-model="formData.city"></textarea> - </div> + <!-- position --> + <ng-include src="'plugins/es/templates/common/edit_position.html'"></ng-include> <!-- social networks --> - <ng-include src="'plugins/es/templates/common/edit_socials.html'"></ng-include> + <ng-include src="'plugins/es/templates/common/edit_socials.html'" ng-controller="ESSocialsEditCtrl"></ng-include> <div class="item item-divider" translate>REGISTRY.TECHNICAL_DIVIDER</div> diff --git a/www/plugins/es/templates/registry/view_record.html b/www/plugins/es/templates/registry/view_record.html index db62b5dff..a1ef5ddcd 100644 --- a/www/plugins/es/templates/registry/view_record.html +++ b/www/plugins/es/templates/registry/view_record.html @@ -15,8 +15,8 @@ <ion-content scroll="true"> <div class="positive-900-bg hero"> <div class="content" ng-if="!loading"> - <i class="avatar cion-page-{{formData.type}}" ng-if="!formData.thumbnail"></i> - <i class="avatar" style="background-image: url({{::formData.thumbnail.src}})" ng-if="formData.thumbnail"></i> + <i class="avatar cion-page-{{formData.type}}" ng-if="!formData.avatar"></i> + <i class="avatar" ng-style="{{avatarStyle}}" ng-if="formData.avatar"></i> <h3 ng-bind-html="formData.title"></h3> <h4> </h4> </div> diff --git a/www/plugins/es/templates/user/edit_profile.html b/www/plugins/es/templates/user/edit_profile.html index a4524098e..5a49ea3cc 100644 --- a/www/plugins/es/templates/user/edit_profile.html +++ b/www/plugins/es/templates/user/edit_profile.html @@ -92,110 +92,11 @@ </textarea> </ion-item> - <!-- address --> - <ion-item class="item-input item-floating-label item-button-right"> - <span class="input-label">{{'PROFILE.ADDRESS' | translate}}</span> - <textarea placeholder="{{'PROFILE.ADDRESS_HELP' | translate}}" - ng-model="formData.address" - ng-model-options="{ debounce: 350 }" - rows="4" cols="10"> - </textarea> - </ion-item> - - <!-- city --> - <div class="item item-input item-floating-label"> - <span class="input-label" translate>PROFILE.CITY</span> - <input type="text" placeholder="{{'PROFILE.CITY_HELP'|translate}}" - ng-model="formData.city" - ng-model-options="{ updateOn: 'blur' }" - ng-change="onCityChanged()"> - </div> - - <!-- Position (lat/lon) --> - <div class="row responsive-md responsive-sm no-padding"> - - <!-- lat --> - <div class="col no-padding"> - <label class="item item-input item-floating-label" - ng-class="{'item-input-error': form.$submitted && form.latitude.$invalid}"> - <span class="input-label" translate>PROFILE.LATITUDE</span> - <input class="no-padding-right" - name="latitude" - type="number" placeholder="{{'PROFILE.LATITUDE_HELP'|translate}}" - ng-model="formData.geoPoint.lat" - ng-model-options="{ debounce: 350 }" - ng-change="onFormDataChanged()" - min="-90" max="90"> - </label> - <div class="form-errors" - ng-show="form.$submitted && form.latitude.$error" - ng-messages="form.latitude.$error"> - <div class="form-error" ng-message="min"> - <span translate="ERROR.FIELD_MIN" translate-values="{min: -90}"></span> - </div> - <div class="form-error" ng-message="max"> - <span translate="ERROR.FIELD_MAX" translate-values="{max: 90}"></span> - </div> - </div> - </div> - - <div class="col-10 no-padding hidden-xs"> - - </div> - - <!-- lon --> - <div class="col no-padding"> - <label class="item item-input item-floating-label" - ng-class="{'item-input-error': form.$submitted && form.longitude.$invalid}"> - <span class="input-label" translate>PROFILE.LONGITUDE</span> - <input class="no-padding-right" - name="longitude" - type="number" placeholder="{{'PROFILE.LONGITUDE_HELP'|translate}}" - ng-model="formData.geoPoint.lon" - ng-model-options="{ debounce: 350 }" - ng-change="onFormDataChanged()" - min="-180" max="180"> - </label> - <div class="form-errors" - ng-show="form.$submitted && form.longitude.$error" - ng-messages="form.longitude.$error"> - <div class="form-error" ng-message="min"> - <span translate="ERROR.FIELD_MIN" translate-values="{min: -180}"></span> - </div> - <div class="form-error" ng-message="max"> - <span translate="ERROR.FIELD_MAX" translate-values="{max: 180}"></span> - </div> - </div> - </div> - - <div class="col col-40 no-padding"> - <div class="item no-padding text-center"> - <span class="input-label"></span> - - <a class="button button-stable button-small-padding icon ion-refresh" - title="{{'PROFILE.BTN_GEOLOC_ADDRESS'|translate}}" - ng-disabled="!formData.city" - ng-click="localizeByAddress()"> - </a> - - <a class="button button-stable button-small-padding icon ion-android-locate" - title="{{'PROFILE.BTN_GEOLOC_ME'|translate}}" - ng-click="localizeMe()"> - </a> - - <a class="button button-stable button-small-padding icon ion-close" - title="{{'PROFILE.BTN_REMOVE_GEOLOC'|translate}}" - ng-disabled="!formData.geoPoint || (!formData.geoPoint.lat && !formData.geoPoint.lon)" - ng-click="removeLocalisation()"> - </a> - </div> - </div> - </div> - - <cs-extension-point name="after-position"></cs-extension-point> + <!-- position --> + <ng-include src="'plugins/es/templates/common/edit_position.html'" ng-controller="ESPositionEditCtrl"></ng-include> <!-- social networks --> - <ng-include src="'plugins/es/templates/common/edit_socials.html'"></ng-include> + <ng-include src="'plugins/es/templates/common/edit_socials.html'" ng-controller="ESSocialsEditCtrl"></ng-include> <div class="item item-divider"> {{'PROFILE.TECHNICAL_DIVIDER' | translate}} diff --git a/www/plugins/es/templates/user/modal_edit_avatar.html b/www/plugins/es/templates/user/modal_edit_avatar.html index 3c7e84d12..46c9cd0ec 100644 --- a/www/plugins/es/templates/user/modal_edit_avatar.html +++ b/www/plugins/es/templates/user/modal_edit_avatar.html @@ -1,28 +1,27 @@ <ion-modal-view> <ion-header-bar class="bar-positive"> <button class="button button-clear visible-xs visible-sm" ng-click="closeModal()" translate>COMMON.BTN_CANCEL</button> - <h1 class="title" translate>PROFILE.MODAL_AVATAR.TITLE</h1> - - <div class="buttons buttons-right"> - <div class="secondary-buttons"> - <button class="button button-icon button-clear ion-ios-arrow-right visible-xs visible-sm" - ng-if="imageCropStep == 2" - ng-click="doCrop()"> - </button> - <button class="button button-icon button-clear ion-android-done visible-xs visible-sm" - ng-if="imageCropStep == 3" - ng-click="closeModal(result)"> - </button> - </div> - </div> + <h1 class="title" translate>PROFILE.MODAL_AVATAR.TITLE</h1> + <button class="button button-clear icon-right visible-xs" + ng-click="doCrop()" + ng-disabled="formData.imageCropStep == 1" + ng-if="formData.imageCropStep <= 2"> + <span translate>COMMON.BTN_NEXT</span> + <i class="icon ion-ios-arrow-right"></i> + </button> + <button class="button button-clear icon-right visible-xs" + ng-click="closeModal(formData.result)" + ng-if="formData.imageCropStep == 3"> + <i class="icon ion-android-done"></i> + </button> </ion-header-bar> <ion-content class="modal-avatar padding"> - <div ng-show="imageCropStep == 1"> + <div ng-show="formData.imageCropStep == 1"> <p translate>PROFILE.MODAL_AVATAR.SELECT_FILE_HELP</p> <!-- Add picture button --> @@ -37,7 +36,7 @@ style="visibility:hidden; position:absolute;"/> </div> - <div ng-show="imageCropStep == 2"> + <div ng-show="formData.imageCropStep == 2"> <p translate>PROFILE.MODAL_AVATAR.RESIZE_HELP</p> <!-- <image-crop @@ -58,23 +57,23 @@ data-height="100" data-width="100" data-shape="circle" - data-step="imageCropStep" - src="imgSrc" - data-result="result" - data-result-blob="resultBlob" - crop="initCrop" + data-step="formData.imageCropStep" + src="formData.imgSrc" + data-result="formData.result" + data-result-blob="formData.resultBlob" + crop="formData.initCrop" padding="150" - max-size="1024" - ></image-crop> + max-size="1024"> + </image-crop> </div> </div> - <div ng-show="imageCropStep == 3"> + <div ng-show="formData.imageCropStep == 3"> <p translate>PROFILE.MODAL_AVATAR.RESULT_HELP</p> <div class="item card padding hero" style="height: 110px;"> <div class="content"> - <img class="avatar" ng-src="{{result}}" style="height: 88px; width: 88px;"> + <img class="avatar" ng-src="{{formData.result}}" style="height: 88px; width: 88px;"> </div> </div> </div> @@ -85,12 +84,12 @@ COMMON.BTN_CANCEL </button> <button class="button button-calm icon-right ion-chevron-right ink" ng-click="doCrop()" translate - ng-disabled="imageCropStep == 1" - ng-if="imageCropStep <= 2"> + ng-disabled="formData.imageCropStep == 1" + ng-if="formData.imageCropStep <= 2"> COMMON.BTN_NEXT </button> - <button class="button button-positive ink" ng-click="closeModal(result)" translate - ng-if="imageCropStep == 3"> + <button class="button button-positive ink" ng-click="closeModal(formData.result)" translate + ng-if="formData.imageCropStep == 3"> COMMON.BTN_CONTINUE </button> </div> -- GitLab