diff --git a/Gruntfile.js b/Gruntfile.js
index f8d2cdac74..31adcd98ee 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -62,7 +62,7 @@ module.exports = function (grunt) {
'bower_components/ngclipboard/dist/ngclipboard.js',
'bower_components/growl/javascripts/jquery.growl.js',
'bower_components/jquery-validation/dist/jquery.validate.js',
- 'bower_components/jpkleemans-angular-validate/src/angular-validate.js',
+ 'bower_components/waves-angular-validate/src/angular-validate.js',
'src/js/vendor/jquery.modal.js',
@@ -118,6 +118,7 @@ module.exports = function (grunt) {
'src/js/shared/password.strength.directive.js',
'src/js/shared/address.directive.js',
'src/js/shared/decimal.directive.js',
+ 'src/js/shared/focus.directive.js',
'src/js/shared/transaction.loading.service.js',
'src/js/shared/transaction.filter.js',
diff --git a/bower.json b/bower.json
index efb32801b8..a0b994d408 100644
--- a/bower.json
+++ b/bower.json
@@ -23,7 +23,8 @@
"growl": "^1.3.2",
"angular-messages": "^1.5.8",
"angular-validation-match": "^1.9.0",
- "jpkleemans-angular-validate": "^1.1.1"
+ "angular-material": "^1.1.1",
+ "waves-angular-validate": "git@github.com:beregovoy68/angular-validate.git#^1.1.2"
},
"analytics": false
}
diff --git a/src/css/style.css b/src/css/style.css
index 213226958c..e4fd7dd6c7 100644
--- a/src/css/style.css
+++ b/src/css/style.css
@@ -1188,6 +1188,14 @@ span.tabs-radio img.selected {
color: #999999;
}
+.popup-autocomplete {
+ z-index: 160;
+}
+
+.md-virtual-repeat-container.md-autocomplete-suggestions-container {
+ z-index: 160;
+}
+
/* ======================================================================= */
diff --git a/src/js/app.js b/src/js/app.js
index 9404f9fa38..38622ac1fc 100644
--- a/src/js/app.js
+++ b/src/js/app.js
@@ -4,22 +4,92 @@
* @see controllers
* @see services
*/
-var app = angular.module('app',
- [
- 'restangular',
- 'waves.core',
- 'waves.core.services',
-
- 'ngclipboard',
- 'ngMessages',
- 'ngValidate',
- 'ngAnimate',
- 'app.ui',
- 'app.shared',
- 'app.login',
- 'app.navigation',
- 'app.wallet',
- 'app.history',
- 'app.community'
- ]
-);
+
+// mock methods to implement late binding
+var __mockShowError = function(message) {};
+var __mockValidateAddress = function(address) {};
+
+var app = angular.module('app', [
+ 'restangular',
+ 'waves.core',
+ 'waves.core.services',
+
+ 'ngclipboard',
+ 'ngMessages',
+ 'ngAnimate',
+ 'ngMaterial',
+ 'ngValidate',
+ 'app.ui',
+ 'app.shared',
+ 'app.login',
+ 'app.navigation',
+ 'app.wallet',
+ 'app.history',
+ 'app.community'
+]).config(AngularApplicationConfig).run(AngularApplicationRun);
+
+function AngularApplicationConfig($validatorProvider) {
+ $validatorProvider.setDefaults({
+ errorClass: 'wInput-error',
+ onkeyup: false,
+ showErrors : function(errorMap, errorList) {
+ errorList.forEach(function(error) {
+ // can't use notificationService here cos services are not available in config phase
+ __mockShowError(error.message);
+ });
+
+ var i, elements;
+ for (i = 0, elements = this.validElements(); elements[i]; i++) {
+ angular.element(elements[i]).removeClass(this.settings.errorClass);
+ }
+
+ for (i = 0, elements = this.invalidElements(); elements[i]; i++) {
+ angular.element(elements[i]).addClass(this.settings.errorClass);
+ }
+ }
+ });
+ $validatorProvider.addMethod('address', function(value, element) {
+ return this.optional(element) || __mockValidateAddress(value);
+ }, 'Account number must be a sequence of 35 alphanumeric characters with no spaces, ' +
+ 'optionally starting with \'1W\'');
+ $validatorProvider.addMethod('decimal', function(value, element, params) {
+ var maxdigits = angular.isNumber(params) ? params : Currency.WAV.precision;
+
+ var regex = new RegExp('^(?:-?\\d+)?(?:\\.\\d{1,' + maxdigits + '})?$');
+ return this.optional(element) || regex.test(value);
+ }, 'Amount is expected with a dot (.) as a decimal separator with no more than {0} fraction digits');
+ $validatorProvider.addMethod('password', function(value, element) {
+ if (this.optional(element))
+ return true;
+
+ var containsDigits = /[0-9]/.test(value);
+ var containsUppercase = /[A-Z]/.test(value);
+ var containsLowercase = /[a-z]/.test(value);
+
+ return containsDigits && containsUppercase && containsLowercase;
+ }, 'The password is too weak. A good password must contain at least one digit, ' +
+ 'one uppercase and one lowercase letter');
+}
+
+AngularApplicationConfig.$inject = ['$validatorProvider'];
+
+function AngularApplicationRun(rest, coreConstants, notificationService, addressService) {
+ // restangular configuration
+ rest.setDefaultHttpFields({
+ timeout: 10000 // milliseconds
+ });
+ //var url = coreConstants.NODE_ADDRESS;
+ var url = 'http://52.28.66.217:6869';
+ rest.setBaseUrl(url);
+
+ // override mock methods cos in config phase services are not available yet
+ __mockShowError = function (message) {
+ notificationService.error(message);
+ };
+ __mockValidateAddress = function (address) {
+ return addressService.validateDisplayAddress(address);
+ };
+}
+
+AngularApplicationRun.$inject = ['Restangular', 'constants.core', 'notificationService', 'addressService'];
+
diff --git a/src/js/shared/address.directive.js b/src/js/shared/address.directive.js
index 50f68f5fdf..f849c495cf 100644
--- a/src/js/shared/address.directive.js
+++ b/src/js/shared/address.directive.js
@@ -14,7 +14,7 @@
return true;
return addressService.validateDisplayAddress(viewValue);
- }
+ };
}
};
}]);
diff --git a/src/js/shared/decimal.directive.js b/src/js/shared/decimal.directive.js
index 9f4da56c25..f879b7b9ee 100644
--- a/src/js/shared/decimal.directive.js
+++ b/src/js/shared/decimal.directive.js
@@ -23,10 +23,10 @@
return true;
var maxdigits = isFinite(parseInt(digits)) ? digits : 8;
- var regex = new RegExp("^(?:-?\\d+)?(?:\\.\\d{1," + maxdigits + "})?$");
+ var regex = new RegExp('^(?:-?\\d+)?(?:\\.\\d{1,' + maxdigits + '})?$');
return regex.test(viewValue);
- }
+ };
}
};
});
diff --git a/src/js/shared/focus.directive.js b/src/js/shared/focus.directive.js
new file mode 100644
index 0000000000..065be82378
--- /dev/null
+++ b/src/js/shared/focus.directive.js
@@ -0,0 +1,18 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('app.shared')
+ .directive('focusMe', ['$timeout', function WavesFocusDirective($timeout) {
+ return {
+ restrict: 'A',
+ link: function (scope, element, attributes) {
+ scope.$watch(attributes.focusMe, function (newValue) {
+ $timeout(function () {
+ return newValue && element[0].focus();
+ });
+ }, true);
+ }
+ };
+ }]);
+})();
diff --git a/src/js/shared/password.strength.directive.js b/src/js/shared/password.strength.directive.js
index 15a346c562..4d32eefd83 100644
--- a/src/js/shared/password.strength.directive.js
+++ b/src/js/shared/password.strength.directive.js
@@ -18,7 +18,7 @@
var containsLowercase = /[a-z]/.test(viewValue);
return containsDigits && containsUppercase && containsLowercase;
- }
+ };
}
};
});
diff --git a/src/js/shared/shared.dialog.directive.js b/src/js/shared/shared.dialog.directive.js
index 77e827e164..12d5d76b9e 100644
--- a/src/js/shared/shared.dialog.directive.js
+++ b/src/js/shared/shared.dialog.directive.js
@@ -8,6 +8,7 @@
closeable: true,
showButtons: true,
okButtonCaption: 'OK',
+ okButtonEnabled: true,
cancelButtonCaption: 'CANCEL'
};
@@ -58,6 +59,7 @@
dialogOk: '&onDialogOk',
dialogCancel: '&onDialogCancel',
okButtonCaption: '@',
+ okButtonEnabled: '=?',
cancelButtonCaption: '@',
isError: '=?'
},
@@ -66,7 +68,8 @@
'
' +
'' +
'
' +
+ 'title="{{::tooltip}}" ng-click="onOk()" ng-disabled="!okButtonEnabled">' +
+ '{{::okButtonCaption}}' +
'
' +
'