diff --git a/electron-builder.json b/electron-builder.json index 465f4e5564..1e2405d299 100644 --- a/electron-builder.json +++ b/electron-builder.json @@ -1,7 +1,7 @@ { "appId": "com.wavesplatform.client.lite", "copyright": "Waves Platform", - "productName": "Waves Lite Client", + "productName": "Waves Client", "files": "**/*", "asar": true, "compression": "normal", @@ -17,7 +17,7 @@ "deb", "zip" ], - "executableName": "waves-lite-client", + "executableName": "waves-client", "icon": "electron/icons/icon128x128.png" }, "mac": { @@ -36,7 +36,7 @@ "icon": "electron/icons/icon.ico" }, "nsis": { - "artifactName": "waves-lite-client[${env.WAVES_CONFIGURATION}]-setup-${version}.${ext}" + "artifactName": "waves-client[${env.WAVES_CONFIGURATION}]-setup-${version}.${ext}" }, "dmg": { "icon": null, diff --git a/electron/package.json b/electron/package.json index 6e12660c6b..db67d53226 100644 --- a/electron/package.json +++ b/electron/package.json @@ -1,12 +1,12 @@ { - "name": "waves-lite-client", - "version": "1.0.0-beta.10", + "name": "waves-client", + "version": "1.0.0-beta.X", "author": { "name": "Waves Platform", "email": "info@wavesplatform.com", "url": "https://wavesplatform.com" }, - "description": "A lite client for Waves platform", + "description": "The official client application for the Waves platform", "license": "Apache-2.0", "main": "main.js" } diff --git a/package-lock.json b/package-lock.json index 0994019e41..a20df19155 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "waves-client", - "version": "1.0.0-beta.10", + "version": "1.0.0-beta.12", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -39,7 +39,7 @@ "@types/babel-core": { "version": "6.25.2", "resolved": "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.2.tgz", - "integrity": "sha1-UAt/7yg03Oh7MjEaTWehp1etqsc=", + "integrity": "sha512-+Ush/fQHUDIithA5yDJWZiL6KdOiVOs5yuj4qcgvQOCnmJec+RgzkLgxnpgmM6Ear9RXa3aCcwjPiUnStPp1zA==", "dev": true, "requires": { "@types/babel-generator": "6.25.0", @@ -52,7 +52,7 @@ "@types/babel-generator": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.0.tgz", - "integrity": "sha1-glVGmqFHEvDRYIuZaDyr1bQT2Ws=", + "integrity": "sha512-WbrKGSt8SKOxAivCHB1fsIP59EyCCfMHuCYcA6yenjGxnjh0rK3BOSPHR96RdZD6ukgyDwzMF/biQH4llowTDg==", "dev": true, "requires": { "@types/babel-types": "6.25.1" @@ -61,7 +61,7 @@ "@types/babel-template": { "version": "6.25.0", "resolved": "https://registry.npmjs.org/@types/babel-template/-/babel-template-6.25.0.tgz", - "integrity": "sha1-JQXXtVuI+CHZgEi0/fB7OyJWPTA=", + "integrity": "sha512-TtyfVlrprX92xSuKa8D//7vFz5kBJODBw5IQ1hQXehqO+me26vt1fyNxOZyXhUq2a7jRyT72V8p68IyH4NEZNA==", "dev": true, "requires": { "@types/babel-types": "6.25.1", @@ -71,7 +71,7 @@ "@types/babel-traverse": { "version": "6.25.2", "resolved": "https://registry.npmjs.org/@types/babel-traverse/-/babel-traverse-6.25.2.tgz", - "integrity": "sha1-PPrr4xb+xRWpZK27hBR7PIlxup8=", + "integrity": "sha512-SO/YPiHOYApenZJecbw1Psd2lopAQ9Wc9HnFevEvM1mOoNXHglV8mHgVkCQJRIrn6UgWqHE/QfvQ1uG1crNgHA==", "dev": true, "requires": { "@types/babel-types": "6.25.1" @@ -80,13 +80,13 @@ "@types/babel-types": { "version": "6.25.1", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-6.25.1.tgz", - "integrity": "sha1-zo8SakQD4R4bADOkJPEWOK+seIk=", + "integrity": "sha512-7Z6r20+HE0viAFhsW0d/UrC1K2tTlpXzGpNlYm8MmCv8z5PbAacFIshrM/MjlGRa5SBqxu2socpy8FHntwZKng==", "dev": true }, "@types/babylon": { "version": "6.16.2", "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.2.tgz", - "integrity": "sha1-BizmO2k9mvHCRvWu35KLycMFicg=", + "integrity": "sha512-+Jty46mPaWe1VAyZbfvgJM4BAdklLWxrT5tc/RjvCgLrtk6gzRY6AOnoWFv4p6hVxhJshDdr2hGVn56alBp97Q==", "dev": true, "requires": { "@types/babel-types": "6.25.1" @@ -109,7 +109,7 @@ "@types/connect": { "version": "3.4.31", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.31.tgz", - "integrity": "sha1-H5LWsRfswFB2xJ7NAk95duUoutk=", + "integrity": "sha512-OPSxsP6XqA3984KWDUXq/u05Hu8VWa/2rUVlw/aDUOx87BptIep6xb3NdCxCpKLfLdjZcCE5jR+gouTul3gjdA==", "dev": true, "requires": { "@types/node": "8.0.34" @@ -127,7 +127,7 @@ "@types/express-serve-static-core": { "version": "4.0.53", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.0.53.tgz", - "integrity": "sha1-FyOjXRRH8sVeE8hyHqs0SOQvTYI=", + "integrity": "sha512-zaGeOpEYp5G2EhjaUFdVwysDrfEYc6Q6iPhd3Kl4ip30x0tvVv7SuJvY3yzCUSuFlzAG8N5KsyY6BJg93/cn+Q==", "dev": true, "requires": { "@types/node": "8.0.34" @@ -136,7 +136,7 @@ "@types/fs-extra": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-3.0.3.tgz", - "integrity": "sha1-HWbrZw6/ZX5XwP2gFN80DBnYqgw=", + "integrity": "sha512-o2qkg/J2LWK+sr007+KFBBOrxzxpr9kiP0gMFC75gQJXhUn/E3pQA0kSVdxrQ3lf+rOwsRnuH0wnR5MNTotEKg==", "dev": true, "requires": { "@types/node": "8.0.34" @@ -165,7 +165,7 @@ "@types/gulp": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-4.0.4.tgz", - "integrity": "sha1-dT/+Ww3a8MmmAQGzRhQbuA5gLyU=", + "integrity": "sha512-5hGc57snkSvGEkUQ42tcYAQmQrU9E41XQJNglP6FtDg7ou9QGyF1HfPZ5POGnrl7ee7uYq0Om0gh1bAmykxaxA==", "dev": true, "requires": { "@types/chokidar": "1.7.1", @@ -222,7 +222,7 @@ "@types/handlebars": { "version": "4.0.36", "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.36.tgz", - "integrity": "sha1-/1fHf6GrZxO7RGU03cTZeXB6Onk=", + "integrity": "sha512-LjNiTX7TY7wtuC6y3QwC93hKMuqYhgV9A1uXBKNvZtVC8ZvyWAjZkJ5BvT0K7RKqORRYRLMrqCxpw5RgS+MdrQ==", "dev": true }, "@types/html-minifier": { @@ -244,7 +244,7 @@ "@types/jasmine": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.6.0.tgz", - "integrity": "sha1-mXtBondStIUK8mg7xKjYIiwlvQI=", + "integrity": "sha512-1ZZdFvYA5zARDXPj5+VF0bwDZWH/o0QQWJVDc5srdC/DngcCZXskR33eR/4PielGvBjLQpQOd6KiQbmtqVkeZA==", "dev": true }, "@types/jquery": { @@ -268,7 +268,7 @@ "@types/mime": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", - "integrity": "sha1-WnMG42fFObn2VDSZ3o3VGfrDeos=", + "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", "dev": true }, "@types/minimatch": { @@ -291,7 +291,7 @@ "@types/serve-static": { "version": "1.7.32", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.7.32.tgz", - "integrity": "sha1-D2cy5NqwgTdx3Y/I/hSUDzRyi0w=", + "integrity": "sha512-WpI0g7M1FiOmJ/a97Qrjafq2I938tjAZ3hZr9O7sXyA6oUhH3bqUNZIt7r1KZg8TQAKxcvxt6JjQ5XuLfIBFvg==", "dev": true, "requires": { "@types/express-serve-static-core": "4.0.53", @@ -315,7 +315,7 @@ "@types/uglify-js": { "version": "2.6.29", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-2.6.29.tgz", - "integrity": "sha1-UhNH9p4gIB0hj1mRrmbhCHivzxo=", + "integrity": "sha512-BdFLCZW0GTl31AbqXSak8ss/MqEZ3DN2MH9rkAyGoTuzK7ifGUlX+u0nfbWeTsa7IPcZhtn8BlpYBXSV+vqGhQ==", "requires": { "@types/source-map": "0.5.2" } @@ -323,7 +323,7 @@ "@types/undertaker": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.1.2.tgz", - "integrity": "sha1-zw9izcvfYq2fcKTXj4GGmlw0mgk=", + "integrity": "sha512-cfqbNE5SKyXIWKaWdeThRgZewNUX5D1yp4xPnFkuTvr93l6EreBxO9FS3bAluiadarKMBGq6aiFosLZkMsolLw==", "dev": true, "requires": { "@types/undertaker-registry": "1.0.0" @@ -358,7 +358,7 @@ "@uirouter/angularjs": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.8.tgz", - "integrity": "sha1-CedSiIR1L6QHGrHPdDJfEMbW2Mk=", + "integrity": "sha512-GNgCyLmtOryzyBO4o8F+e41wkkLzihEN/6hrClQvmA+vf6zX1yvTaC26bFpNg2CJFUNb+DIv8gY5Id3/F0OvZA==", "requires": { "@uirouter/core": "5.0.10" }, @@ -540,7 +540,7 @@ "ansi-escapes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", - "integrity": "sha1-7D6LTp+AZPwCw6ybZfHCdb2o75I=", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", "dev": true }, "ansi-regex": { @@ -551,7 +551,7 @@ "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", "dev": true, "requires": { "color-convert": "1.9.0" @@ -560,7 +560,7 @@ "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", "dev": true, "requires": { "micromatch": "2.3.11", @@ -594,7 +594,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "array-differ": { @@ -744,7 +744,7 @@ "async": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha1-hDGQ/WtzV6C54clW7d3V7IRitU0=", + "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", "dev": true, "requires": { "lodash": "4.17.4" @@ -771,7 +771,7 @@ "autoprefixer": { "version": "7.1.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.5.tgz", - "integrity": "sha1-1l0UuDx80d17yAHaoAVXrd9aBrI=", + "integrity": "sha512-sMN453qIm8Z+tunzYWW+Y490wWkICHhCYm/VohLjjl+N7ARSFuF5au7E6tr7oEbeeXj8mNjpSw2kxjJaO6YCOw==", "dev": true, "requires": { "browserslist": "2.5.1", @@ -1595,7 +1595,7 @@ "bignumber.js": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", - "integrity": "sha1-228UBnwUC9RmJIFaeRbJLZtsJLE=" + "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" }, "binary-extensions": { "version": "1.10.0", @@ -1635,7 +1635,7 @@ "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", "dev": true }, "body-parser": { @@ -2340,7 +2340,7 @@ "chalk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha1-rFvs8U+iG5nGySynp9fP1bF+dD4=", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", "dev": true, "requires": { "ansi-styles": "3.2.0", @@ -2380,7 +2380,7 @@ "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "dev": true, "requires": { "inherits": "2.0.3", @@ -2390,7 +2390,7 @@ "circular-json": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "clean-css": { @@ -2588,7 +2588,7 @@ "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=" + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" }, "commoner": { "version": "0.10.8", @@ -2756,7 +2756,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "convert-source-map": { @@ -2786,7 +2786,7 @@ "cosmiconfig": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha1-YXPOvVb6wELB9DkO33r2wHx8uJI=", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", "dev": true, "requires": { "is-directory": "0.3.1", @@ -2866,7 +2866,7 @@ "crypto-browserify": { "version": "3.11.1", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", - "integrity": "sha1-lIlF78Z1ekANbl5a9HGU0QBkJ58=", + "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==", "dev": true, "requires": { "browserify-cipher": "1.0.0", @@ -4032,7 +4032,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -4157,7 +4157,7 @@ "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "dev": true, "requires": { "md5.js": "1.3.4", @@ -4265,7 +4265,7 @@ "external-editor": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.5.tgz", - "integrity": "sha1-UsJJo5gbm6GHx8rPW+tQvx2Rprw=", + "integrity": "sha512-Msjo64WT5W+NhOpQXh0nOHm+n0RfU1QUwDnKYvJ8dEJ8zlwLrqXNTv5mSUTJpepf41PDJGyhueTw2vNZW+Fr/w==", "dev": true, "requires": { "iconv-lite": "0.4.18", @@ -4276,7 +4276,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "1.0.2" @@ -5103,7 +5103,8 @@ "jsbn": { "version": "0.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "json-schema": { "version": "0.2.3", @@ -5569,7 +5570,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, "functional-red-black-tree": { @@ -5771,7 +5772,7 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "globby": { @@ -6284,7 +6285,7 @@ "gulp-copy": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gulp-copy/-/gulp-copy-1.0.1.tgz", - "integrity": "sha1-93c724Ab5Mj5EjtXW48zun2x+d8=", + "integrity": "sha512-uhIdHo9SoWkf+pjfjETOMD/6ez10ZItO5/L1bFRfVGH+7lq9zE3TSjkh3WVPuTS9ttPRHA7yW4g1QRE1hPwUOA==", "dev": true, "requires": { "gulp": "3.9.1", @@ -6999,7 +7000,7 @@ "hash.js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha1-NA3tvmKQGHFRweodd3o0SJNd+EY=", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "dev": true, "requires": { "inherits": "2.0.3", @@ -7068,7 +7069,7 @@ "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha1-bWDjSzq7yDEwYsO3mO+NkBoHrzw=" + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" }, "html-minifier": { "version": "3.5.7", @@ -7093,7 +7094,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "uglify-js": { "version": "3.2.1", @@ -7154,12 +7155,12 @@ "i18next": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/i18next/-/i18next-9.1.0.tgz", - "integrity": "sha1-QIAF/iYqmQyNk5RqbeDHe7oRZns=" + "integrity": "sha512-oarlBl8AX+2xSae45aT57y/i0dlhRP+MAYhuV2AMtih4Cv+ICpAApOILxtxi0BKPL95FMDStIH4F0PX/4CwfCQ==" }, "i18next-xhr-backend": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-1.4.3.tgz", - "integrity": "sha1-1y9wU2o79qOJImHd41K8d9cIiGo=" + "integrity": "sha512-l9YfIMl0N17Ka/F1KmzLF97iDC6xl5FtmTG60h/ETAfFwFQnYmmZ6B+oUKdNU4bZzBQR1QYWp58zVvUv95c5LA==" }, "iconv-lite": { "version": "0.4.18", @@ -7169,7 +7170,7 @@ "identity-img": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/identity-img/-/identity-img-1.0.0.tgz", - "integrity": "sha1-vkmdR2GqzWf23qyR26JrqiuXMFk=" + "integrity": "sha512-lOl0WslzXMFChhtnE6XeuSg68QjkfL5A1kNgQMlooo5+FDM6qBGiITlg1jMXHnXYoQ+t+4uPpCdjfjpV/wBwOw==" }, "ieee754": { "version": "1.1.8", @@ -7180,7 +7181,7 @@ "ignore": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", - "integrity": "sha1-xOcVRV9gc6jX5drnLS/J1xZj26Y=", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", "dev": true }, "image-size": { @@ -7249,7 +7250,7 @@ "inquirer": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", "dev": true, "requires": { "ansi-escapes": "3.0.0", @@ -7283,7 +7284,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -7576,7 +7577,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { "isobject": "3.0.1" @@ -7827,7 +7828,7 @@ "jschardet": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz", - "integrity": "sha1-xRn2KfhrOlvtuliojTETCe7Al/k=", + "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==", "dev": true }, "jsesc": { @@ -7951,7 +7952,7 @@ "karma": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/karma/-/karma-1.7.1.tgz", - "integrity": "sha1-hcwI6eCiLXzpzKN8ShvoJPaisa4=", + "integrity": "sha512-k5pBjHDhmkdaUccnC7gE3mBzZjcxyxYsYVaqiL2G5AqlfLyBO5nw2VdNK+O16cveEPd/gIOWULH7gkiYYwVNHg==", "dev": true, "requires": { "bluebird": "3.5.0", @@ -7992,7 +7993,7 @@ "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", "dev": true }, "tmp": { @@ -8009,7 +8010,7 @@ "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", + "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", "dev": true, "requires": { "fs-access": "1.0.1", @@ -8604,7 +8605,7 @@ "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { "pseudomap": "1.0.2", @@ -8741,7 +8742,7 @@ "mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/mime/-/mime-2.0.3.tgz", - "integrity": "sha1-Q1MzeFR0fEjqSYMw3ANPn0u7zAs=", + "integrity": "sha512-TrpAd/vX3xaLPDgVRm6JkZwLR0KHfukMdU2wTEbqMDdCnY6Yo3mE+mjs9YE6oMNw2QRfXVeBEYpmpO94BIqiug==", "dev": true }, "mime-db": { @@ -8994,7 +8995,7 @@ "no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha1-YLgTOWvjmz8SiKTB7V0efSi0ZKw=", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "requires": { "lower-case": "1.1.4" } @@ -9020,7 +9021,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "requires": { "hosted-git-info": "2.5.0", "is-builtin-module": "1.0.0", @@ -9547,7 +9548,7 @@ "pbkdf2": { "version": "3.0.14", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha1-o14TxkeZsGzhUyD0WcIw5o5zut4=", + "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", "dev": true, "requires": { "create-hash": "1.1.3", @@ -9612,7 +9613,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "postcss": { @@ -9703,7 +9704,7 @@ "postcss-reporter": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-5.0.0.tgz", - "integrity": "sha1-oUF3/RNCgp0pFlPyeG79ZxEDMsM=", + "integrity": "sha512-rBkDbaHAu5uywbCR2XE8a25tats3xSOsGNx6mppK6Q9kSFGKc/FyAzfci+fWM2l+K402p1D0pNcfDGxeje5IKg==", "dev": true, "requires": { "chalk": "2.1.0", @@ -9715,7 +9716,7 @@ "log-symbols": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz", - "integrity": "sha1-81+mDieIMrU43E3dy7R4pF0+O+Y=", + "integrity": "sha512-zLeLrzMA1A2vRF1e/0Mo+LNINzi6jzBylHj5WqvQ/WK/5WCZt8si9SyN4p9llr/HRYvVR1AoXHRHl4WTHyQAzQ==", "dev": true, "requires": { "chalk": "2.1.0" @@ -9799,7 +9800,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { "asap": "2.0.6" } @@ -9850,7 +9851,7 @@ "qrcode-reader": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/qrcode-reader/-/qrcode-reader-1.0.3.tgz", - "integrity": "sha1-QphaxHUcE04FYTLiUJcNaXldE4w=" + "integrity": "sha512-J1UTJS2vGxJdVPXH1KqFAu/nVMaBJsRLVYus1oDnKKcEVUtktUZDGNwmVTYriEgMz0VCM+uPbBX7136VnuRCEQ==" }, "qs": { "version": "6.4.0", @@ -9873,7 +9874,7 @@ "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { "is-number": "3.0.0", @@ -9914,7 +9915,7 @@ "randombytes": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", - "integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=", + "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", "dev": true, "requires": { "safe-buffer": "5.1.1" @@ -10392,7 +10393,7 @@ "resolve": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha1-p1vgHFPaJdk0qY69DkxKcxL5KoY=", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", "dev": true, "requires": { "path-parse": "1.0.5" @@ -10480,7 +10481,7 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM=", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", "dev": true }, "sanitize-filename": { @@ -10501,7 +10502,7 @@ "semver": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha1-4FnAnYVx8FQII3M0M1BdOi8AsY4=" + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" }, "semver-diff": { "version": "2.1.0", @@ -10515,7 +10516,7 @@ "send": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", - "integrity": "sha1-pw4coh0TgsEdDZ9iMd6ygQgNerM=", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", "dev": true, "requires": { "debug": "2.6.9", @@ -10545,7 +10546,7 @@ "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha1-Eh+evEnjdm8xGnbh+hyAA8SwOqY=", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", "dev": true } } @@ -10559,7 +10560,7 @@ "serve-static": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", - "integrity": "sha1-TFfVNASnYdjy58HooYpH2/J4pxk=", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", "dev": true, "requires": { "encodeurl": "1.0.1", @@ -10672,7 +10673,7 @@ "slice-ansi": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0" @@ -11043,7 +11044,7 @@ "stream-http": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", - "integrity": "sha1-QKBQ7I3DtTsz2ZCUFcAsC/Gr+60=", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", "dev": true, "requires": { "builtin-status-codes": "3.0.0", @@ -11240,7 +11241,7 @@ "table": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", "dev": true, "requires": { "ajv": "5.2.3", @@ -11278,7 +11279,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -11440,7 +11441,7 @@ "ts-api-validator": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ts-api-validator/-/ts-api-validator-2.0.0.tgz", - "integrity": "sha1-Au99P+TGvKQlE9yEJDYUuE8yPU4=", + "integrity": "sha512-VovTPe5am/TP6doPConDwTWeWcxF9D04OmagSTaKpOTfvHfRe8rxg0zktyhZMAuo2/EUV6HpgAafVVYf6Z1HUQ==", "requires": { "dts-gen": "0.5.6", "dts-generator": "2.1.0", @@ -11450,14 +11451,14 @@ "ts-utils": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/ts-utils/-/ts-utils-4.5.0.tgz", - "integrity": "sha1-vjz94AN7KfJR/R/EqiEilNg8dlY=" + "integrity": "sha512-nLchzdDOiZ93CxZCsY6Od9q0FwFJivRD0qLSL/au6qjoCE3iBdLr5GnvMENOYdS7Z2ThUBHjq+D1UiMq0aYqng==" } } }, "ts-utils": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/ts-utils/-/ts-utils-6.0.0.tgz", - "integrity": "sha1-b3O1o1oBADD7w4GXTT5w8EcDMkc=" + "integrity": "sha512-4LQHT6Nb2Er942WprkOtrAeYpFW6UZZUfq6meq8wA3jNHcht/MJi4YcGfVqXtK6muUHWA5bPE/o33jnzbS7Mgg==" }, "tty-browserify": { "version": "0.0.0", @@ -11509,7 +11510,7 @@ "typescript": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", - "integrity": "sha1-3z3Nw48764ANS8MiZGsEo/bKfw0=" + "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==" }, "ua-parser-js": { "version": "0.7.14", @@ -11519,7 +11520,7 @@ "uglify-es": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.1.3.tgz", - "integrity": "sha1-oh7rFJyxIKH4MCVjaJ4ZSWVQeAs=", + "integrity": "sha512-Nuo5gkv/Q6PmLa+Ui2LvK+87YdMAcuXfRIWF0uVfkHVSfpT3Ue0euCSu4t0b8xv4Bt05lmXUT8bLI9OmnyPj8A==", "dev": true, "requires": { "commander": "2.11.0", @@ -11701,7 +11702,7 @@ "uuid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", "dev": true }, "v8flags": { @@ -11873,7 +11874,7 @@ "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { "isexe": "2.0.0" @@ -11943,7 +11944,7 @@ "worker-wrapper": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/worker-wrapper/-/worker-wrapper-1.2.2.tgz", - "integrity": "sha1-jYSssjCBFSGaJy94ele0E9g4MEM=" + "integrity": "sha512-rXz1Ct+n1KFq5X24LPwGP/qMYyQiVXaWgaOsuLvoBpQ4H5IrIvSTsR7JCUcLGbDxfRcjh537tDhEw7AwzsIEEA==" }, "wrap-ansi": { "version": "2.1.0", diff --git a/package.json b/package.json index 718201f492..94cc3a58be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "waves-client", - "version": "1.0.0-beta.11", + "version": "1.0.0-beta.12", "description": "The official client application for the Waves platform", "private": true, "repository": { diff --git a/src/index.html b/src/index.html index 9a8f657f5e..1fdce8ee6f 100644 --- a/src/index.html +++ b/src/index.html @@ -256,6 +256,7 @@ modules: [], minAliasLength: 4, maxAliasLength: 30, + maxAddressLength: 45, getLocaleData: function () { return WavesApp.localize[i18next.language]; }, @@ -386,6 +387,7 @@ * @property {Object} localize * @property {number} minAliasLength * @property {number} maxAliasLength + * @property {number} maxAddressLength * @property {object} network * @property {string} network.code * @property {string} network.node diff --git a/src/modules/app/directives/i18n/i18n.js b/src/modules/app/directives/i18n/i18n.js index a5095c2f61..4980a5ca3e 100644 --- a/src/modules/app/directives/i18n/i18n.js +++ b/src/modules/app/directives/i18n/i18n.js @@ -71,6 +71,7 @@ } }); } + return literal; } diff --git a/src/modules/app/initialize/AppConfig.js b/src/modules/app/initialize/AppConfig.js index 55500a6c45..4d0eddc6c3 100644 --- a/src/modules/app/initialize/AppConfig.js +++ b/src/modules/app/initialize/AppConfig.js @@ -54,9 +54,13 @@ format: function (value, format) { switch (format) { case 'money': - return value.getTokens().toFixed(); + return value && value.getTokens().toFixed() || ''; case 'money-currency': - return `${value.getTokens().toFixed()} ${value.asset.displayName}`; + if (value) { + return `${value.getTokens().toFixed()} ${value.asset.displayName}`; + } else { + return ''; + } case 'BigNumber': return value && value.toFixed() || ''; default: diff --git a/src/modules/app/less/app.less b/src/modules/app/less/app.less index c23d433548..74ba7a7a5f 100644 --- a/src/modules/app/less/app.less +++ b/src/modules/app/less/app.less @@ -87,6 +87,10 @@ md-input-container { width: 100%; } +.relative { + position: relative; +} + w-scroll-box { display: flex; flex-direction: column; diff --git a/src/modules/app/services/waves/node/content/Aliases.js b/src/modules/app/services/waves/node/content/Aliases.js index 75b74bc07e..9166e8eb2f 100644 --- a/src/modules/app/services/waves/node/content/Aliases.js +++ b/src/modules/app/services/waves/node/content/Aliases.js @@ -13,6 +13,11 @@ class Aliases extends BaseNodeComponent { + constructor() { + super(); + this.aliases = []; + } + /** * Get address by alias * @param {string} alias @@ -24,11 +29,10 @@ /** * Get alias list by user - * @return {Promise} + * @return {string[]} */ getAliasList() { - return Waves.API.Node.v2.addresses.aliasList(user.address) - .then((list) => list.sort(utils.comparators.asc)); + return this.aliases; } /** diff --git a/src/modules/app/services/waves/node/content/Assets.js b/src/modules/app/services/waves/node/content/Assets.js index 57a7c029a4..204a531ea8 100644 --- a/src/modules/app/services/waves/node/content/Assets.js +++ b/src/modules/app/services/waves/node/content/Assets.js @@ -113,17 +113,14 @@ * @return {Promise<{id: string}>} */ transfer({ amount, fee, recipient, attachment, keyPair }) { - const address = recipient <= WavesApp.maxAliasLength ? - aliases.getAddress(recipient) : Promise.resolve(recipient); - - return Promise.all([address, this.getFee('transfer', fee)]) - .then(([address, fee]) => { + return this.getFee('transfer', fee) + .then((fee) => { return Waves.API.Node.v1.assets.transfer({ amount: amount.toCoins(), assetId: amount.asset.id, fee: fee.toCoins(), feeAssetId: fee.asset.id, - recipient: address, + recipient, attachment }, keyPair) .then(this._pipeTransaction([amount, fee])); @@ -180,8 +177,7 @@ _getBalanceOrders() { return matcher.getOrders() .then((orders) => orders.filter(Assets._filterOrders)) - .then((orders) => orders.map(Assets._remapOrders)) - .then(Promise.all.bind(Promise)); + .then((orders) => orders.map(Assets._remapOrders)); } /** @@ -229,10 +225,10 @@ static _remapOrders(order) { switch (order.type) { case 'sell': - return Promise.resolve(order.amount.sub(order.filled)); + return order.amount.sub(order.filled); case 'buy': const tokens = order.amount.sub(order.filled).getTokens().mul(order.price.getTokens()); - return Waves.Money.fromTokens(tokens, order.price.asset.id); + return order.price.cloneWithTokens(tokens); } } @@ -253,14 +249,16 @@ * @private */ static _remapBalance([wavesDetails, moneyList, orderMoneyList]) { - const orderMoneyHash = Assets._getMoneyHashFromMoneyList(orderMoneyList); - const eventsMoneyHash = Assets._getMoneyHashFromMoneyList(eventManager.getReservedMoneyList()); + const orderMoneyHash = utils.groupMoney(orderMoneyList); + const eventsMoneyHash = utils.groupMoney(eventManager.getReservedMoneyList()); const wavesNodeRegular = wavesDetails.wavesBalance.regular; const wavesNodeAvailable = wavesDetails.wavesBalance.available; const wavesTx = eventsMoneyHash[WavesApp.defaultAssets.WAVES] || wavesNodeRegular.cloneWithCoins('0'); const wavesOrder = orderMoneyHash[WavesApp.defaultAssets.WAVES] || wavesNodeRegular.cloneWithCoins('0'); + aliases.aliases = wavesDetails.aliases; + return [{ asset: wavesNodeRegular.asset, regular: Assets._getMoneySub(wavesNodeRegular, wavesTx), @@ -311,22 +309,6 @@ } } - /** - * @param {Money[]} orderMoneyList - * @return {object} - * @private - */ - static _getMoneyHashFromMoneyList(orderMoneyList) { - return orderMoneyList.reduce((hash, orderMoney) => { - if (!hash[orderMoney.asset.id]) { - hash[orderMoney.asset.id] = orderMoney; - } else { - hash[orderMoney.asset.id] = hash[orderMoney.asset.id].add(orderMoney); - } - return hash; - }, Object.create(null)); - } - } return new Assets(); diff --git a/src/modules/app/services/waves/node/content/Transactions.js b/src/modules/app/services/waves/node/content/Transactions.js index 53c8ee24fc..447d512225 100644 --- a/src/modules/app/services/waves/node/content/Transactions.js +++ b/src/modules/app/services/waves/node/content/Transactions.js @@ -36,11 +36,8 @@ * @return {Promise} */ get(id) { - return Promise.all([ - aliases.getAliasList(), - Waves.API.Node.v2.transactions.get(id) - ]).then(([aliases, tx]) => { - const pipe = this._pipeTransaction(false, aliases); + return Waves.API.Node.v2.transactions.get(id).then((tx) => { + const pipe = this._pipeTransaction(false); return pipe(tx); }); } @@ -51,11 +48,8 @@ * @return {Promise} */ getUtx(id) { - return Promise.all([ - aliases.getAliasList(), - Waves.API.Node.v2.transactions.utxGet(id) - ]).then(([aliases, tx]) => { - const pipe = this._pipeTransaction(false, aliases); + return Waves.API.Node.v2.transactions.utxGet(id).then((tx) => { + const pipe = this._pipeTransaction(false); return pipe(tx); }); } @@ -75,12 +69,8 @@ * @return {Promise} */ list(limit = 0) { - return Promise.all([ - aliases.getAliasList(), - Waves.API.Node.v2.addresses.transactions(user.address, { limit }) - ]).then(([aliases, txList = []]) => { - return txList.map(this._pipeTransaction(false, aliases)); - }); + return Waves.API.Node.v2.addresses.transactions(user.address, { limit }) + .then((txList = []) => txList.map(this._pipeTransaction(false))); } /** @@ -88,12 +78,8 @@ * @return {Promise} */ listUtx() { - return Promise.all([ - aliases.getAliasList(), - Waves.API.Node.v2.addresses.utxTransactions(user.address) - ]).then(([aliases, list = []]) => { - return list.map(this._pipeTransaction(true, aliases)); - }); + return Waves.API.Node.v2.addresses.utxTransactions(user.address) + .then((list = []) => list.map(this._pipeTransaction(true))); } /** @@ -117,13 +103,11 @@ } createTransaction(transactionType, txData) { - return aliases.getAliasList().then((aliasList) => { - return this._pipeTransaction(false, aliasList)({ - transactionType, - sender: user.address, - timestamp: Date.now(), - ...txData - }); + return this._pipeTransaction(false)({ + transactionType, + sender: user.address, + timestamp: Date.now(), + ...txData }); } @@ -133,7 +117,9 @@ * @return {function(*=)} * @private */ - _pipeTransaction(isUTX, aliasList) { + _pipeTransaction(isUTX) { + const aliasList = aliases.getAliasList(); + return (tx) => { tx.timestamp = new Date(tx.timestamp); tx.isUTX = isUTX; diff --git a/src/modules/dex/directives/createOrder/CreateOrder.js b/src/modules/dex/directives/createOrder/CreateOrder.js index 5477645827..d8b7a86407 100644 --- a/src/modules/dex/directives/createOrder/CreateOrder.js +++ b/src/modules/dex/directives/createOrder/CreateOrder.js @@ -49,7 +49,7 @@ * Has price balance for buy amount * @type {boolean} */ - this.cantByOrder = false; + this.canByOrder = true; /** * Amount asset balance * @type {Money} @@ -75,14 +75,22 @@ * @private */ this._assetIdPair = null; + /** + * @type {Money} + */ + this.amount = null; + /** + * @type {Money} + */ + this.price = null; Waves.Money.fromTokens('0.003', WavesApp.defaultAssets.WAVES).then((money) => { this.fee = money; }); this.receive(dexDataService.chooseOrderBook, ({ type, price, amount }) => { - this.amount = new BigNumber(amount); - this.price = new BigNumber(price); + this.amount = this.amountBalance.cloneWithTokens(amount); + this.price = this.priceBalance.cloneWithTokens(price); this.expand(type); $scope.$apply(); }); @@ -118,10 +126,10 @@ this.maxAmountBalance = CreateOrder._getMaxAmountBalance(this.type, this.amountBalance, this.fee); switch (type) { case 'sell': - this.price = new BigNumber(this.bid.price); + this.price = this.priceBalance.cloneWithTokens(this.bid.price); break; case 'buy': - this.price = new BigNumber(this.ask.price); + this.price = this.priceBalance.cloneWithTokens(this.ask.price); break; default: throw new Error('Wrong type'); @@ -134,24 +142,24 @@ setMaxAmount() { if (this.amountBalance.asset.id === this.fee.asset.id) { - this.amount = this.amountBalance.sub(this.fee).getTokens() - .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR); + this.amount = this.amountBalance.cloneWithTokens(this.amountBalance.sub(this.fee).getTokens() + .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR)); } else { - this.amount = this.amountBalance.getTokens() - .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR); + this.amount = this.amountBalance.cloneWithTokens(this.amountBalance.getTokens() + .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR)); } } setMaxPrice() { if (this.priceBalance.asset.id === this.fee.asset.id) { - this.amount = this.priceBalance.sub(this.fee) + this.amount = this.amountBalance.cloneWithTokens(this.priceBalance.sub(this.fee) .getTokens() - .div(this.price) - .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR); + .div(this.price.getTokens()) + .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR)); } else { - this.amount = this.priceBalance.getTokens() - .div(this.price) - .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR); + this.amount = this.amountBalance.cloneWithTokens(this.priceBalance.getTokens() + .div(this.price.getTokens()) + .round(this.amountBalance.asset.precision, BigNumber.ROUND_FLOOR)); } } @@ -164,11 +172,9 @@ user.getSeed() .then((seed) => { return Waves.AssetPair.get(this._assetIdPair.amount, this._assetIdPair.price).then((pair) => { - return Promise.all([ - Waves.Money.fromTokens(this.amount.toFixed(), this.amountBalance.asset.id), - Waves.OrderPrice.fromTokens(this.price.toFixed(), pair) - ]); - }).then(([amount, price]) => { + return Waves.OrderPrice.fromTokens(this.price.getTokens(), pair); + }).then((price) => { + const amount = this.amount; this.amount = null; form.$setUntouched(); $scope.$apply(); @@ -232,15 +238,17 @@ } if (!this.price || !this.amount) { - this.totalPrice = new BigNumber(0); + this.totalPrice = this.priceBalance.cloneWithTokens('0'); } else { - this.totalPrice = this.price.mul(this.amount); + this.totalPrice = this.priceBalance.cloneWithTokens( + this.price.getTokens().mul(this.amount.getTokens()) + ); } if (this.type === 'buy') { - this.cantByOrder = this.priceBalance.getTokens().lte(this.totalPrice); + this.canByOrder = !this.priceBalance.lte(this.totalPrice); } else { - this.cantByOrder = false; + this.canByOrder = true; } } diff --git a/src/modules/dex/directives/createOrder/createOrder.html b/src/modules/dex/directives/createOrder/createOrder.html index 3c94c36c1b..41dcc10e33 100644 --- a/src/modules/dex/directives/createOrder/createOrder.html +++ b/src/modules/dex/directives/createOrder/createOrder.html @@ -64,9 +64,11 @@
@@ -78,21 +80,24 @@ directives.createOrder.errors.required - + + directives.createOrder.errors.required + + directives.createOrder.errors.precision - + directives.createOrder.errors.balance -
+ directives.createOrder.errors.balance -
+
@@ -103,8 +108,9 @@
@@ -112,11 +118,14 @@
{{$ctrl.priceDisplayName}}
- + directives.createOrder.errors.precision + + directives.createOrder.errors.required + directives.createOrder.errors.required @@ -132,8 +141,7 @@
Fee 0.003 WAVES
- - directives.createOrder.placeSellOrder diff --git a/src/modules/tokens/controllers/TokensCtrl.js b/src/modules/tokens/controllers/TokensCtrl.js index bdadee4a91..edb42dd1ec 100644 --- a/src/modules/tokens/controllers/TokensCtrl.js +++ b/src/modules/tokens/controllers/TokensCtrl.js @@ -105,7 +105,7 @@ * @private */ _onChangePrecision({ value }) { - if (value) { + if (value && value.lte(8)) { this.maxCoinsCount = MAX_OF_COINS_COUNT.div(Math.pow(10, Number(value))); } } @@ -128,6 +128,7 @@ this.precision = null; this.maxCoinsCount = null; + this.createForm.$setPristine(); this.createForm.$setUntouched(); } diff --git a/src/modules/tokens/locales/en.json b/src/modules/tokens/locales/en.json index b6f6861430..ea6d57ca2d 100644 --- a/src/modules/tokens/locales/en.json +++ b/src/modules/tokens/locales/en.json @@ -8,13 +8,23 @@ "fee": "Fee 1 WAVES", "create": "Generate", "help": { - "name": "Please use only Latin letters", - "precision": "This field defines the number of decimal signs for your token" + "name": "Please use only Latin letters" + }, + "helpIcon": { + "totalTokens": { + "headline": "This field defines the total tokens supply that your asset will contain.", + "reissuable": "Reissuability allows for additional tokens creation that will be added to the total token supply of asset.", + "notReissuable": "A Non Reissuability asset will be permanently limited to the total token supply defined on this process. " + }, + "demicals": "This field defines the number of decimals that you asset token will be divided in." }, "validators": { - "nameLen": "An asset name must be at least 4-16 characters’ long", + "byte": { + "lte": "Asset name must be between 4 and 16 bytes long", + "gte": "Asset name must be between 4 and 16 bytes long" + }, "required": "This field must be filled", - "descriptionLen": "Entered description is too large", + "descriptionLen": "The description is too long. It must be no more than 1,000 bytes.", "minValuePrecision": "Invalid number. Enter number from 0 to 8", "maxValuePrecision": "Invalid number. Enter number from 0 to 8", "maxValueCount": "Entered number is too large", diff --git a/src/modules/tokens/locales/ko.json b/src/modules/tokens/locales/ko.json index 7395e2cab4..f9155f5569 100644 --- a/src/modules/tokens/locales/ko.json +++ b/src/modules/tokens/locales/ko.json @@ -8,8 +8,15 @@ "fee": "수수료 1 WAVES", "create": "발행", "help": { - "name": "라틴 문자만 가능합니다.", - "precision": "자산 토큰이 분리될 소수 자릿수를 정하는 항목입니다." + "name": "라틴 문자만 가능합니다." + }, + "helpIcon": { + "totalTokens": { + "headline": "This field defines the total tokens supply that your asset will contain.", + "reissuable": "Reissuability allows for additional tokens creation that will be added to the total token supply of asset.", + "notReissuable": "A Non Reissuability asset will be permanently limited to the total token supply defined on this process. " + }, + "demicals": "자산 토큰이 분리될 소수 자릿수를 정하는 항목입니다." }, "validators": { "nameLen": "자산의 이름은 4-16자 이상이어야 합니다.", diff --git a/src/modules/tokens/locales/ru.json b/src/modules/tokens/locales/ru.json index d1726c4e26..60c07cab08 100644 --- a/src/modules/tokens/locales/ru.json +++ b/src/modules/tokens/locales/ru.json @@ -8,13 +8,23 @@ "fee": "Комиссия 1 WAVES", "create": "Выпустить", "help": { - "name": "Пожалуйста, используйте только латинские буквы", - "precision": "В этом поле укажите, сколько знаков после запятой будет у токена" + "name": "Пожалуйста, используйте только латинские буквы" + }, + "helpIcon": { + "totalTokens": { + "headline": "Количество выпускаемых токенов.", + "reissuable": "Перевыпускаемый тип позволяет при необходимости увеличить количество токенов.", + "notReissuable": "Количество токенов неперевыпускаемого типа не может быть изменено в будущем. " + }, + "demicals": "Это поле определяет, сколько знаков после запятой будет у создаваемого токена." }, "validators": { - "nameLen": "Имя токена должно содержать от 4 до 16 символов", + "byte": { + "lte": "Название токена должно занимать не менее 4 и не более 16 байт.", + "gte": "Название токена должно занимать не менее 4 и не более 16 байт." + }, "required": "Это поле должно быть заполнено", - "descriptionLen": "Описание слишком длинное", + "descriptionLen": "Описание слишком большое. Текст не должен занимать более 1000 байт.", "minValuePrecision": "Неверное число, введите число от 0 до 8", "maxValuePrecision": "Неверное число, введите число от 0 до 8", "maxValueCount": "Число токенов слишком велико", diff --git a/src/modules/tokens/templates/tokens.html b/src/modules/tokens/templates/tokens.html index 7d6f6f7ae3..216edb3aeb 100644 --- a/src/modules/tokens/templates/tokens.html +++ b/src/modules/tokens/templates/tokens.html @@ -12,19 +12,20 @@ - - validators.nameLen - - - validators.nameLen - validators.required + + validators.byte.lte + + + validators.byte.gte + @@ -35,33 +36,50 @@ name="description" ng-model="$ctrl.description" placeholder="placeholders.description" - maxlength="1000" + w-validate + w-validator-byte-lte="1000" w-i18n-attr="placeholder"> - + + validators.descriptionLen
-
+
+ count + +
+ helpIcon.totalTokens.headline +
+
+
+
+
- +
- + - +
@@ -69,10 +87,10 @@ validators.required - + validators.minValueCount - + validators.maxValueCount @@ -82,32 +100,39 @@
-
+
precision -
+ +
+ helpIcon.demicals +
+
- + + validators.minValuePrecision - + validators.maxValuePrecision validators.required + + validators.required +
@@ -122,7 +147,8 @@ {{$ctrl.name}}
-
diff --git a/src/modules/ui/directives/assetLogo/AssetLogo.js b/src/modules/ui/directives/assetLogo/AssetLogo.js index e21f7fa401..6a5ad0af9a 100644 --- a/src/modules/ui/directives/assetLogo/AssetLogo.js +++ b/src/modules/ui/directives/assetLogo/AssetLogo.js @@ -15,32 +15,32 @@ }; const COLORS_MAP = { - 'A': '#39a12c', - 'B': '#6a737b', - 'C': '#e49616', - 'D': '#008ca7', - 'E': '#ff5b38', - 'F': '#ff6a00', - 'G': '#c74124', - 'H': '#00a78e', - 'I': '#b01e53', - 'J': '#e0c61b', - 'K': '#5a81ea', - 'L': '#72b7d2', - 'M': '#a5b5c3', - 'N': '#81c926', - 'O': '#86a3bd', - 'P': '#c1d82f', - 'Q': '#5c84a8', - 'R': '#267e1b', - 'S': '#fbb034', - 'T': '#ff846a', - 'U': '#47c1ff', - 'V': '#00a0af', - 'W': '#85d7c6', - 'X': '#8a7967', - 'Y': '#26c1c9', - 'Z': '#72d28b' + A: '#39a12c', + B: '#6a737b', + C: '#e49616', + D: '#008ca7', + E: '#ff5b38', + F: '#ff6a00', + G: '#c74124', + H: '#00a78e', + I: '#b01e53', + J: '#e0c61b', + K: '#5a81ea', + L: '#72b7d2', + M: '#a5b5c3', + N: '#81c926', + O: '#86a3bd', + P: '#c1d82f', + Q: '#5c84a8', + R: '#267e1b', + S: '#fbb034', + T: '#ff846a', + U: '#47c1ff', + V: '#00a0af', + W: '#85d7c6', + X: '#8a7967', + Y: '#26c1c9', + Z: '#72d28b' }; const DEFAULT_COLOR = '#96bca0'; diff --git a/src/modules/ui/directives/balanceInput/BalanceInput.js b/src/modules/ui/directives/balanceInput/BalanceInput.js index 09088dc3e0..67aa8cf105 100644 --- a/src/modules/ui/directives/balanceInput/BalanceInput.js +++ b/src/modules/ui/directives/balanceInput/BalanceInput.js @@ -20,7 +20,11 @@ */ this.name = null; /** - * @type {BigNumber} + * @type {boolean} + */ + this.focus = false; + /** + * @type {Money} */ this.amount = null; /** @@ -46,6 +50,13 @@ this.observe('assetId', this._onChangeAssetId); this.observe(['fee', 'maxBalance'], this._setMaxBalance); + this.observe('focus', () => { + if (this.focus) { + this.onFocus(); + } else { + this.onBlur(); + } + }); } $postLink() { @@ -60,14 +71,20 @@ return null; } if (this.maxBalance) { + const feeHash = utils.groupMoney(utils.toArray(this.fee)); + let amount = null; + if (feeHash[this.assetId]) { - this.amount = BigNumber.max( - this.maxBalance.getTokens().sub(feeHash[this.assetId].getTokens()), - new BigNumber(0) - ); + amount = this.maxBalance.sub(feeHash[this.assetId]); + } else { + amount = this.maxBalance; + } + + if (amount.getTokens().lt(0)) { + this.amount = this.maxBalance.cloneWithTokens('0'); } else { - this.amount = this.maxBalance.getTokens(); + this.amount = amount; } } } @@ -97,10 +114,10 @@ if (!this.assetId) { return null; } - waves.node.assets.info(this.assetId).then((info) => { - this.asset = info; + Waves.Money.fromTokens('0', this.assetId).then((money) => { + this.asset = money.asset; if (!this.amount) { - this.amount = new BigNumber(0); + this.amount = money; } }); } @@ -117,6 +134,8 @@ name: '@', inputClasses: '@', fillMax: '&', + onFocus: '&', + onBlur: '&', amount: '=', assetId: '<', maxBalance: '<', @@ -125,7 +144,6 @@ }, scope: false, templateUrl: 'modules/ui/directives/balanceInput/balanceInput.html', - transclude: false, controller }); })(); diff --git a/src/modules/ui/directives/balanceInput/balanceInput.html b/src/modules/ui/directives/balanceInput/balanceInput.html index ab983fbf2b..d11255eac5 100644 --- a/src/modules/ui/directives/balanceInput/balanceInput.html +++ b/src/modules/ui/directives/balanceInput/balanceInput.html @@ -1,13 +1,13 @@
balanceInput.max
-
\ No newline at end of file + diff --git a/src/modules/ui/directives/button/button.less b/src/modules/ui/directives/button/button.less index caa2c55cae..ce4d81ef66 100644 --- a/src/modules/ui/directives/button/button.less +++ b/src/modules/ui/directives/button/button.less @@ -121,6 +121,7 @@ w-button { background-color: @color-white; border: 1px solid @color-accent-50; color: @color-basic-500; + font-family: @font-roboto-medium; &:hover, &.hover { border-color: @color-basic-500; diff --git a/src/modules/ui/directives/confirmTransaction/ConfirmTransaction.js b/src/modules/ui/directives/confirmTransaction/ConfirmTransaction.js index 3f2315bb16..a7449f858a 100644 --- a/src/modules/ui/directives/confirmTransaction/ConfirmTransaction.js +++ b/src/modules/ui/directives/confirmTransaction/ConfirmTransaction.js @@ -8,9 +8,10 @@ * @param {$mdDialog} $mdDialog * @param {ModalManager} modalManager * @param {User} user + * @param {app.utils} utils * @returns {ConfirmTransaction} */ - const controller = function (Base, waves, $attrs, $mdDialog, modalManager, user) { + const controller = function (Base, waves, $attrs, $mdDialog, modalManager, user, utils) { class ConfirmTransaction extends Base { @@ -22,7 +23,7 @@ } confirm() { - this.sendTransaction().then(({ id }) => { + utils.when(this.sendTransaction()).then(({ id }) => { this.tx.id = id; this.step++; }).catch((e) => { @@ -96,7 +97,7 @@ return new ConfirmTransaction(); }; - controller.$inject = ['Base', 'waves', '$attrs', '$mdDialog', 'modalManager', 'user']; + controller.$inject = ['Base', 'waves', '$attrs', '$mdDialog', 'modalManager', 'user', 'utils']; angular.module('app.ui').component('wConfirmTransaction', { bindings: { diff --git a/src/modules/ui/directives/helpIcon/helpIcon.less b/src/modules/ui/directives/helpIcon/helpIcon.less index 58b941aba8..460b7bcf7d 100644 --- a/src/modules/ui/directives/helpIcon/helpIcon.less +++ b/src/modules/ui/directives/helpIcon/helpIcon.less @@ -58,16 +58,22 @@ div.help-content { border-top: 5px solid @color-submit-300; border-radius: @border-radius; box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.18); - width: 50%; padding: 15px; margin-top: 4px; - left: 25%; &:hover { display: block; } - .row { + .row-help { margin-bottom: 5px; + margin-top: 0; + } +} + +md-dialog { + div.help-content { + left: 25%; + width: 50%; } } diff --git a/src/modules/ui/directives/input/Input.js b/src/modules/ui/directives/input/Input.js index ad77dc7188..37c4bf84ae 100644 --- a/src/modules/ui/directives/input/Input.js +++ b/src/modules/ui/directives/input/Input.js @@ -68,7 +68,7 @@ $onDestroy() { super.$onDestroy(); - this._stopScopeHandlers.forEach(cb => cb()); + this._stopScopeHandlers.forEach((cb) => cb()); } /** @@ -77,18 +77,12 @@ _initialize() { this._$input = $element.find('input,textarea'); this._$inputWrap = $element.find('.w-input-wrap'); - const name = this._name = this._getName(); - - this._$input.on('focus', () => { - this._$inputWrap.addClass('focused'); - }); - - this._$input.on('blur', () => { - this._$inputWrap.removeClass('focused'); - }); + const name = this._name = this._getName(); const formName = $element.closest('form').attr('name'); + this._setHandlers(); + if (this._name && formName) { const form = this._$form = this._getForm(formName); @@ -105,6 +99,16 @@ } } + _setHandlers() { + this._$input.on('focus', () => { + this._$inputWrap.addClass('focused'); + }); + + this._$input.on('blur', () => { + this._$inputWrap.removeClass('focused'); + }); + } + _getName() { const name = this._$input.attr('name'); diff --git a/src/modules/ui/directives/inputContainer/InputContainer.js b/src/modules/ui/directives/inputContainer/InputContainer.js index d9b5f8f8c6..c2248ec401 100644 --- a/src/modules/ui/directives/inputContainer/InputContainer.js +++ b/src/modules/ui/directives/inputContainer/InputContainer.js @@ -9,19 +9,28 @@ class InputContainer { + /** + * @type {Array.} + */ + get inputs() { + return $element.find('input,textarea') + .toArray(); + } + + /** + * @type {ngModel.NgModelController[]} + */ + get target() { + return this.inputs.map((input) => { + return this.form[input.getAttribute('name')]; + }); + } + constructor() { - /** - * @type {ngModel.NgModelController[]} - */ - this.target = null; /** * @type {ngForm} */ this.form = null; - /** - * @type {Array.} - */ - this.inputs = null; } $postLink() { @@ -32,11 +41,6 @@ throw new Error('Can\'t get form!'); } - this.inputs = $element.find('input') - .toArray(); - this.target = this.inputs.map((input) => { - return this.form[input.getAttribute('name')]; - }); } } diff --git a/src/modules/ui/directives/inputContainer/InputError.js b/src/modules/ui/directives/inputContainer/InputError.js index 13503a46a6..f0533176fe 100644 --- a/src/modules/ui/directives/inputContainer/InputError.js +++ b/src/modules/ui/directives/inputContainer/InputError.js @@ -48,8 +48,12 @@ _getElements() { const empty = tsUtils.isEmpty(this.name); - return !empty ? [this.inputContainer.form[this.name].$touched] : - this._getTarget(); + if (empty) { + return this._getTarget(); + } else { + const target = this.inputContainer.form[this.name]; + return target && target.$$element.get(0) !== document.activeElement ? [target] : []; + } } /** diff --git a/src/modules/ui/directives/password/password.html b/src/modules/ui/directives/password/password.html index d9f1834f7d..b38682e887 100644 --- a/src/modules/ui/directives/password/password.html +++ b/src/modules/ui/directives/password/password.html @@ -33,9 +33,9 @@ diff --git a/src/modules/utils/directives/validators/Address.js b/src/modules/utils/directives/validators/Address.js deleted file mode 100644 index 12dfa96f74..0000000000 --- a/src/modules/utils/directives/validators/Address.js +++ /dev/null @@ -1,60 +0,0 @@ -(function () { - 'use strict'; - - /** - * @param Validator - * @param {Waves} waves - * @param $q - * @param outerBlockchains - * @returns {Address} - */ - const factory = function (Validator, waves, $q, outerBlockchains) { - - class Address extends Validator { - - constructor(data) { - super(data); - - const withGateways = this.$attrs.withGateways === 'true'; - const outerChain = outerBlockchains[this.$attrs.assetId]; - - this.$ngModel.$asyncValidators.inputAddress = function (address) { - if (address.length < WavesApp.minAliasLength) { - return $q.reject(); - } else if (withGateways && outerChain && outerChain.isValidAddress(address)) { - return $q.resolve(); - } else if (address.length <= WavesApp.maxAliasLength) { - if (waves.node.aliases.validate(address)) { - return waves.node.aliases.getAddress(address) - .then( - () => $q.resolve(), - () => $q.reject() - ); - } else { - $q.reject(); - } - } else { - // TODO : replace with address validator from `waves-api` when it's implemented - return Waves.API.Node.v1.addresses.balance(address) - .then((data) => { - if (data && data.balance != null) { - return $q.resolve(); - } else { - return $q.reject(); - } - }, (e) => { - return $q.reject(e.message); - }); - } - }; - } - - } - - return Address; - }; - - factory.$inject = ['Validator', 'waves', '$q', 'outerBlockchains']; - - angular.module('app.utils').factory('Address', factory); -})(); diff --git a/src/modules/utils/directives/validators/Asset.js b/src/modules/utils/directives/validators/Asset.js deleted file mode 100644 index 21bcd00b79..0000000000 --- a/src/modules/utils/directives/validators/Asset.js +++ /dev/null @@ -1,99 +0,0 @@ -(function () { - 'use strict'; - - /** - * @param {typeof Num} Num - * @param {app.utils} utils - * @param {Waves} waves - * @return {Asset} - */ - const factory = function (Num, utils, waves) { - - class Asset extends Num { - - constructor(params) { - super(params); - - /** - * @type {string} - */ - this.assetId = this.$attrs.assetId; - if (!this.assetId) { - throw new Error('Has no asset id attribute for asset validator'); - } - - this.onReady() - .then((asset) => { - /** - * @type {Asset} - */ - this.asset = asset; - - this.registerValidator('asset-input', (modelValue, viewValue) => { - const parts = String(viewValue || 0) - .replace(',', '') - .split('.'); - if (!modelValue) { - return 'required' in this.$attrs; - } - return (!parts[1] || parts[1].length <= asset.precision); - }); - - if (this.$attrs.maxBalance) { - let balance; - - this.registerValidator('asset-max', (modelValue) => { - if (!balance) { - return true; - } else { - return modelValue && modelValue.lte(balance.getTokens()); - } - }); - - this.$scope.$watch(this.$attrs.maxBalance, (value) => { - balance = value; - this.validateByName('asset-max'); - }); - } - - this.$scope.$watch(this.assetId, (id) => { - waves.node.assets.info(id).then((asset) => { - this.asset = asset; - this.validate(); - }); - }); - }); - } - - getFormatter() { - return (value) => { - if (value == null) { - return ''; - } - if (new BigNumber(value).eq(utils.parseNiceNumber(this.$input.val()))) { - if (value.indexOf('e') !== -1) { - return new BigNumber(value).toFixed(this.asset.precision); - } else { - return this.$input.val(); - } - } else { - return value; - } - }; - } - - onReady() { - return super.onReady() - .then(() => waves.node.assets.info(this.$scope.$eval(this.assetId))); - } - - } - - return Asset; - }; - - factory.$inject = ['Num', 'utils', 'waves']; - - angular.module('app.utils') - .factory('Asset', factory); -})(); diff --git a/src/modules/utils/directives/validators/CompareTo.js b/src/modules/utils/directives/validators/CompareTo.js deleted file mode 100644 index d8d0ba14bd..0000000000 --- a/src/modules/utils/directives/validators/CompareTo.js +++ /dev/null @@ -1,33 +0,0 @@ -(function () { - 'use strict'; - - const factory = function (Validator) { - - class CompareTo extends Validator { - - constructor(data) { - super(data); - - const $compare = this.$input.closest('form').find(`input[name="${this.$attrs.wCompareTo}"]`); - if (!$compare.length) { - throw new Error('Element for compare not found!'); - } - - $compare.on('input', () => { - this.validate(); - }); - - this.registerValidator('w-compare-to', (value) => { - return value === $compare.val(); - }); - } - - } - - return CompareTo; - }; - - factory.$inject = ['Validator', 'utils']; - - angular.module('app.utils').factory('CompareTo', factory); -})(); diff --git a/src/modules/utils/directives/validators/Num.js b/src/modules/utils/directives/validators/Num.js deleted file mode 100644 index 688ece818a..0000000000 --- a/src/modules/utils/directives/validators/Num.js +++ /dev/null @@ -1,167 +0,0 @@ -(function () { - 'use strict'; - - const factory = function (Validator, utils) { - // TODO rename all validators (add postfix "Validator") - class Num extends Validator { - - constructor(data) { - super(data); - - /** - * @type {RegExp} - */ - const numberReg = /[0-9]/; - /** - * @type {HTMLInputElement} - */ - const input = this.$input.get(0); - - /** - * @param {string} char - * @param {boolean} hasDot - * @return {boolean} - */ - const checkChar = (char, hasDot) => { - if (char === '.') { - return !hasDot; - } else { - return numberReg.test(char); - } - }; - - /** - * @type {boolean} - */ - const isRequired = input.hasAttribute('required'); - /** - * @type {boolean} - */ - const isInteger = input.hasAttribute('integer'); - /** - * @type {boolean} - */ - const hasMax = input.hasAttribute('max'); - /** - * @type {boolean} - */ - const hasMin = input.hasAttribute('min'); - /** - * @type {boolean} - */ - const includeRangeMin = input.hasAttribute('include-range-min'); // TODO refactor to watchers! - /** - * @type {boolean} - */ - const includeRangeMax = input.hasAttribute('include-range-max'); - /** - * @type {boolean} - */ - const hasPrecision = input.hasAttribute('precision'); - - if (isInteger) { - this.registerValidator('integer', (modalValue) => { - return !modalValue || modalValue.round(0).eq(modalValue); - }); - } else if (hasPrecision) { - let precision; - this.registerValidator('precision', (modalValue) => { - return !modalValue || precision == null || modalValue.eq(modalValue.round(precision)); - }); - this.$scope.$watch(this.$attrs.precision, (value) => { - precision = Number(value) || 0; - this.validateByName('precision'); - }); - } - - let min; - if (hasMin) { - if (includeRangeMin) { - this.registerValidator('min', (modalValue) => !min || !modalValue || modalValue.gte(min)); - } else { - this.registerValidator('min', (modalValue) => !min || !modalValue || modalValue.gt(min)); - } - - this.$scope.$watch(this.$attrs.min, (value) => { - min = Num._toBigNumber(value); - this.validateByName('min'); - }); - } - - if (hasMax) { - let max; - if (includeRangeMax) { - this.registerValidator('max', (modalValue) => !max || !modalValue || modalValue.lte(max)); - } else { - this.registerValidator('max', (modalValue) => !max || !modalValue || modalValue.lt(max)); - } - - this.$scope.$watch(this.$attrs.max, (value) => { - max = Num._toBigNumber(value); - this.validateByName('max'); - }); - } - - this.registerValidator('required', (modelValue) => { - return !isRequired || Num._isEmpty(modelValue, includeRangeMin, min); - }); - - this.$input.on('keypress', (event) => { - function getChar(event) { - if (event.which === null) { - if (event.keyCode < 32) return null; - return String.fromCharCode(event.keyCode); - } - - if (event.which !== 0 && event.charCode !== 0) { - if (event.which < 32) { - return null; - } - return String.fromCharCode(event.which); - } - - return null; - } - - const char = getChar(event); - if (event.charCode == null || event.charCode !== 0) { - if (!char || !checkChar(char, this.$input.val().indexOf('.') !== -1)) { - event.preventDefault(); - } - } - }); - - } - - getParser() { - return utils.parseNiceNumber; - } - - static _isEmpty(value, include, min) { - if (include) { - return value instanceof BigNumber ? value.gte(min) : !!value; - } - return value instanceof BigNumber ? value.gt(0) : !!value; - } - - static _toBigNumber(value) { - if (value == null) { - return null; - } else if (!value) { - return new BigNumber(0); - } else if (value instanceof BigNumber) { - return value; - } else { - return new BigNumber(value); - } - } - - } - - return Num; - }; - - factory.$inject = ['Validator', 'utils']; - - angular.module('app.utils').factory('Num', factory); -})(); diff --git a/src/modules/utils/directives/validators/Validate.js b/src/modules/utils/directives/validators/Validate.js index 23df0a60a5..8a40667d5c 100644 --- a/src/modules/utils/directives/validators/Validate.js +++ b/src/modules/utils/directives/validators/Validate.js @@ -1,160 +1,636 @@ (function () { 'use strict'; + const AVAILABLE_VALIDATORS = [ + 'gt', + 'gte', + 'lt', + 'lte', + 'length', + 'integer', + 'precision', + 'byteLt', + 'byteLte', + 'byteGt', + 'byteGte', + 'number', + 'asset', + 'compare', + 'alias', + 'address', + 'wavesAddress', + 'outerBlockchains', + 'anyAddress', + 'pattern', + 'custom' + ]; + + const NUMBER_PATTERN = '[0-9.]'; //TODO Add locale separators + /** - * @param {typeof Base} Base + * * @param {app.utils} utils - * @param {typeof Asset} Asset - * @param {typeof Num} Num - * @param {typeof CompareTo} CompareTo - * @param {typeof Address} Address - * @return {{require: string, link: (function(*=, *, *, *))}} + * @param {ValidateService} validateService + * @param {app.utils.decorators} decorators */ - const directive = (Base, utils, Asset, Num, CompareTo, Address) => { - + const directive = function (utils, validateService, decorators) { return { require: 'ngModel', - link: ($scope, $input, $attrs, $ngModel) => { + priority: 10000, + /** + * @param {JQuery} $input + * @param {object} $attrs + * @return {*} + */ + compile: function ($input, $attrs) { /** * $input can be both and , in the latter case we should ignore validation */ - if ($input.get(0).tagName !== 'INPUT') { + if ($input.get(0).tagName !== 'INPUT' && $input.get(0).tagName !== 'TEXTAREA') { return null; } - class Validate extends Base { + return function ($scope, $input, $compiledAttrs, $ngModel) { + + class Validate { + + constructor() { + this._validators = Object.create(null); + /** + * @type {Signal} + * @private + */ + this._validatorsReady = new tsUtils.Signal(); + this._ready = false; + + this._validatorsReady.once(() => { + this._ready = true; + }); + + this._createValidatorList(); + $scope.$watch($attrs.ngModel, () => this._validate()); + } + + _addInputPattern(pattern) { + const create = () => { + const patternName = Validate._getAttrName('pattern'); + if (!$attrs[patternName]) { + $attrs[patternName] = pattern; + this._createValidator('pattern'); + } + }; + + if (this._ready) { + create(); + } else { + this._validatorsReady.once(create); + } + } + + /** + * @param validators + * @private + */ + _applyValidators(validators) { + validators.forEach(({ name, handler }) => { + const result = handler($ngModel.$modelValue, $ngModel.$viewValue); + + switch (typeof result) { + case 'boolean': + $ngModel.$setValidity(name, result); + break; + case 'object': + if (result && typeof result.then === 'function') { + $ngModel.$setValidity(`pending-${name}`, false); + const onEnd = () => { + $ngModel.$setValidity(`pending-${name}`, true); + }; + utils.when(result).then(() => { + $ngModel.$setValidity(name, true); + onEnd(); + }, () => { + $ngModel.$setValidity(name, false); + onEnd(); + }); + } else { + throw new Error('Wrong validation result!'); + } + break; + default: + throw new Error('Wrong validation result!'); + } + }); + } + + /** + * @private + */ + @decorators.async() + _validate() { + this._applyValidators(Object.keys(this._validators).map((name) => this._validators[name])); + $scope.$apply(); + } + + /** + * @param targetName + * @private + */ + _validateByName(targetName) { + this._applyValidators([this._validators[targetName]].filter(Boolean)); + } - constructor() { - super($scope); /** - * @type {Validator[]} * @private */ - this._messages = []; + _createValidatorList() { + AVAILABLE_VALIDATORS.filter(Validate._hasValidator).forEach((name) => { + this._createValidator(name); + }); + + this._validatorsReady.dispatch(); + } - this._createValidators(); - this._onReady() - .then(() => { + /** + * @param name + * @private + */ + _createValidator(name) { - const { parsers, formatters } = this._getProcessors(); + if (this._validators[name]) { + throw new Error(`Duplicate validator! ${name}`); + } - $ngModel.$parsers.unshift((value) => { - this._validate(value); - return parsers.reduce(Validate.valueFormatReducer, value); - }); + switch (name) { + case 'asset': + this._validators[name] = this._createAssetValidator(name); + break; + case 'compare': + this._validators[name] = this._createCompareValidator(name); + break; + case 'custom': + this._validators[name] = this._createCustomValidator(name); + break; + case 'number': + this._validators[name] = this._createBigNumberValidator(name); + break; + case 'alias': + case 'address': + case 'wavesAddress': + this._validators[name] = this._createAddressValidator(name); + break; + case 'integer': + this._validators[name] = this._createIntegerValidator(name); + break; + case 'anyAddress': + this._validators[name] = this._createAnyAddressValidator(name); + break; + case 'outerBlockchains': + this._validators[name] = this._createOuterBlockchainsValidator(name); + break; + case 'pattern': + this._validators[name] = this._createPatternValidator(name); + break; + default: + this._validators[name] = this._createSimpleValidator(name); + } - $ngModel.$formatters.unshift((value) => { - return formatters.reduce(Validate.valueFormatReducer, value); - }); + if (this._validators[name].parser) { + $ngModel.$parsers.push(this._validators[name].parser); + } - $scope.$watch($attrs.ngModel, () => { - this._validate(); - }); + if (this._validators[name].formatter) { + $ngModel.$formatters.push(this._validators[name].formatter); + } - $input.get(0).value = $ngModel.$formatters.reduce((result, formatter) => { - return formatter(result); - }, $ngModel.$viewValue); - this._validate(); + return this._validators[name]; + } + + _createCustomValidator(name) { + + const validator = { + name, + value: null, + handler: function () { + if (validator.value == null) { + return true; + } else if (typeof validator.value === 'function') { + return validator.value(); + } else { + return !!validator.value; + } + } + }; + + this._listenValidatorChanges(name, validator); + + return validator; + } + + _createIntegerValidator(name) { + this._createPatternValidator('[0-9]'); + + return { + name, + value: null, + handler: (modelValue) => { + try { + const num = Validate._toBigNumber(modelValue); + return !modelValue || num.round(0).eq(Validate._toBigNumber(modelValue)); + } catch (e) { + return false; + } + } + }; + } + + _createOuterBlockchainsValidator(name) { + + let value = null; + + const validator = { + name, + value: null, + handler: function (address) { + return validateService.outerBlockchains(address, validator.value); + } + }; + + Object.defineProperty(validator, 'value', { + get: () => value, + set: (data) => { + value = Validate._toAssetId(data); + } }); - } - /** - * @private - */ - _validate() { - this._messages.forEach((validator) => { - validator.validate(); - }); - } + this._listenValidatorChanges(name, validator); - /** - * @return {*|Promise} - * @private - */ - _onReady() { - return utils.whenAll(this._messages.map((validator) => validator.onReady())); - } + return validator; + } + + _createAnyAddressValidator(name) { + + let value = null; + + const validator = { + name, + value: null, + handler: function (address) { + return validateService.anyAddress(address, validator.value); + } + }; + + Object.defineProperty(validator, 'value', { + get: () => value, + set: (data) => { + value = Validate._toAssetId(data); + } + }); + + this._listenValidatorChanges(name, validator); + + return validator; + } + + _createCompareValidator(name) { + + let value = null; + + const validator = { + name, + value: null, + $compare: null, + $compareHandler: () => { + this._validateByName(name); + $scope.$apply(); + }, + handler: (value) => { + return value === validator.$compare.val(); + }, + destroy: function () { + this.$compare.off('input', this.$compareHandler); + } + }; + + Object.defineProperty(validator, 'value', { + get: () => value, + set: (val) => { + if (utils.isNotEqualValue(value, val)) { + if (validator.$compare) { + validator.$compare.off('input', validator.$compareHandler); + } + validator.$compare = $input.closest('form').find(`input[name="${val}"]`); + validator.$compare.on('input', validator.$compareHandler); + value = val; + } + } + }); + + this._listenValidatorChanges(name, validator); + + return validator; + } + + _createPatternValidator(name) { + + let value; + + const validator = { + name, + value: null, + handler: (modelValue, viewValue) => { + return true; // TODO + } + }; + + Object.defineProperty(validator, 'value', { + get: () => value, + set: (val) => { + value = new RegExp(val); + } + }); + + $input.on('keypress', (event) => { + if (event.keyCode != null) { + const char = String.fromCharCode(event.keyCode); + if (char != null) { + if (validator.value.test(char)) { + if (char === '.' && $input.val().includes('.')) { + // TODO add separator from locale + event.preventDefault(); + } + } else { + event.preventDefault(); + } + } + } + }); + + this._listenValidatorChanges(name, validator); + + return validator; + } + + /** + * + * @param name + * @return {*} + * @private + */ + _createAssetValidator(name) { + const precisionValidator = this._createValidator('precision'); + + this._addInputPattern(NUMBER_PATTERN); + + let value = null; + + const validator = { + name, + money: null, + value: null, + apply: () => { + precisionValidator.value = validator.money.asset.precision; + this._validateByName(name); + }, + handler: (modelValue, viewValue) => { + return (viewValue && !!modelValue) || !viewValue; + }, + parser: (value) => { + if (precisionValidator.handler($ngModel.$modelValue, value)) { + return Validate._toMoney(value, validator.money); + } else { + return null; + } + }, + formatter: (value) => { + + const viewValue = $input.val(); + const money = precisionValidator.handler($ngModel.$modelValue, viewValue) && + Validate._toMoney(viewValue, validator.money); + + if (Validate._isFocused() && (!value || (money && money.eq(value)))) { + return $input.val(); + } else { + return Validate._toString(value); + } + } + }; + + $input.on('input', () => { + this._validateByName(precisionValidator.name); + $scope.$apply(); + }); + + Object.defineProperty(validator, 'value', { + get: () => value, + set: (assetData) => { + + validator.money = null; + + if (!assetData) { + return null; + } + + value = Validate._toAssetId(assetData); + if (value) { + Waves.Money.fromTokens('0', value).then((money) => { + if (utils.isNotEqualValue(validator.money, money)) { + validator.money = money; + validator.apply(); + $ngModel.$modelValue = validator.parser($ngModel.$viewValue); + } + }); + } + } + }); - /** - * @return {{parsers: Array, formatters: Array}} - * @private - */ - _getProcessors() { - const parsers = []; - const formatters = []; - this._messages.forEach((item) => { - const parser = item.getParser(); - const formatter = item.getFormatter(); - if (parser) { - parsers.push(parser); + this._listenValidatorChanges(name, validator); + + return validator; + } + + _createAddressValidator(name) { + const validator = { + name, + value: null, + handler: (value) => validateService[name](value, validator.value) + }; + this._listenValidatorChanges(name, validator); + + return validator; + } + + /** + * @param name + * @private + */ + _createSimpleValidator(name) { + + let handler; + switch (name) { + case 'precision': + handler = function (modelValue, viewValue) { + let value; + + try { + if (viewValue) { + value = utils.parseNiceNumber(viewValue); + } else { + value = null; + } + } catch (e) { + value = null; + } + + return validateService[name](value, validator.value); + }; + break; + default: + handler = function (modelValue) { + return validateService[name](modelValue, validator.value); + }; } - if (formatter) { - formatters.push(formatter); + + const validator = { + name, + value: null, + handler + }; + + this._listenValidatorChanges(name, validator); + + return validator; + } + + _createBigNumberValidator(name) { + + this._addInputPattern(NUMBER_PATTERN); + + return { + name, + handler: () => true, + parser: Validate._toBigNumber, + formatter: Validate._toString + }; + } + + + /** + * @param name + * @param validator + * @private + */ + _listenValidatorChanges(name, validator) { + const attrValue = $attrs[Validate._getAttrName(name)]; + + if (Validate._hasExp(attrValue)) { + const exp = attrValue.replace(/{{(.*)?}}/g, '$1'); + + if (exp.indexOf('::') !== -1) { + validator.value = $scope.$eval(exp.replace('::', '')); + } else { + $scope.$watch(exp, (value) => { + validator.value = value; + this._validateByName(validator.name); + }); + } + + } else { + validator.value = attrValue; } - }); - return { parsers, formatters }; - } + } - /** - * @private - */ - _createValidators() { - if (!$attrs.wValidate) { - throw new Error('Has no validators list!'); + static _isFocused() { + return document.activeElement === $input.get(0); } - const list = $attrs.wValidate.split(','); - if (!list.length) { - throw new Error('Validators list is empty!'); + + static _toAssetId(data) { + if (typeof data === 'string') { + return data; + } else if (data instanceof Waves.Money) { + return data.asset.id; + } else if (data instanceof Waves.Asset) { + return data.id; + } else { + return null; + } } - const hash = Object.create(null); - list.forEach((name) => { - if (hash[name]) { - throw new Error('Duplicate validator!'); + static _toString(value) { + if (value instanceof BigNumber) { + return value.toFixed(); + } else if (value instanceof Waves.Money) { + return value.toFormat(); + } else if (!value) { + return ''; + } else { + return String(value); } - this._createValidator(name); - }); - } + } - /** - * @param name - * @private - */ - _createValidator(name) { - let Constructor = null; - switch (name) { - case 'asset': - Constructor = Asset; - break; - case 'address': - Constructor = Address; - break; - case 'number': - Constructor = Num; - break; - case 'compare': - Constructor = CompareTo; - break; - default: - throw new Error('Wrong validator name!'); - } - this._messages.push(new Constructor({ $scope, $input, $attrs, $ngModel })); - } + static _toMoney(value, target) { + if (!target) { + return null; + } else { + try { + return target.cloneWithTokens(utils.parseNiceNumber(value)); + } catch (e) { + return null; + } + } + } - static valueFormatReducer(result, item) { - return item(result); - } + static _toBigNumber(value) { + try { + return new BigNumber(utils.parseNiceNumber(value)); + } catch (e) { + return null; + } + } - } + /** + * @param value + * @return {boolean} + * @private + */ + static _hasExp(value) { + if (!value) { + return false; + } + + const openIndex = value.indexOf('{{'); + const closeIndex = value.indexOf('}}'); + return openIndex !== -1 && closeIndex !== -1 && openIndex < closeIndex; + } + + /** + * @param validatorName + * @return {string} + * @private + */ + static _getAttrName(validatorName) { + return `wValidator${validatorName.charAt(0).toUpperCase()}${validatorName.slice(1)}`; + } + + /** + * @param name + * @return {boolean} + * @private + */ + static _hasValidator(name) { + return Validate._getAttrName(name) in $attrs; + } + + } - new Validate(); + return new Validate(); + }; } }; }; - directive.$inject = ['Base', 'utils', 'Asset', 'Num', 'CompareTo', 'Address']; + directive.$inject = ['utils', 'validateService', 'decorators']; angular.module('app.utils').directive('wValidate', directive); diff --git a/src/modules/utils/directives/validators/ValidateService.js b/src/modules/utils/directives/validators/ValidateService.js new file mode 100644 index 0000000000..443f79c6d7 --- /dev/null +++ b/src/modules/utils/directives/validators/ValidateService.js @@ -0,0 +1,208 @@ +(function () { + 'use strict'; + + /** + * @param {Waves} waves + * @param {$q} $q + * @param {Object.} outerBlockchains + * @param {app.utils} utils + * @param {User} user + * @return {ValidateService} + */ + const factory = function (waves, $q, outerBlockchains, utils, user) { + + class ValidateService { + + @toBigNumberArgs + @notNullArgs + gt(inputValue, validateValue) { + return inputValue.gt(validateValue); + } + + @toBigNumberArgs + @notNullArgs + gte(inputValue, validateValue) { + return inputValue.gte(validateValue); + } + + @toBigNumberArgs + @notNullArgs + lt(inputValue, validateValue) { + return inputValue.lt(validateValue); + } + + @toBigNumberArgs + @notNullArgs + lte(inputValue, validateValue) { + return inputValue.lte(validateValue); + } + + @notNullArgs + length(inputValue, length) { + return String(inputValue).length <= length; + } + + @toBigNumberArgs + @notNullArgs + precision(inputValue, precision) { + const [int, dec] = inputValue.toFixed().split('.'); //TODO add separator + return dec ? dec.length <= precision : true; //TODO remove empty zero + } + + @notNullArgs + byteLt(inputValue, bytes) { + const blob = new Blob([inputValue], { type: 'text/html' }); + return blob.size < Number(bytes); + } + + @notNullArgs + byteLte(inputValue, bytes) { + const blob = new Blob([inputValue], { type: 'text/html' }); + return blob.size <= Number(bytes); + } + + @notNullArgs + byteGt(inputValue, bytes) { + const blob = new Blob([inputValue], { type: 'text/html' }); + return blob.size > Number(bytes); + } + + @notNullArgs + byteGte(inputValue, bytes) { + const blob = new Blob([inputValue], { type: 'text/html' }); + return blob.size >= Number(bytes); + } + + @notNullArgs + integer(inputValue) { + return inputValue.round().eq(inputValue); + } + + anyAddress(address, assetId) { + return this.outerBlockchains(address, assetId) ? true : this.wavesAddress(address); + } + + wavesAddress(address, value) { + return utils.whenAll([ + this.alias(address, value), + this.address(address, value) + ]).then(([alias = true, address = true]) => { + return (alias || address) ? $q.resolve() : $q.reject(); + }); + } + + outerBlockchains(address, assetId) { + if (!address || !assetId) { + return true; + } + + const outerChain = outerBlockchains[assetId]; + + if (!outerChain) { + return false; + } + + return outerChain.isValidAddress(address); + } + + alias(address, value = '') { + if (!address) { + return true; + } + + if (address.length < WavesApp.minAliasLength) { + return false; + } + + if (address.length > WavesApp.maxAliasLength) { + return false; + } + + if (!waves.node.aliases.validate(address)) { + return false; + } else { + if (value && value === 'no-self') { + return !waves.node.aliases.getAliasList().includes(address) && + waves.node.aliases.getAddress(address); + } else { + return waves.node.aliases.getAddress(address); + } + } + } + + address(address, value = '') { + if (!address) { + return true; + } + + if (address.length <= WavesApp.maxAliasLength) { + return false; + } + + if (address.length >= WavesApp.maxAddressLength) { + return false; + } + + if (value && value === 'no-self' && address === user.address) { + return false; + } + + return Waves.API.Node.v1.addresses.balance(address) + .then((data) => { + if (data && data.balance != null) { + return $q.resolve(); + } else { + return $q.reject(); + } + }, (e) => { + return $q.reject(e.message); + }); + } + + static toBigNumber(item) { + switch (typeof item) { + case 'string': + case 'number': + try { + return new BigNumber(item); + } catch (e) { + return null; + } + case 'object': + if (item instanceof BigNumber) { + return item; + } else if (item instanceof Waves.Money) { + return item.getTokens(); + } else { + return null; + } + } + } + + } + + function notNullArgs(target, key, descriptor) { + const origin = descriptor.value; + descriptor.value = function (...args) { + if (args.some((value) => value == null || value === '')) { + return true; + } else { + return origin.call(this, ...args); + } + }; + } + + function toBigNumberArgs(target, key, descriptor) { + const origin = descriptor.value; + descriptor.value = function (...args) { + return origin.call(this, ...args.map(ValidateService.toBigNumber)); + }; + } + + return utils.bind(new ValidateService()); + }; + + factory.$inject = ['waves', '$q', 'outerBlockchains', 'utils', 'user']; + + angular.module('app.utils').factory('validateService', factory); +})(); diff --git a/src/modules/utils/directives/validators/Validator.js b/src/modules/utils/directives/validators/Validator.js deleted file mode 100644 index b19a4a4ba9..0000000000 --- a/src/modules/utils/directives/validators/Validator.js +++ /dev/null @@ -1,69 +0,0 @@ -(function () { - 'use strict'; - - const factory = function (Base, utils) { - - class Validator extends Base { - - constructor({ $scope, $input, $attrs, $ngModel }) { - super($scope); - - this.$scope = $scope; - this.$input = $input; - this.$attrs = $attrs; - this.$ngModel = $ngModel; - - /** - * @type {Array} - * @private - */ - this._messages = []; - } - - registerValidator(name, handler) { - if (!tsUtils.find(this._messages, { name })) { - this._messages.push({ name, handler }); - } else { - throw new Error('Duplicate validator name!'); - } - } - - onReady() { - return utils.when(); - } - - validate() { - this._messages.forEach((validator) => { - const state = validator.handler(this.$ngModel.$modelValue, this.$ngModel.$viewValue); - this.$ngModel.$setValidity(validator.name, state); - }); - } - - validateByName(name) { - this._messages.forEach((validator) => { - if (validator.name === name) { - this.$ngModel.$setValidity( - validator.name, - validator.handler(this.$ngModel.$modelValue, this.$ngModel.$viewValue) - ); - } - }); - } - - getParser() { - return null; - } - - getFormatter() { - return null; - } - - } - - return Validator; - }; - - factory.$inject = ['Base', 'utils']; - - angular.module('app.utils').factory('Validator', factory); -})(); diff --git a/src/modules/utils/locales/en.json b/src/modules/utils/locales/en.json index 541922dd4d..d7e4568b7c 100755 --- a/src/modules/utils/locales/en.json +++ b/src/modules/utils/locales/en.json @@ -48,12 +48,15 @@ "description": "Description", "descriptionPlaceholder": "Write an optional message", "placeholderRecipient": "Paste or scan an address", - "fee": "Transaction Fee", + "fee": "Transaction Fee {{fee, money-currency}}", + "attachmentLength": "The description is too long", "total": "Total", "errors": { "address": "The address is not valid", "required": "This field is required", - "max": "Insufficient funds" + "max": "Insufficient funds", + "precision": "The number in this field is invalid. It can include a maximum of {{precision}} digits after the decimal point.", + "invalidChars": "The field can only contain numbers" }, "confirm": { "title": "Transaction Details", diff --git a/src/modules/utils/locales/ru.json b/src/modules/utils/locales/ru.json index 1144b42fa1..29fd3c36ba 100644 --- a/src/modules/utils/locales/ru.json +++ b/src/modules/utils/locales/ru.json @@ -48,12 +48,15 @@ "description": "Описание", "descriptionPlaceholder": "Напишите сообщение (не обязательно)", "placeholderRecipient": "Вставьте или просканируйте адрес", - "fee": "Комиссия", + "fee": "Комиссия {{fee, money-currency}}", + "attachmentLength": "Превышена максимальная длина описания!", "total": "Всего", "errors": { "address": "Неверный адрес", "required": "Это обязательное поле", - "max": "Недостаточно средств" + "max": "Недостаточно средств", + "precision": "Число в этом поле не может содрержать более {{precision}} знаков после точки.", + "invalidChars": "Это поле может содержать только цифры" }, "confirm": { "title": "Детали транзакции", @@ -106,7 +109,7 @@ }, "coinomatETH": { "warningTitle": "Не отправляйте ETH со смарт-контрактов! Не отправляйте ERC20-токены! Только Ethereum.", - "warningText" : "Проверьте, не использует ли ваш кошелёк или биржа смарт-контракты для отправки ETH. Мы не принимаем такие переводы и не можем возместить их. Вы потеряете эти деньги.", + "warningText": "Проверьте, не использует ли ваш кошелёк или биржа смарт-контракты для отправки ETH. Мы не принимаем такие переводы и не можем возместить их. Вы потеряете эти деньги.", "warningMinAmountTitle": "Минимальная сумма депозита 0.001 ETH.", "warningMinAmountText": "Если вы отправите меньше чем 0.001 ETH, вы потеряете деньги.", "helpDescrTitle": "Введите этот адрес в ваш Ethereum клиент или кошелёк.", @@ -114,7 +117,7 @@ }, "coinomatLTC": { "warningTitle": "Отправляйте только LTC на этот адрес", - "warningText" : "Отправка любой другой валюты на этот адрес может повлечь за собой потерю средств.", + "warningText": "Отправка любой другой валюты на этот адрес может повлечь за собой потерю средств.", "warningMinAmountTitle": "Минимальная сумма депозита 0.001 LTC.", "warningMinAmountText": "Если вы отправите меньше чем 0.001 LTC, вы потеряете деньги.", "helpDescrTitle": "Введите этот адрес в ваш Litecoin клиент или кошелёк.", @@ -122,7 +125,7 @@ }, "coinomatZEC": { "warningTitle": "Отправляйте только Zcash на этот адрес", - "warningText" : "Отправка любой другой валюты на этот адрес может повлечь за собой потерю средств.", + "warningText": "Отправка любой другой валюты на этот адрес может повлечь за собой потерю средств.", "warningMinAmountTitle": "Минимальная сумма депозита 0.001 ZEC.", "warningMinAmountText": "Если вы отправите меньше чем 0.001 ZEC, вы потеряете деньги.", "helpDescrTitle": "Введите этот адрес в ваш Zcash клиент или кошелёк.", diff --git a/src/modules/utils/modals/ModalManager.js b/src/modules/utils/modals/ModalManager.js index bb5b98b053..9717ccc6b4 100644 --- a/src/modules/utils/modals/ModalManager.js +++ b/src/modules/utils/modals/ModalManager.js @@ -104,7 +104,6 @@ mod: 'modal-send', locals: { assetId: asset.id, - baseAssetId: user.getSetting('baseAssetId'), canChooseAsset: !asset.id } }); @@ -189,14 +188,14 @@ } showConfirmTx(type, txData) { - return $injector.get('waves').node.transactions.createTransaction(type, txData).then((tx) => { - return this._getModal({ - id: 'confirm-tx', - ns: 'app.ui', - locals: { tx }, - controller: 'ConfirmTxCtrl', - contentUrl: 'modules/utils/modals/confirmTx/confirmTx.modal.html' - }); + const tx = $injector.get('waves').node.transactions.createTransaction(type, txData); + + return this._getModal({ + id: 'confirm-tx', + ns: 'app.ui', + locals: { tx }, + controller: 'ConfirmTxCtrl', + contentUrl: 'modules/utils/modals/confirmTx/confirmTx.modal.html' }); } diff --git a/src/modules/utils/modals/accountInfo/AccountInfoCtrl.js b/src/modules/utils/modals/accountInfo/AccountInfoCtrl.js index 8b52c715c8..91ee0d48a4 100644 --- a/src/modules/utils/modals/accountInfo/AccountInfoCtrl.js +++ b/src/modules/utils/modals/accountInfo/AccountInfoCtrl.js @@ -41,10 +41,7 @@ this.fee = fee; }); - waves.node.aliases.getAliasList() - .then((aliases) => { - this.aliases = aliases; - }); + this.aliases = waves.node.aliases.getAliasList(); } createAlias() { diff --git a/src/modules/utils/modals/accountInfo/account-info.modal.html b/src/modules/utils/modals/accountInfo/account-info.modal.html index 109acf18b0..dbc5199840 100644 --- a/src/modules/utils/modals/accountInfo/account-info.modal.html +++ b/src/modules/utils/modals/accountInfo/account-info.modal.html @@ -34,7 +34,7 @@ placeholder="modal.account.placeholder" required w-i18n-attr="placeholder" - ng-pattern="/[a-z0-9-.@_]/" + ng-pattern="/^[a-z0-9-@_.]*$/" maxlength="30" minlength="4">
modal.qr.copyAndShare -
modal.qr.warningTitle
-
modal.qr.warningText
+
modal.qr.warningTitle
+
modal.qr.warningText
diff --git a/src/modules/utils/modals/depositAsset/deposit-asset.modal.html b/src/modules/utils/modals/depositAsset/deposit-asset.modal.html index 8fa979f467..0a1d2b3931 100644 --- a/src/modules/utils/modals/depositAsset/deposit-asset.modal.html +++ b/src/modules/utils/modals/depositAsset/deposit-asset.modal.html @@ -13,11 +13,11 @@
-
+
modal.deposit.{{::$ctrl.assetKeyName}}.helpDescrTitle
-
modal.deposit.{{::$ctrl.assetKeyName}}.helpDescrText
-
modal.deposit.pleaseNote
+
modal.deposit.{{::$ctrl.assetKeyName}}.helpDescrText
+
modal.deposit.pleaseNote
diff --git a/src/modules/utils/modals/sendAsset/AssetSendCtrl.js b/src/modules/utils/modals/sendAsset/AssetSendCtrl.js index e54707d796..310f230c66 100644 --- a/src/modules/utils/modals/sendAsset/AssetSendCtrl.js +++ b/src/modules/utils/modals/sendAsset/AssetSendCtrl.js @@ -3,83 +3,77 @@ /** * @param $scope - * @param $mdDialog * @param {Waves} waves * @param {Base} Base * @param {app.utils} utils * @param {User} user - * @param {EventManager} eventManager - * @param {NotificationManager} notificationManager * @param {function} createPoll - * @param {@constructor PollComponent} PollComponent - * @param {ModalManager} modalManager * @param outerBlockchains * @param {GatewayService} gatewayService * @return {AssetSendCtrl} */ - const controller = function ($scope, $mdDialog, waves, Base, utils, user, eventManager, notificationManager, - createPoll, modalManager, outerBlockchains, gatewayService) { + const controller = function ($scope, waves, Base, utils, user, createPoll, outerBlockchains, gatewayService) { class AssetSendCtrl extends Base { + /** + * @return {number} + */ + get moneyLength() { + return this.moneyHash && Object.keys(this.moneyHash).length; + } + + /** + * @return {Money} + */ + get balance() { + return this.moneyHash && this.moneyHash[this.assetId]; + } + /** * @param {string} assetId - * @param {string} mirrorId * @param {boolean} canChooseAsset */ - constructor(assetId, mirrorId, canChooseAsset) { + constructor(assetId, canChooseAsset) { super($scope); - this.defaultAssets = WavesApp.defaultAssets; - this.tx = Object.create(null); - /** - * @type {Money} - */ - this.fee = null; - /** - * @type {BigNumber} - */ - this.amount = null; /** - * @type {BigNumber} + * @type {ISendTx} */ - this.amountMirror = null; - /** - * @type {number} - */ - this.step = 0; - /** - * @type {boolean} - */ - this.canChooseAsset = !assetId || canChooseAsset; + this.tx = { + amount: null, + fee: null, + recipient: '', + attachment: '' + }; /** - * @type {string} + * @type {{BTC: string, USD: string, LTC: string, ETH: string, WAVES: string, EUR: string, ZEC: string}} */ - this.mirrorId = mirrorId; + this.defaultAssets = WavesApp.defaultAssets; /** * @type {string} */ - this.assetId = assetId || WavesApp.defaultAssets.WAVES; + this.focus = null; /** * @type {string} */ - this.recipient = ''; + this.mirrorId = null; /** * @type {Money} */ - this.balance = null; + this.mirror = null; /** - * @type {string} + * @type {number} */ - this.attachment = null; + this.step = 0; /** - * @type {Money} + * @type {boolean} */ - this.mirrorBalance = null; + this.canChooseAsset = !assetId || canChooseAsset; /** - * @type {Money[]} + * @type {string} */ - this.moneyList = null; + this.assetId = assetId || WavesApp.defaultAssets.WAVES; /** * @type {boolean} */ @@ -104,93 +98,158 @@ * @type {Array} */ this.feeList = null; + /** + * @type {Object.} + */ + this.moneyHash = null; + /** + * @type {boolean} + * @private + */ + this._noCurrentRate = false; + + this.syncSettings({ + mirrorId: 'baseAssetId' + }); - this.observe('amount', this._onChangeAmount); - this.observe('amountMirror', this._onChangeAmountMirror); - this.observe('assetId', this._onChangeAssetId); - this.observe('recipient', this._updateGatewayDetails); - this.observe(['gatewayDetails', 'fee', 'amount'], this._currentHasCommission); + /** + * @type {Poll} + */ + this.poll = createPoll(this, this._getBalanceList, 'moneyHash', 1000, { isBalance: true }); + + utils.whenAll([ + waves.node.assets.fee('transfer'), + this.poll.ready + ]).then(([[fee]]) => { + + this.observe('gatewayDetails', this._currentHasCommission); + this.receive(utils.observe(this.tx, 'fee'), this._currentHasCommission, this); + + this.tx.fee = fee; + this.tx.amount = this.moneyHash[this.assetId].cloneWithTokens('0'); + this.mirror = this.moneyHash[this.mirrorId].cloneWithTokens('0'); + + this.observe('assetId', this._onChangeAssetId); + this.observe('mirrorId', this._onChangeMirrorId); + this.observe(['assetId', 'mirrorId'], () => this.poll.restart()); + this.receive(utils.observe(this.tx, 'recipient'), this._updateGatewayDetails, this); + this.receive(utils.observe(this.tx, 'amount'), this._onChangeAmount, this); + this.observe('mirror', this._onChangeAmountMirror); - this._onChangeAssetId({}); + this._onChangeBaseAssets(); - createPoll(this, this._getBalanceList, this._setAssets, 1000, { isBalance: true }); + this._updateGatewayDetails(); + }); } fillMax() { - // TODO : consider gateway fee - if (this.assetId === this.fee.asset.id) { - if (this.balance.getTokens().gt(this.fee.getTokens())) { - this.amount = this.balance.getTokens() - .sub(this.fee.getTokens()); - } + let amount = null; + const moneyHash = utils.groupMoney(this.feeList); + if (moneyHash[this.assetId]) { + amount = this.balance.sub(moneyHash[this.assetId]); } else { - this.amount = this.balance.getTokens(); + amount = this.balance; } + waves.utils.getRate(this.assetId, this.mirrorId).then((rate) => { + this._noCurrentRate = true; + this.mirror = amount.convertTo(this.moneyHash[this.mirrorId].asset, rate); + this.tx.amount = amount; + this._noCurrentRate = false; + }); } onReadQrCode(result) { - this.recipient = result; + this.tx.recipient = result; } createTx() { const toGateway = this.outerSendMode && this.gatewayDetails; - return Waves.Money.fromTokens(this.amount, this.assetId) - .then((amount) => waves.node.transactions.createTransaction('transfer', { - amount, - sender: user.address, - fee: this.fee, - recipient: toGateway ? this.gatewayDetails.address : this.recipient, - attachment: toGateway ? this.gatewayDetails.attachment : this.attachment - })).then((tx) => { - this.tx = tx; - this.step++; - }); + const tx = waves.node.transactions.createTransaction('transfer', { + ...this.tx, + sender: user.address, + recipient: toGateway ? this.gatewayDetails.address : this.tx.recipient, + attachment: toGateway ? this.gatewayDetails.attachment : this.tx.attachment + }); + + this.txInfo = tx; + this.step++; } back() { this.step--; } - _getBalanceList() { - return waves.node.assets.userBalances().then((list) => { - return list && list.length ? list : waves.node.assets.balanceList([WavesApp.defaultAssets.WAVES]); - }).then((list) => list.map(({ available }) => available)) - .then((list) => { - if (list.some(({ asset }) => asset.id === this.assetId)) { - return list; - } else { - return Waves.Money.fromTokens('0', this.assetId).then((money) => { - list.push(money); - return list; - }); - } + onBlurMirror() { + if (!this.mirror) { + this._fillMirror(); + } + this.focus = ''; + } + + /** + * @private + */ + _onChangeBaseAssets() { + if (this.assetId === this.mirrorId) { + this.noMirror = true; + } else { + waves.utils.getRate(this.assetId, this.mirrorId).then((rate) => { + this.noMirror = rate.eq(0); }); + } } - _onChangeAssetId({ prev }) { - if (!this.assetId) { + /** + * @return {Promise} + * @private + */ + _getBalanceList() { + return waves.node.assets.userBalances() + .then((list) => list.map(({ available }) => available)) + .then((list) => list.filter((money) => money.getTokens().gt(0))) + .then((list) => utils.toHash(list, 'asset.id')) + .then(AssetSendCtrl._getAddMoneyProcessor(this.assetId)) + .then(AssetSendCtrl._getAddMoneyProcessor(this.mirrorId)); + } + + /** + * @private + */ + _onChangeMirrorId() { + if (!this.mirrorId) { + throw new Error('Has no asset id!'); + } + + this._onChangeBaseAssets(); + + if (!this.moneyHash[this.mirrorId]) { return null; } - if (prev) { - analytics.push('Send', 'Send.ChangeCurrency', this.assetId); + this.mirror = this.moneyHash[this.mirrorId].cloneWithTokens('0'); + this._onChangeAmount(); + } + + /** + * @private + */ + _onChangeAssetId() { + if (!this.assetId) { + throw new Error('Has no asset id!'); } - this.ready = utils.whenAll([ - this._getBalanceList(), - waves.node.assets.info(this.mirrorId), - waves.node.assets.fee('transfer'), - waves.utils.getRateApi(this.assetId, this.mirrorId) - ]).then(([balance, mirrorBalance, [fee], api]) => { - this.noMirror = this.assetId === mirrorBalance.id || api.rate.eq(0); - this.amount = new BigNumber(0); - this.amountMirror = new BigNumber(0); - this.mirrorBalance = mirrorBalance; - this._setAssets(balance); - this.balance = tsUtils.find(this.moneyList, (item) => item.asset.id === this.assetId); - this.fee = fee; - }).then(() => this._updateGatewayDetails()); + this._onChangeBaseAssets(); + + if (!this.moneyHash[this.assetId]) { + return null; + } + + this.tx.amount = this.moneyHash[this.assetId].cloneWithTokens('0'); + this.mirror = this.moneyHash[this.mirrorId].cloneWithTokens('0'); + this._updateGatewayDetails(); + + analytics.push('Send', 'Send.ChangeCurrency', this.assetId); } _currentHasCommission() { @@ -198,7 +257,7 @@ const check = (feeList) => { const feeHash = utils.groupMoney(feeList); - const balanceHash = utils.toHash(this.moneyList, 'asset.id'); + const balanceHash = this.moneyHash; this.hasComission = Object.keys(feeHash).every((feeAssetId) => { const fee = feeHash[feeAssetId]; return balanceHash[fee.asset.id] && balanceHash[fee.asset.id].gt(fee); @@ -206,73 +265,58 @@ }; if (details) { - Waves.Money.fromTokens(details.gatewayFee, this.assetId).then((fee) => { - check([this.fee, fee]); - this.feeList = [this.fee, fee]; - }); + const gatewayFee = this.balance.cloneWithTokens(details.gatewayFee); + this.feeList = [this.tx.fee, gatewayFee]; + check(this.feeList); } else { - check([this.fee]); - this.feeList = [this.fee]; + this.feeList = [this.tx.fee]; + check(this.feeList); } } /** - * @return {Promise} * @private */ - _getAsset() { - return waves.node.assets.balance(this.assetId).then(({ available }) => available); + _onChangeAmount() { + if (!this._noCurrentRate && !this.noMirror && this.tx.amount && this.focus === 'amount') { + this._fillMirror(); + } } /** - * @param {Money|Money[]} money * @private */ - _setAssets(money) { - this.moneyList = utils.toArray(money); - if (!this.assetId && this.moneyList.length) { - this.assetId = this.moneyList[0].asset.id; + _onChangeAmountMirror() { + if (!this._noCurrentRate && this.mirror && this.focus === 'mirror') { + this._fillAmount(); } } - /** - * @private - */ - _onChangeAmount() { - if (this.amount && this.balance) { - this._getRate().then((api) => { - const mirrorVal = api.exchangeReverse(this.amountMirror).toFixed(this.balance.asset.precision); - if (mirrorVal !== this.amount.toFixed(this.balance.precision)) { - this.amountMirror = api.exchange(this.amount).round(this.mirrorBalance.precision); - } - }); - } + _fillMirror() { + utils.when(waves.utils.getRate(this.assetId, this.mirrorId)).then((rate) => { + const mirror = this.tx.amount.convertTo(this.moneyHash[this.mirrorId].asset, rate); + this.mirror = mirror; + }); } - /** - * @private - */ - _onChangeAmountMirror() { - if (this.amountMirror && this.mirrorBalance) { - this._getRate().then((api) => { - const amountVal = api.exchange(this.amount).toFixed(this.mirrorBalance.precision); - if (amountVal !== this.amountMirror.toFixed(this.mirrorBalance.precision)) { - this.amount = api.exchangeReverse(this.amountMirror).round(this.balance.precision); - } - }); - } + _fillAmount() { + utils.when(waves.utils.getRate(this.mirrorId, this.assetId)).then((rate) => { + const amount = this.mirror.convertTo(this.moneyHash[this.assetId].asset, rate); + this.tx.amount = amount; + }); } _updateGatewayDetails() { const outerChain = outerBlockchains[this.assetId]; - const isValidWavesAddress = waves.node.isValidAddress(this.recipient); + const isValidWavesAddress = waves.node.isValidAddress(this.tx.recipient); - this.outerSendMode = !isValidWavesAddress && outerChain && outerChain.isValidAddress(this.recipient); + this.outerSendMode = !isValidWavesAddress && outerChain && outerChain.isValidAddress(this.tx.recipient); if (this.outerSendMode) { - gatewayService.getWithdrawDetails(this.balance.asset, this.recipient).then((details) => { - this.assetKeyName = gatewayService.getAssetKeyName(this.balance.asset, 'withdraw'); + gatewayService.getWithdrawDetails(this.balance.asset, this.tx.recipient).then((details) => { + this.assetKeyName = gatewayService.getAssetKeyName(this.tx.amount.asset, 'withdraw'); this.gatewayDetails = details; + $scope.$apply(); // TODO : validate amount field for gateway minimumAmount and maximumAmount }); } else { @@ -281,31 +325,31 @@ } } - /** - * @param {string} [fromRateId] - * @return {Promise} - * @private - */ - _getRate(fromRateId) { - return waves.utils.getRateApi(fromRateId || this.assetId, this.mirrorId); + static _getAddMoneyProcessor(assetId) { + return (hash) => { + if (!hash[assetId]) { + return Waves.Money.fromTokens('0', assetId).then((money) => { + hash[assetId] = money; + return hash; + }); + } else { + return hash; + } + }; } } - return new AssetSendCtrl(this.assetId, this.baseAssetId, this.canChooseAsset); + return new AssetSendCtrl(this.assetId, this.canChooseAsset); }; controller.$inject = [ '$scope', - '$mdDialog', 'waves', 'Base', 'utils', 'user', - 'eventManager', - 'notificationManager', 'createPoll', - 'modalManager', 'outerBlockchains', 'gatewayService' ]; @@ -313,3 +357,11 @@ angular.module('app.utils') .controller('AssetSendCtrl', controller); })(); + +/** + * @typedef {object} ISendTx + * @property {Money} amount + * @property {Money} fee + * @property {string} recipient + * @property {string} attachment + */ diff --git a/src/modules/utils/modals/sendAsset/send.modal.html b/src/modules/utils/modals/sendAsset/send.modal.html index 959b664fdc..d8aef8da2b 100644 --- a/src/modules/utils/modals/sendAsset/send.modal.html +++ b/src/modules/utils/modals/sendAsset/send.modal.html @@ -7,7 +7,7 @@
-
@@ -19,9 +19,9 @@
-
@@ -42,20 +42,19 @@
- + modal.send.errors.address @@ -88,54 +87,74 @@ fee="$ctrl.feeList" input-classes="big" min="0" - amount="$ctrl.amount"> + on-focus="$ctrl.focus = 'amount'" + on-blur="$ctrl.focus = ''" + amount="$ctrl.tx.amount">
+ amount="$ctrl.mirror">
- + inputs.errors.required - - inputs.errors.invalidAsset + + inputs.errors.required + + + modal.send.errors.invalidChars + + + modal.send.errors.precision + + + modal.send.errors.precision - + modal.send.errors.max
- + + + + + modal.send.attachmentLength + +
- modal.send.fee  - - {{$ctrl.fee.asset.name}} + modal.send.fee
+ params="{fee: $ctrl.tx.fee, getawayFee: $ctrl.gatewayDetails.gatewayFee, currency: $ctrl.balance.asset.displayName}"> modal.send.validationError.notEnoughFundsWithdraw modal.send.validationError.notEnoughFunds + params="{fee: $ctrl.tx.fee}">modal.send.validationError.notEnoughFunds
@@ -153,13 +172,13 @@ + tx="$ctrl.txInfo"> + target-recipient="$ctrl.tx.recipient" + tx="$ctrl.txInfo"> diff --git a/src/modules/utils/modals/settings/settings.html b/src/modules/utils/modals/settings/settings.html index 02ba8e3010..74e44f7b88 100644 --- a/src/modules/utils/modals/settings/settings.html +++ b/src/modules/utils/modals/settings/settings.html @@ -44,17 +44,17 @@
-
+
modal.settings.security.show -
{{::$ctrl.phrase}}
+
{{::$ctrl.phrase}}
-
+
modal.settings.security.show @@ -63,26 +63,26 @@
-
+
{{::$ctrl.publicKey}}
-
+
{{::$ctrl.address}}
-
+
-
+
@@ -95,17 +95,17 @@
-
+
{{::$ctrl.appName}} {{::$ctrl.appVersion}}
-
© 2017 Waves Platform
+
© 2017 Waves Platform
diff --git a/src/modules/utils/modals/settings/settings.less b/src/modules/utils/modals/settings/settings.less index 88cee813bc..1fcb70d073 100644 --- a/src/modules/utils/modals/settings/settings.less +++ b/src/modules/utils/modals/settings/settings.less @@ -149,6 +149,16 @@ md-dialog.settings-modal { border-radius: 4px; border: 1px dashed @color-basic-200; padding: 0 15px; + overflow: auto; + + pre { + display: block; + position: absolute; + line-height: 1em; + margin: 0; + padding: 19px 0 10px 0; + top: 0; + } input { border-radius: @border-radius; diff --git a/src/modules/utils/modals/startLeasing/StartLeasingCtrl.js b/src/modules/utils/modals/startLeasing/StartLeasingCtrl.js index 1e28194efb..344b897154 100644 --- a/src/modules/utils/modals/startLeasing/StartLeasingCtrl.js +++ b/src/modules/utils/modals/startLeasing/StartLeasingCtrl.js @@ -23,7 +23,7 @@ this.title = i18n.translate('modal.startLease.title', 'app.utils'); this.assetId = WavesApp.defaultAssets.WAVES; this.recipient = ''; - this.amount = new BigNumber(0); + this.amount = null; waves.node.fee('lease') .then(([money]) => { @@ -36,17 +36,19 @@ }); } + back() { + this.step--; + } + next() { - return Waves.Money.fromTokens(this.amount, this.assetId).then((amount) => { - return waves.node.transactions.createTransaction('lease', { - recipient: this.recipient, - fee: this.fee, - amount - }); - }).then((tx) => { - this.tx = tx; - this.step++; + const tx = waves.node.transactions.createTransaction('lease', { + recipient: this.recipient, + fee: this.fee, + amount: this.amount }); + + this.tx = tx; + this.step++; } } diff --git a/src/modules/utils/modals/startLeasing/startLeasing.html b/src/modules/utils/modals/startLeasing/startLeasing.html index 6b776e5d91..a7ac4e5404 100644 --- a/src/modules/utils/modals/startLeasing/startLeasing.html +++ b/src/modules/utils/modals/startLeasing/startLeasing.html @@ -19,7 +19,8 @@ @@ -38,6 +39,7 @@ diff --git a/src/modules/utils/services/utils.js b/src/modules/utils/services/utils.js index 66443611ea..921e76e327 100644 --- a/src/modules/utils/services/utils.js +++ b/src/modules/utils/services/utils.js @@ -28,6 +28,25 @@ return _addObserverSignals(target, keys, options); }, + /** + * @name app.utils#debounce + * @param {function} handler + * @param {number} [timeout] + * @return {Function} + */ + debounce(handler, timeout) { + let timer = null; + return function (...args) { + if (timer) { + clearTimeout(timer); + } + timer = setTimeout(() => { + timer = null; + handler.call(...args); + }, timeout); + }; + }, + /** * @name app.utils#animate * @param {JQuery} $element @@ -430,7 +449,14 @@ } }; } - } + }, + + /** + * @name app.utils#isNotEqualValue + * @param {*} oldValue + * @param {*} newValue + */ + isNotEqualValue: isNotEqualValue }; function _processDecimal(decimal) { @@ -488,7 +514,7 @@ function isNotEqualValue(oldValue, newValue) { if (typeof oldValue === typeof newValue) { if (oldValue instanceof Waves.Money && newValue instanceof Waves.Money) { - return oldValue.toTokens() !== newValue.toTokens(); + return oldValue.asset.id !== newValue.asset.id || oldValue.toTokens() !== newValue.toTokens(); } else if (oldValue instanceof BigNumber && newValue instanceof BigNumber) { return !oldValue.eq(newValue); } else if (Array.isArray(oldValue) && Array.isArray(newValue)) { diff --git a/src/modules/wallet/modules/assets/templates/assets.html b/src/modules/wallet/modules/assets/templates/assets.html index 7b2c4d6eca..d5125f35ac 100644 --- a/src/modules/wallet/modules/assets/templates/assets.html +++ b/src/modules/wallet/modules/assets/templates/assets.html @@ -1,7 +1,7 @@
- - - + + + diff --git a/src/modules/wallet/modules/portfolio/templates/portfolio.html b/src/modules/wallet/modules/portfolio/templates/portfolio.html index 59c2067823..e524e276ab 100644 --- a/src/modules/wallet/modules/portfolio/templates/portfolio.html +++ b/src/modules/wallet/modules/portfolio/templates/portfolio.html @@ -1,9 +1,9 @@
- - - + + + diff --git a/src/modules/wallet/modules/transactions/less/transactions.less b/src/modules/wallet/modules/transactions/less/transactions.less index ad2e6f031d..061b7f1a2e 100644 --- a/src/modules/wallet/modules/transactions/less/transactions.less +++ b/src/modules/wallet/modules/transactions/less/transactions.less @@ -25,7 +25,7 @@ } button.download { - background: url(/img/icons/download.svg) 20px center no-repeat; + background: url(/img/icons/download.svg) 20px center no-repeat @color-white; padding-left: 40px; } diff --git a/src/modules/wallet/modules/transactions/templates/transactions.html b/src/modules/wallet/modules/transactions/templates/transactions.html index e1213a3059..581bd3c19e 100644 --- a/src/modules/wallet/modules/transactions/templates/transactions.html +++ b/src/modules/wallet/modules/transactions/templates/transactions.html @@ -22,7 +22,7 @@ - + export