├── .gitignore ├── ui ├── img │ ├── close.png │ ├── help.png │ ├── user.png │ ├── logout.png │ ├── privacy.png │ ├── arrow-down.png │ ├── arrow-left.png │ ├── icon-menu.png │ ├── iota-logo.png │ ├── arrow-right.png │ ├── icon-logout.png │ └── iota-logo-small.png ├── bower.json ├── js │ ├── iota.lightwallet.js │ ├── ui.app.js │ ├── ui.help.js │ ├── ui.url.js │ ├── ui.modals.js │ ├── ui.animation.js │ ├── ui.spam.js │ ├── ui.addresses.js │ ├── ui.pasteTrytes.js │ ├── ui.update.js │ ├── other │ │ └── loading-btn.js │ ├── ui.init.js │ ├── ui.login.js │ ├── ui.transfers.js │ └── ui.utils.js └── css │ ├── remodal-theme.css │ └── loading-btn.css ├── app ├── bower.json ├── windows │ ├── loading.html │ ├── quit.html │ ├── mac_volume.html │ ├── already_running_process.html │ ├── init_error.html │ ├── setup.html │ ├── css │ │ └── style.css │ ├── img │ │ └── spin.svg │ ├── no_java.html │ └── js │ │ ├── mac_volume.js │ │ ├── already_running_process.js │ │ ├── quit.js │ │ └── init_error.js ├── index.html ├── js │ ├── server-ipc.js │ └── ccurl-interface.js └── css │ └── style.css ├── ISSUE_TEMPLATE.md ├── README.md ├── install-deps.js ├── package.json ├── package.testnet.json └── locales ├── zh-TW └── translation.json ├── zh-CN └── translation.json ├── ko └── translation.json └── ja └── translation.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | app/bower_components 3 | ui/bower_components 4 | npm-debug.log 5 | iri/* 6 | out/* 7 | ccurl/* -------------------------------------------------------------------------------- /ui/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/close.png -------------------------------------------------------------------------------- /ui/img/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/help.png -------------------------------------------------------------------------------- /ui/img/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/user.png -------------------------------------------------------------------------------- /ui/img/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/logout.png -------------------------------------------------------------------------------- /ui/img/privacy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/privacy.png -------------------------------------------------------------------------------- /ui/img/arrow-down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/arrow-down.png -------------------------------------------------------------------------------- /ui/img/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/arrow-left.png -------------------------------------------------------------------------------- /ui/img/icon-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/icon-menu.png -------------------------------------------------------------------------------- /ui/img/iota-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/iota-logo.png -------------------------------------------------------------------------------- /ui/img/arrow-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/arrow-right.png -------------------------------------------------------------------------------- /ui/img/icon-logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/icon-logout.png -------------------------------------------------------------------------------- /ui/img/iota-logo-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iotaledger-archive/legacy-wallet-use-trinity-wallet-instead/HEAD/ui/img/iota-logo-small.png -------------------------------------------------------------------------------- /app/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iota-app", 3 | "authors": [ 4 | "Iota Foundation " 5 | ], 6 | "homepage": "https://www.iota.org/", 7 | "dependencies": { 8 | "tingle": "^0.7.0", 9 | "i18next": "^8.3.0", 10 | "i18next-xhr-backend": "^1.4.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/windows/loading.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | 18 | 19 | Loading 20 | 21 | 22 | -------------------------------------------------------------------------------- /ui/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iota-ui", 3 | "authors": [ 4 | "IOTA Foundation " 5 | ], 6 | "homepage": "https://www.iota.org/", 7 | "dependencies": { 8 | "font-awesome": "^4.6.3", 9 | "clipboard": "^1.5.10", 10 | "jquery-qrcode": "lrsjng/jquery-qrcode#^0.12.0", 11 | "jquery": "^2.2.4", 12 | "remodal": "^1.0.7", 13 | "toastr": "^2.1.2", 14 | "async": "^2.1.4", 15 | "iota.lib.js": "^0.4.7", 16 | "i18next": "^8.3.0", 17 | "i18next-xhr-backend": "^1.4.1", 18 | "jquery-i18next": "^1.2.0", 19 | "openpgp": "opengpg#^2.5.12" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/windows/quit.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

10 |

11 |
12 | 15 | 16 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /app/windows/mac_volume.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

10 |

11 |
12 | 15 | 16 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /app/windows/already_running_process.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |

10 |

11 |
12 | 16 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 | New user? Read the FAQ first! 21 |
22 | 23 | 24 | 27 | -------------------------------------------------------------------------------- /ui/js/iota.lightwallet.js: -------------------------------------------------------------------------------- 1 | var localInterruptAttachingToTangle = function(callback) { 2 | console.log("Light Wallet: localInterruptAttachingToTangle"); 3 | 4 | ccurl.ccurlInterrupt(connection.ccurlProvider); 5 | 6 | if (callback) { 7 | return callback(); 8 | } 9 | } 10 | var localAttachToTangle = function(trunkTransaction, branchTransaction, minWeightMagnitude, trytes, callback) { 11 | console.log("Light Wallet: localAttachToTangle"); 12 | 13 | ccurl.ccurlHashing(connection.ccurlProvider, trunkTransaction, branchTransaction, minWeightMagnitude, trytes, function(error, success) { 14 | console.log("Light Wallet: ccurl.ccurlHashing finished:"); 15 | if (error) { 16 | console.log(error); 17 | } else { 18 | console.log(success); 19 | } 20 | if (callback) { 21 | return callback(error, success); 22 | } else { 23 | return success; 24 | } 25 | }) 26 | } 27 | 28 | iota.api.attachToTangle = localAttachToTangle; 29 | iota.api.__proto__.attachToTangle = localAttachToTangle; 30 | iota.api.interruptAttachingToTangle = localInterruptAttachingToTangle; 31 | iota.api.__proto__.interruptAttachingToTangle = localInterruptAttachingToTangle; 32 | -------------------------------------------------------------------------------- /app/windows/init_error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |

11 |

12 |
13 |

14 | 15 |
16 |
17 |
18 | 24 | 25 | 26 | 29 | 30 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Prerequisites 2 | If you are **not** suggesting a feature, you must be able to check all of the following (place an x inside the brackets to check the box). If you cannot check all of the boxes, this issue should not be reported on GitHub as it is not a bug: 3 | 4 | * [ ] I confirm that this is an issue with the IOTA Wallet and not an exchange 5 | * [ ] I confirm that this is an issue with the wallet, not IRI 6 | * [ ] For pending transactions: I confirm that I have tried reattaching and promoting multiple times (check this box if your issue is not related to a pending transaction) 7 | * [ ] I confirm that this is not an issue related to stolen/lost funds 8 | * [ ] I confirm that this is not a zero balance issue related to a snapshot (last snapshots occurred on October 23 and January 28) 9 | * [ ] For private key warnings: I confirm that I am not at risk of reusing an address, or another user has verified that I am not (check this box if your issue is not related to a private key reuse) 10 | * [ ] I confirm that this issue is present on the latest version of the wallet 11 | 12 | 13 | ### Description 14 | 15 | [Description of the bug or feature] 16 | 17 | ### Steps to Reproduce 18 | 19 | 1. [First Step] 20 | 2. [Second Step] 21 | 3. [and so on...] 22 | 23 | **Expected behavior:** [What you expected to happen] 24 | 25 | **Actual behavior:** [What actually happened] 26 | 27 | ### Versions 28 | 29 | [OS Version] 30 | [Wallet Version] 31 | -------------------------------------------------------------------------------- /ui/js/ui.app.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.inAppInitialize = function() { 3 | console.log("UI.inAppInitialize"); 4 | window.addEventListener("message", handleAppEvents, false); 5 | 6 | // Enable status bar updating 7 | if (connection.showStatus) { 8 | UI.startStatusBarTracking(); 9 | } 10 | 11 | rendererIsReady(); 12 | } 13 | 14 | UI.startStatusBarTracking = function() { 15 | console.log("UI.startStatusBarTracking"); 16 | 17 | connection.showStatus = 1; 18 | 19 | $("body").on("mouseenter.status", ".amount", function(e) { 20 | e.preventDefault(); 21 | e.stopPropagation(); 22 | hoverAmountStart($(this).data("value")); 23 | }).on("mouseleave.status", ".amount", function(e) { 24 | e.preventDefault(); 25 | e.stopPropagation(); 26 | hoverAmountStop(); 27 | }); 28 | } 29 | 30 | UI.stopStatusBarTracking = function() { 31 | console.log("UI.stopStatusBarTracking"); 32 | 33 | connection.showStatus = 0; 34 | 35 | $("body").off("mouseenter.status"); 36 | $("body").off("mouseleave.status"); 37 | } 38 | 39 | function handleAppEvents(evt) { 40 | console.log("UI.handleAppEvents: " + evt.data); 41 | 42 | var message; 43 | 44 | if (evt.origin != "file://") { 45 | console.log("UI.handleAppEvents: Event origin != file"); 46 | return; 47 | } 48 | 49 | switch (evt.data) { 50 | case "showNodeInfo": 51 | UI.showNodeInfo(); 52 | break; 53 | case "showPeers": 54 | UI.showPeers(); 55 | break; 56 | case "hideAlerts": 57 | UI.hideAlerts(); 58 | break; 59 | default: 60 | console.log("UI.handleAppEvents: Unknown command"); 61 | break 62 | } 63 | } 64 | 65 | return UI; 66 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /ui/css/remodal-theme.css: -------------------------------------------------------------------------------- 1 | .remodal-overlay { 2 | opacity: 0; 3 | background: rgba(0, 0, 0, 0.6); 4 | } 5 | 6 | .remodal-overlay.remodal-is-opened { 7 | -webkit-transition: opacity .2s ease; 8 | transition: opacity .2s ease; 9 | opacity: 1; 10 | } 11 | 12 | .remodal-wrapper { 13 | padding: 10px 10px 0; 14 | } 15 | 16 | .remodal { 17 | -webkit-box-sizing: border-box; 18 | box-sizing: border-box; 19 | width: 100%; 20 | margin-bottom: 10px; 21 | padding: 35px; 22 | -webkit-transform: scale(0.7); 23 | -moz-transform: scale(0.7); 24 | -ms-transform: scale(0.7); 25 | transform: scale(0.7); 26 | opacity: 0; 27 | -webkit-transition: all 0.3s; 28 | -moz-transition: all 0.3s; 29 | transition: all 0.3s; 30 | color: #2b2e38; 31 | background: #fff; 32 | } 33 | 34 | .remodal-is-opened .remodal { 35 | -webkit-transform: scale(1); 36 | -moz-transform: scale(1); 37 | -ms-transform: scale(1); 38 | transform: scale(1); 39 | opacity: 1; 40 | } 41 | 42 | .remodal, 43 | .remodal-wrapper:after { 44 | vertical-align: middle; 45 | } 46 | 47 | .remodal-close { 48 | position: absolute; 49 | top: 0; 50 | left: 0; 51 | 52 | display: block; 53 | overflow: visible; 54 | 55 | width: 35px; 56 | height: 35px; 57 | margin: 0; 58 | padding: 0; 59 | 60 | cursor: pointer; 61 | text-decoration: none; 62 | 63 | color: #95979c; 64 | border: 0; 65 | outline: 0; 66 | background: transparent; 67 | } 68 | 69 | .remodal-close:hover, 70 | .remodal-close:focus { 71 | color: #2b2e38; 72 | } 73 | 74 | .remodal-close:before { 75 | font-family: Arial, "Helvetica CY", "Nimbus Sans L", sans-serif !important; 76 | font-size: 25px; 77 | line-height: 35px; 78 | 79 | position: absolute; 80 | top: 0; 81 | left: 0; 82 | 83 | display: block; 84 | 85 | width: 35px; 86 | 87 | content: "\00d7"; 88 | text-align: center; 89 | } 90 | 91 | @media only screen and (min-width: 641px) { 92 | .remodal { 93 | max-width: 700px; 94 | } 95 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IOTA App 2 | 3 | **WARNING:** This wallet is now deprecated. Please use https://github.com/iotaledger/trinity-wallet instead. 4 | 5 | ## Prerequisites 6 | 7 | 1. Download [NodeJS](https://nodejs.org/en/download/) 8 | 9 | 2. Install [Electron](http://electron.atom.io): 10 | 11 | ``` 12 | npm install -g electron 13 | ``` 14 | 15 | 3. Install [Bower](https://bower.io/): 16 | 17 | ``` 18 | npm install -g bower 19 | ``` 20 | 21 | #### Windows Users Only 22 | 23 | Run the following command as Administrator: 24 | 25 | ``` 26 | npm install -g --production windows-build-tools 27 | ``` 28 | 29 | #### Compiling 30 | 31 | If you wish to compile the app, install the following also: 32 | 33 | 1. Install [Electron Builder](https://github.com/electron-userland/electron-builder) 34 | 35 | Electron Builder is used behind the scenes. Read their [instructions](https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build) on how to set up your system. 36 | 37 | 2. Install [Docker](https://www.docker.com) 38 | 39 | ## Instructions 40 | 41 | 1. Clone this repository: 42 | 43 | ``` 44 | git clone https://github.com/iotaledger/wallet 45 | ``` 46 | 47 | 2. Go to the `wallet` directory: 48 | 49 | ``` 50 | cd wallet 51 | ``` 52 | 53 | 3. Clone iri: 54 | 55 | ``` 56 | git clone https://github.com/iotaledger/iri 57 | ``` 58 | 59 | Note: make sure compiled iri.jar is in the `iri` folder. 60 | 61 | 4. Install components 62 | 63 | ``` 64 | npm install 65 | ``` 66 | 67 | 5. Run the app: 68 | 69 | ``` 70 | npm start 71 | ``` 72 | 73 | 6. If you wish to compile the app: 74 | 75 | ``` 76 | npm run compile 77 | ``` 78 | 79 | If you'd like to create a package only for a specific OS, you can do so like this: 80 | 81 | ``` 82 | npm run compile:win 83 | npm run compile:mac 84 | npm run compile:lin 85 | ``` 86 | 87 | Compiled binaries are found in the `out` directory. 88 | 89 | #### Testnet 90 | 91 | To build testnet binaries, rename `package.testnet.json` to `package.json` and follow instructions as above. Make sure the jar is named `iri-testnet.jar`. 92 | -------------------------------------------------------------------------------- /ui/js/ui.help.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.handleHelpMenu = function() { 3 | var $help = $("#help"); 4 | var $overlay = $("#overlay"); 5 | 6 | $("#app .menu").on("click", function(e) { 7 | UI.openHelpMenu(); 8 | }); 9 | 10 | $help.find(".sections li").on("click", function(e) { 11 | var section = $(this).attr("class"); 12 | $help.css("width", "100%"); 13 | $help.find(".start").hide(); 14 | $help.find(".section[data-section='" + section + "']").fadeIn(); 15 | }); 16 | 17 | $help.find(".back").on("click", function(e) { 18 | var menuWidth = ($(document).width() <= 440 ? 300 : 400); 19 | $help.css({"left": 0, "width": menuWidth + "px"}); 20 | $help.find(".section").hide(); 21 | $help.find(".start").fadeIn(); 22 | }); 23 | 24 | $help.find("dt").on("click", function(e) { 25 | var isOpen = $(this).hasClass("open"); 26 | var $dd = $(this).next("dd"); 27 | 28 | if (isOpen) { 29 | $(this).removeClass("open"); 30 | $dd.slideUp("fast"); 31 | } else { 32 | $(this).addClass("open"); 33 | $dd.slideDown("fast"); 34 | } 35 | }); 36 | } 37 | 38 | UI.openHelpMenu = function() { 39 | var $help = $("#help"); 40 | var $overlay = $("#overlay"); 41 | 42 | if ($help.hasClass("active")) { 43 | return; 44 | } 45 | 46 | var menuWidth = ($(document).width() <= 440 ? 300 : 400); 47 | $help.css({"left": "-" + menuWidth + "px", "width": menuWidth + "px"}).addClass("active"); 48 | 49 | $overlay.show(); 50 | 51 | setTimeout(function() { 52 | $help.css("left", 0); 53 | $("#help .close, #overlay").on("click.help", function(e) { 54 | $("#help .close, #overlay").off("click.help"); 55 | $overlay.hide(); 56 | $help.addClass("closing").css({"left" :"-" + menuWidth + "px"}); 57 | $help.one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend", function(e) { 58 | if ($help.hasClass("closing")) { 59 | $help.removeClass("active closing"); 60 | } 61 | }); 62 | }); 63 | }, 10); 64 | 65 | $help.on("click", function(e) { 66 | e.stopPropagation(); 67 | }); 68 | } 69 | 70 | return UI; 71 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /app/windows/setup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 |

11 |

12 |
13 |
14 | 15 |

16 |
17 |
18 | 19 |

20 |
21 |
22 |
23 |

:

24 |

25 |

26 |

27 |
28 |
29 |

:

30 | 31 |

:

32 | 33 |

: udp://ip:12345

34 |
35 |
36 |
37 | 42 | 43 | 44 | 47 | 48 | -------------------------------------------------------------------------------- /ui/css/loading-btn.css: -------------------------------------------------------------------------------- 1 | .slider{ 2 | position:absolute; 3 | width:100%; 4 | height:6px; 5 | } 6 | 7 | .line{ 8 | position:absolute; 9 | background:#4a8df8; 10 | width:100%; 11 | height:6px; 12 | } 13 | 14 | .break{ 15 | position:absolute; 16 | background:blue; 17 | width:6px; 18 | height:6px; 19 | opacity: 0; 20 | background: #004a26; 21 | } 22 | 23 | .dot1{ 24 | -webkit-transform: translateZ(0); 25 | -webkit-animation: loading 2s infinite; 26 | -moz-animation: loading 2s infinite; 27 | -ms-animation: loading 2s infinite; 28 | -o-animation: loading 2s infinite; 29 | animation: loading 2s infinite; 30 | } 31 | 32 | .dot2{ 33 | -webkit-transform: translateZ(0); 34 | -webkit-animation: loading 2s 0.5s infinite; 35 | -moz-animation: loading 2s 0.5s infinite; 36 | -ms-animation: loading 2s 0.5s infinite; 37 | -o-animation: loading 2s 0.5s infinite; 38 | animation: loading 2s 0.5s infinite; 39 | } 40 | 41 | .dot3{ 42 | -webkit-transform: translateZ(0); 43 | -webkit-animation: loading 2s 1s infinite; 44 | -moz-animation: loading 2s 1s infinite; 45 | -ms-animation: loading 2s 1s infinite; 46 | -o-animation: loading 2s 1s infinite; 47 | animation: loading 2s 1s infinite; 48 | } 49 | 50 | .btn { 51 | position: relative; 52 | } 53 | 54 | .btn .progress { 55 | display: none; 56 | position: absolute; 57 | left: 0; 58 | right: 0; 59 | bottom: 6px; 60 | z-index:2; 61 | } 62 | 63 | .btn.loading .progress { 64 | display: block; 65 | } 66 | 67 | .btn { 68 | -webkit-transition: background 0.5s linear; 69 | -moz-transition: background 0.5s linear; 70 | -ms-transition: background 0.5s linear; 71 | -o-transition: background 0.5s linear; 72 | transition: background 0.5s linear; 73 | } 74 | 75 | .btn.error { 76 | background: #b43012 !important; 77 | color: #fff; 78 | } 79 | 80 | .btn.success { 81 | background: #1587c7 !important; 82 | color: #fff; 83 | } 84 | 85 | @keyframes loading { 86 | 0% { left: 0; opacity: 0; } 87 | 10% { opacity: 1; } 88 | 40% { opacity: 1; } 89 | 100% { left: 99%; opacity: 0;} 90 | } 91 | 92 | @-webkit-keyframes loading { 93 | 0% { left: 0; opacity: 0; } 94 | 10% { opacity: 1; } 95 | 40% { opacity: 1; } 96 | 100% { left: 99%; opacity: 0;} 97 | } 98 | 99 | @-moz-keyframes loading { 100 | 0% { left: 0; opacity: 0; } 101 | 10% { opacity: 1; } 102 | 40% { opacity: 1; } 103 | 100% { left: 99%; opacity: 0;} 104 | } 105 | @-ms-keyframes loading { 106 | 0% { left: 0; opacity: 0; } 107 | 10% { opacity: 1; } 108 | 40% { opacity: 1; } 109 | 100% { left: 99%; opacity: 0;} 110 | } 111 | @-o-keyframes loading { 112 | 0% { left: 0; opacity: 0; } 113 | 10% { opacity: 1; } 114 | 40% { opacity: 1; } 115 | 100% { left: 99%; opacity: 0;} 116 | } -------------------------------------------------------------------------------- /ui/js/ui.url.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.handleURL = function(url) { 3 | if (url == "faq" || url == "help") { 4 | UI.openHelpMenu(); 5 | } else if (!connection.seed) { 6 | UI.notify("error", "please_log_in_first"); 7 | connection.handleURL = url; 8 | } else { 9 | if (!url) { 10 | url = connection.handleURL; 11 | connection.handleURL = false; 12 | } 13 | if (url == "history") { 14 | var $stack = $("#history-stack"); 15 | 16 | if (!$stack.hasClass("open")) { 17 | $stack.trigger("click"); 18 | } 19 | } else if (url == "generateaddress" || url == "generate-address" || url == "address") { 20 | var $stack = $("#generate-address-stack"); 21 | 22 | if (!$stack.hasClass("open")) { 23 | $stack.trigger("click"); 24 | } 25 | } else if (url == "balance") { 26 | var $stack = $("#balance-stack"); 27 | 28 | if (!$stack.hasClass("open")) { 29 | $stack.trigger("click"); 30 | } 31 | } else if (url == "transfer") { 32 | var $stack = $("#transfer-stack"); 33 | 34 | if (!$stack.hasClass("open")) { 35 | $stack.trigger("click"); 36 | } 37 | } else { 38 | var match = url.match(/(?:transfer|send)\/([A-Z9]{90})\/([0-9\.]+)\-?([TGMK]?i)?(\/.*)?$/i); 39 | var submatch = false; 40 | 41 | if (match && match[1] && match[2]) { 42 | if (match[4]) { 43 | submatch = match[4].match(/^\/([A-Z9]{1,27})\/?$/i); 44 | if (!submatch) { 45 | UI.notify("error", "ignoring_invalid_tag_value"); 46 | return; 47 | } 48 | } 49 | 50 | if ($("#transfer-address").val() || $("#transfer-amount").val() || (submatch && submatch[1] && $("#transfer-tag").val())) { 51 | UI.notify("error", "wont_overwrite_transfer_fields"); 52 | } else { 53 | UI.notify("success", "transfer_fields_prefilled_link"); 54 | 55 | $("#transfer-address").val(match[1].toUpperCase()); 56 | $("#transfer-amount").val(match[2]); 57 | $("#transfer-autofill").val("1"); 58 | 59 | if (!match[3] || match[3] == "i") { 60 | $("#transfer-units-value").html("i"); 61 | } else { 62 | $("#transfer-units-value").html(match[3].charAt(0).toUpperCase() + match[3].charAt(1).toLowerCase()); 63 | } 64 | 65 | if (submatch && submatch[1]) { 66 | $("#transfer-tag").val(submatch[1].toUpperCase()); 67 | } 68 | var $stack = $("#transfer-stack"); 69 | 70 | if (!$stack.hasClass("open")) { 71 | $stack.trigger("click"); 72 | } 73 | } 74 | } else { 75 | UI.notify("error", "unknown_or_invalid_url"); 76 | } 77 | } 78 | } 79 | } 80 | 81 | return UI; 82 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /app/windows/css/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html, 6 | body { 7 | margin: 0; 8 | padding: 0; 9 | } 10 | 11 | body { 12 | font-size: 16px; 13 | line-height: 1.5; 14 | background-color: #fff; 15 | font-family: 'Source Sans Pro', sans-serif; 16 | } 17 | 18 | #message { 19 | border: 1px solid gray; 20 | padding: 10px; 21 | background: #efefef; 22 | } 23 | 24 | .content { 25 | padding: 20px; 26 | } 27 | 28 | #footer { 29 | position: absolute; 30 | bottom: 0; 31 | left: 0; 32 | right: 0; 33 | padding: 20px; 34 | background-color: #f1f1f1; 35 | } 36 | 37 | .btn { 38 | display: inline-block; 39 | margin: 0 5px; 40 | padding: 10px 20px; 41 | border: none; 42 | background-color: grey; 43 | box-shadow: none; 44 | color: #fff; 45 | vertical-align: middle; 46 | text-decoration: none; 47 | font-size: inherit; 48 | font-family: inherit; 49 | line-height: normal; 50 | cursor: pointer; 51 | } 52 | 53 | .btn-primary { 54 | background-color: #3498db; 55 | } 56 | 57 | .btn-danger { 58 | background-color: #e74c3c; 59 | } 60 | 61 | .btn-default { 62 | background-color: #34495e; 63 | } 64 | 65 | .btn-choice { 66 | background-color: #a9a9a9; 67 | } 68 | 69 | .btn[disabled] { 70 | cursor: not-allowed; 71 | opacity: 0.65; 72 | } 73 | 74 | .btn-pull-left { 75 | float: left; 76 | } 77 | 78 | .btn-pull-right { 79 | float: right; 80 | } 81 | 82 | h1 { 83 | margin: 0; 84 | margin-bottom: 20px; 85 | font-size: 30px; 86 | line-height: 1.5; 87 | } 88 | 89 | p:last-child { 90 | margin-bottom: 0; 91 | } 92 | 93 | a, 94 | a:hover, 95 | a:visited { 96 | color: #07C; 97 | text-decoration: underline; 98 | } 99 | 100 | #message > span { 101 | display: none; 102 | } 103 | 104 | #edit-launch-arguments-section, #server-output-section { 105 | display: none; 106 | } 107 | 108 | #server-output, #nodes { 109 | width: 100%; 110 | background: #000; 111 | color: #fff; 112 | height: 120px; 113 | font-family: courier; 114 | font-size: 16px; 115 | } 116 | 117 | #nodes { 118 | background: #ccc; 119 | color: #000; 120 | } 121 | 122 | p.label { 123 | margin-bottom: 5px; 124 | margin-top: 5px; 125 | font-weight: bold; 126 | } 127 | 128 | p.note { 129 | font-size: 85%; 130 | font-style: italic; 131 | color: darkgray; 132 | margin-top: 0; 133 | margin-bottom: 0; 134 | } 135 | 136 | .fadein { 137 | animation: fadein 3s; 138 | } 139 | 140 | @keyframes fadein { 141 | from { opacity: 0; } 142 | to { opacity: 1; } 143 | } 144 | 145 | .two-columns { 146 | display: table; 147 | height: 100%; 148 | width: 100%; 149 | } 150 | 151 | .two-columns > div { 152 | display: table-cell; 153 | height: 100%; 154 | width: 50%; 155 | padding: 10px; 156 | } 157 | 158 | .two-columns > div:first-child { 159 | border-right: 1px solid #cccccc; 160 | } 161 | 162 | .error { 163 | display: none; 164 | color: red; 165 | } -------------------------------------------------------------------------------- /app/windows/img/spin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /install-deps.js: -------------------------------------------------------------------------------- 1 | const https = require('follow-redirects').https; 2 | const fs = require("fs"); 3 | const URL = require("url"); 4 | const path = require("path"); 5 | 6 | console.log("Fetching ccurl dependencies...");; 7 | 8 | var paths = ["ccurl", "ccurl/win64", "ccurl/lin64", "ccurl/mac"]; 9 | 10 | for (var i=0; i"; 19 | } else { 20 | var nrNeighbors = parseInt(neighbors.length, 10); 21 | 22 | for (var i=0; i
" + UI.format(value) + "
"; 29 | }); 30 | 31 | html += ""; 32 | 33 | if (i" + UI.t("neighbors", nrNeighbors) + "
" + html + "
"); 40 | } else { 41 | var $modal = $("#peers-modal"); 42 | 43 | $("h1#neighbors").localize(nrNeighbors); 44 | 45 | $modal.find(".contents").html(html); 46 | 47 | var modal = $modal.remodal({hashTracking: false}); 48 | modal.open(); 49 | } 50 | } 51 | }); 52 | } 53 | 54 | UI.showNodeInfo = function(callback) { 55 | console.log("UI.showNodeInfo"); 56 | 57 | if (!callback && UI.isLocked) { 58 | console.log("UI.showNodeInfo: UI is locked"); 59 | return; 60 | } 61 | 62 | iota.api.getNodeInfo(function(error, info) { 63 | if (error) { 64 | return (callback ? callback(error) : error); 65 | } 66 | 67 | var html = "
    "; 68 | 69 | $.each(info, function(key, value) { 70 | if (key != "duration") { 71 | html += "
  • " + UI.format(key) + "
    " + UI.format(value) + "
  • "; 72 | } 73 | }); 74 | 75 | html += "
"; 76 | 77 | if (callback) { 78 | callback(null, "node-info-modal", "

" + UI.t("node_info") + "

" + html + "
"); 79 | } else { 80 | var $modal = $("#node-info-modal"); 81 | 82 | $modal.find(".contents").html(html); 83 | 84 | var modal = $modal.remodal({hashTracking: false}); 85 | modal.open(); 86 | } 87 | }); 88 | } 89 | 90 | return UI; 91 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iota", 3 | "productName": "IOTA Wallet", 4 | "description": "IOTA Wallet", 5 | "version": "2.5.7", 6 | "license": "GPL-3.0", 7 | "main": "app/js/main.js", 8 | "scripts": { 9 | "postinstall": "electron-builder install-app-deps && node install-deps.js && cd app && bower install && cd ../ui && bower install", 10 | "start": "export NODE_ENV=development || set NODE_ENV=development && electron app/js/main.js", 11 | "precompile": "rimraf out/* && node install-deps.js", 12 | "compile": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --win --mac --linux --x64 --ia32", 13 | "compile:lin": "electron-builder --linux --x64 --ia32", 14 | "compile:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64", 15 | "compile:win": "electron-builder --win --x64 --ia32", 16 | "compile:win64": "electron-builder --win --x64", 17 | "compile:win32": "electron-builder --win --x32", 18 | "prepublish": "rimraf out/*", 19 | "publish": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --win --mac --linux --x64 --ia32 --publish always", 20 | "publish:lin": "electron-builder --linux --x64 --ia32 --publish always", 21 | "publish:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64 --publish always", 22 | "publish:win": "electron-builder --win --x64 --ia32 --publish always" 23 | }, 24 | "author": "IOTA Foundation ", 25 | "homepage": "https://www.iota.org", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/iotaledger/wallet" 29 | }, 30 | "dependencies": { 31 | "core-util-is": "^1.0.2", 32 | "curl.lib.js": "^1.0.22", 33 | "ffi": "^2.2.0", 34 | "fs-extra": "^1.0.0", 35 | "glob": "^7.1.2", 36 | "i18next": "^8.4.2", 37 | "i18next-sync-fs-backend": "^0.1.0", 38 | "pidusage": "^1.1.5" 39 | }, 40 | "devDependencies": { 41 | "electron": "1.7.11", 42 | "electron-builder": "^19.37.2", 43 | "follow-redirects": "^1.2.4", 44 | "rimraf": "^2.6.1" 45 | }, 46 | "build": { 47 | "directories": { 48 | "buildResources": "build", 49 | "output": "out" 50 | }, 51 | "publish": [ 52 | "github" 53 | ], 54 | "appId": "com.iotatoken.wallet", 55 | "extraResources": [ 56 | "iri/iri.jar", 57 | "ccurl/**/*", 58 | "ui/**/*", 59 | "locales/**/*" 60 | ], 61 | "protocols": [ 62 | { 63 | "name": "IOTA URL Scheme", 64 | "schemes": [ 65 | "iota" 66 | ] 67 | } 68 | ], 69 | "dmg": { 70 | "iconSize": 125, 71 | "contents": [ 72 | { 73 | "x": 235, 74 | "y": 290, 75 | "type": "link", 76 | "path": "/Applications" 77 | }, 78 | { 79 | "x": 235, 80 | "y": 20, 81 | "type": "file" 82 | } 83 | ] 84 | }, 85 | "win": { 86 | "target": "nsis" 87 | }, 88 | "linux": { 89 | "target": [ 90 | "AppImage", 91 | "deb", 92 | "rpm", 93 | "tar.gz" 94 | ] 95 | }, 96 | "mac": { 97 | "category": "public.app-category.developer-tools" 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /package.testnet.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "iota-testnet", 3 | "productName": "IOTA Wallet Testnet", 4 | "description": "IOTA Wallet Testnet", 5 | "version": "2.5.7-testnet", 6 | "license": "GPL-3.0", 7 | "main": "app/js/main.js", 8 | "scripts": { 9 | "postinstall": "electron-builder install-app-deps && node install-deps.js && cd app && bower install && cd ../ui && bower install", 10 | "start": "export NODE_ENV=development || set NODE_ENV=development && electron app/js/main.js", 11 | "precompile": "rimraf out/* && node install-deps.js", 12 | "compile": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --win --mac --linux --x64 --ia32", 13 | "compile:lin": "electron-builder --linux --x64 --ia32", 14 | "compile:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64", 15 | "compile:win": "electron-builder --win --x64 --ia32", 16 | "compile:win64": "electron-builder --win --x64", 17 | "compile:win32": "electron-builder --win --x32", 18 | "prepublish": "rimraf out/*", 19 | "publish": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --win --mac --linux --x64 --ia32 --publish always", 20 | "publish:lin": "electron-builder --linux --x64 --ia32 --publish always", 21 | "publish:mac": "export CSC_IDENTITY_AUTO_DISCOVERY=false && electron-builder --mac --x64 --publish always", 22 | "publish:win": "electron-builder --win --x64 --ia32 --publish always" 23 | }, 24 | "author": "IOTA Foundation ", 25 | "homepage": "https://www.iota.org", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/iotaledger/wallet" 29 | }, 30 | "dependencies": { 31 | "curl.lib.js": "^1.0.22", 32 | "ffi": "^2.2.0", 33 | "fs-extra": "^1.0.0", 34 | "glob": "^7.1.2", 35 | "i18next": "^8.4.2", 36 | "i18next-sync-fs-backend": "^0.1.0", 37 | "pidusage": "^1.1.5" 38 | }, 39 | "devDependencies": { 40 | "electron": "1.7.11", 41 | "electron-builder": "^19.13.0", 42 | "follow-redirects": "^1.2.4", 43 | "rimraf": "^2.6.1" 44 | }, 45 | "build": { 46 | "directories": { 47 | "buildResources": "build", 48 | "output": "out" 49 | }, 50 | "publish": [ 51 | "github" 52 | ], 53 | "appId": "com.iotatoken.wallet-testnet", 54 | "extraResources": [ 55 | "iri/iri-testnet.jar", 56 | "ccurl/**/*", 57 | "ui/**/*", 58 | "locales/**/*" 59 | ], 60 | "protocols": [ 61 | { 62 | "name": "IOTA URL Scheme", 63 | "schemes": [ 64 | "iota" 65 | ] 66 | } 67 | ], 68 | "dmg": { 69 | "iconSize": 125, 70 | "contents": [ 71 | { 72 | "x": 235, 73 | "y": 290, 74 | "type": "link", 75 | "path": "/Applications" 76 | }, 77 | { 78 | "x": 235, 79 | "y": 20, 80 | "type": "file" 81 | } 82 | ] 83 | }, 84 | "win": { 85 | "target": "nsis" 86 | }, 87 | "linux": { 88 | "target": [ 89 | "AppImage", 90 | "deb", 91 | "rpm", 92 | "tar.gz" 93 | ] 94 | }, 95 | "mac": { 96 | "category": "public.app-category.developer-tools" 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/windows/no_java.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 68 | 69 | 70 |
71 |

72 |

73 | 74 | () 75 | 76 | 77 | 78 | 79 | 80 |

81 | sudo apt-get install openjdk-8-jre 82 |

83 | 84 |

85 | sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer
86 |
87 | su -c "yum install java-1.8.0-openjdk" 88 | 89 |
90 | 91 |

92 |
93 |
94 |
95 |
96 | 101 | 102 | 103 | 106 | 107 | -------------------------------------------------------------------------------- /ui/js/ui.animation.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.applyGradientAnimation = function(element, colors) { 3 | var step = 0; 4 | var colorIndices = [0,1,2,3]; 5 | var gradientSpeed = 0.002; 6 | 7 | function updateGradient() { 8 | var c0_0 = colors[colorIndices[0]]; 9 | var c0_1 = colors[colorIndices[1]]; 10 | var c1_0 = colors[colorIndices[2]]; 11 | var c1_1 = colors[colorIndices[3]]; 12 | 13 | var istep = 1 - step; 14 | var r1 = Math.round(istep * c0_0[0] + step * c0_1[0]); 15 | var g1 = Math.round(istep * c0_0[1] + step * c0_1[1]); 16 | var b1 = Math.round(istep * c0_0[2] + step * c0_1[2]); 17 | var color1 = "rgb("+r1+","+g1+","+b1+")"; 18 | 19 | var r2 = Math.round(istep * c1_0[0] + step * c1_1[0]); 20 | var g2 = Math.round(istep * c1_0[1] + step * c1_1[1]); 21 | var b2 = Math.round(istep * c1_0[2] + step * c1_1[2]); 22 | var color2 = "rgb("+r2+","+g2+","+b2+")"; 23 | 24 | $(element).css({ 25 | background: "-webkit-gradient(linear, left top, right top, from("+color1+"), to("+color2+"))"}).css({ 26 | background: "-moz-linear-gradient(left, "+color1+" 0%, "+color2+" 100%)"}); 27 | 28 | step += gradientSpeed; 29 | 30 | if (step >= 1) { 31 | step %= 1; 32 | colorIndices[0] = colorIndices[1]; 33 | colorIndices[2] = colorIndices[3]; 34 | 35 | colorIndices[1] = ( colorIndices[1] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length; 36 | colorIndices[3] = ( colorIndices[3] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length; 37 | } 38 | } 39 | 40 | return setInterval(updateGradient,10); 41 | } 42 | 43 | UI.animateStacks = function(delay) { 44 | var $openStack = $(".stack.open"); 45 | 46 | var documentHeight = $(document).height(); 47 | var documentWidth = $(document).width(); 48 | 49 | if (documentHeight <= 582 || documentWidth <= 414) { 50 | var headerHeight = 51; 51 | } else if (documentHeight <= 735 || documentWidth <= 519) { 52 | var headerHeight = 61; 53 | } else { 54 | var headerHeight = 81; 55 | } 56 | 57 | var neededHeight = $openStack.find(".inner").outerHeight(); 58 | 59 | //console.log("needed height = " + neededHeight); 60 | 61 | var windowHeight = $(window).height() - headerHeight; 62 | var leftOverHeight = windowHeight - neededHeight; 63 | 64 | //console.log("left over height: " + leftOverHeight); 65 | 66 | var closedStackHeight = leftOverHeight / 3; 67 | 68 | //console.log("closed stack height: " + closedStackHeight); 69 | 70 | var positions = {}; 71 | 72 | positions["balance-stack"] = [0, 0]; 73 | positions["transfer-stack"] = [headerHeight+neededHeight, headerHeight+windowHeight-neededHeight-closedStackHeight*2]; 74 | positions["generate-address-stack"] = [headerHeight+neededHeight+closedStackHeight, headerHeight+windowHeight-neededHeight-closedStackHeight]; 75 | positions["history-stack"] = [headerHeight+neededHeight+closedStackHeight*2, headerHeight+windowHeight-neededHeight]; 76 | 77 | var foundOpen = false; 78 | 79 | $(".stack").each(function() { 80 | var stack = $(this).attr("id"); 81 | var change = null; 82 | 83 | if ($(this).hasClass("open")) { 84 | change = positions[stack][1]; 85 | foundOpen = true; 86 | } else { 87 | var field = (!foundOpen ? $(this).data("higher") : $(this).data("lower")); 88 | if (field) { 89 | change = positions[stack][(field == "closed" ? 0 : 1)]; 90 | } 91 | } 92 | if (change) { 93 | $(this).animate({"top": change + "px", "bottom": 0}, delay); 94 | } 95 | }); 96 | } 97 | 98 | return UI; 99 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /app/windows/js/mac_volume.js: -------------------------------------------------------------------------------- 1 | const electron = require("electron"); 2 | const path = require("path"); 3 | 4 | var isDevelopment = String(process.env.NODE_ENV).trim() === "development"; 5 | var resourcesDirectory = isDevelopment ? "../../" : "../../../"; 6 | 7 | var __entityMap = { 8 | "&": "&", 9 | "<": "<", 10 | ">": ">", 11 | '"': '"', 12 | "'": ''', 13 | "/": '/' 14 | }; 15 | 16 | String.prototype.escapeHTML = function() { 17 | return String(this).replace(/[&<>"'\/]/g, function(s) { 18 | return __entityMap[s]; 19 | }); 20 | } 21 | 22 | var UI = (function(UI, undefined) { 23 | UI.initialize = function() { 24 | document.getElementById("quit-btn").addEventListener("click", function(e) { 25 | electron.ipcRenderer.send("quit"); 26 | }); 27 | } 28 | 29 | UI.showContextMenu = function(e) { 30 | var template = [ 31 | { 32 | label: UI.t("cut"), 33 | accelerator: "CmdOrCtrl+X", 34 | role: "cut", 35 | }, 36 | { 37 | label: UI.t("copy"), 38 | accelerator: "CmdOrCtrl+C", 39 | role: "copy" 40 | }, 41 | { 42 | label: UI.t("paste"), 43 | accelerator: "CmdOrCtrl+V", 44 | role: "paste" 45 | } 46 | ]; 47 | 48 | const menu = electron.remote.Menu.buildFromTemplate(template); 49 | menu.popup(electron.remote.getCurrentWindow(), e.x, e.y); 50 | } 51 | 52 | UI.show = function() { 53 | UI.updateContentSize(); 54 | 55 | document.body.addEventListener("contextmenu", UI.showContextMenu, false); 56 | 57 | setTimeout(function() { 58 | electron.remote.getCurrentWindow().show(); 59 | }, 20); 60 | } 61 | 62 | UI.updateContentSize = function() { 63 | electron.remote.getCurrentWindow().setContentSize(600, parseInt(document.documentElement.scrollHeight, 10) + parseInt(document.getElementById("footer").scrollHeight, 10), false); 64 | } 65 | 66 | UI.makeMultilingual = function(currentLanguage, callback) { 67 | i18n = i18next 68 | .use(window.i18nextXHRBackend) 69 | .init({ 70 | lng: currentLanguage, 71 | fallbackLng: "en", 72 | backend: { 73 | loadPath: path.join(resourcesDirectory, "locales", "{{lng}}", "{{ns}}.json") 74 | }, 75 | debug: false 76 | }, function(err, t) { 77 | updateUI(); 78 | callback(); 79 | }); 80 | } 81 | 82 | UI.t = function(message, options) { 83 | if (message.match(/^[a-z\_]+$/i)) { 84 | return UI.format(i18n.t(message, options)); 85 | } else { 86 | return UI.format(message); 87 | } 88 | } 89 | 90 | UI.format = function(text) { 91 | return String(text).escapeHTML(); 92 | } 93 | 94 | UI.changeLanguage = function(language, callback) { 95 | i18n.changeLanguage(language, function(err, t) { 96 | updateUI(); 97 | if (callback) { 98 | callback(); 99 | } 100 | }); 101 | } 102 | 103 | UI.changeElementLanguage = function(el, key) { 104 | document.getElementById(el).innerHTML = UI.t(key); 105 | document.getElementById(el).setAttribute("data-i18n", key.match(/^[a-z\_]+$/i ? key : "")); 106 | } 107 | 108 | function updateUI() { 109 | var i18nList = document.querySelectorAll('[data-i18n]'); 110 | i18nList.forEach(function(v){ 111 | if (v.dataset.i18n) { 112 | v.innerHTML = UI.t(v.dataset.i18n, v.dataset.i18nOptions); 113 | } 114 | }); 115 | } 116 | 117 | return UI; 118 | }(UI || {})); 119 | 120 | window.addEventListener("load", UI.initialize, false); 121 | 122 | electron.ipcRenderer.on("show", function(event, params) { 123 | UI.makeMultilingual(params.language, function() { 124 | UI.show(params); 125 | }); 126 | }); 127 | 128 | electron.ipcRenderer.on("changeLanguage", function(event, language) { 129 | UI.changeLanguage(language, function() { 130 | UI.updateContentSize(); 131 | }); 132 | }); -------------------------------------------------------------------------------- /ui/js/ui.spam.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | var spamCount = 0; 3 | 4 | var validTrytes = '9ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 5 | var spamTag = ''; 6 | 7 | for (var i = 0; i < 27; i++) { 8 | 9 | spamTag += validTrytes[ Math.floor( Math.random() * 27 + 0 ) ]; 10 | 11 | } 12 | 13 | UI.showNetworkSpammer = function() { 14 | /* 15 | if (connection.isProofOfWorking) { 16 | UI.notify("error", "Proof of work is busy, cannot spam."); 17 | return; 18 | }*/ 19 | 20 | $("#spam-cnt").html("0"); 21 | 22 | var $modal = $("#spam-modal"); 23 | 24 | var modal = $modal.remodal({hashTracking: false, closeOnOutsideClick: false, closeOnEscape: false}); 25 | modal.open(); 26 | } 27 | 28 | UI.handleNetworkSpamming = function() { 29 | var isSpamming = false; 30 | 31 | $(document).on("closed", "#spam-modal", function (e) { 32 | if (isSpamming) { 33 | isSpamming = false; 34 | $("#spam-btn").loadingReset("spam_the_network"); 35 | iota.api.interruptAttachingToTangle(function() { 36 | console.log("Attaching to tangle was interrupted."); 37 | }); 38 | } 39 | }); 40 | 41 | $("#spam-btn").on("click", function(e) { 42 | isSpamming = true; 43 | spamCount = 0; 44 | 45 | e.preventDefault(); 46 | 47 | console.log("start spam"); 48 | console.log("Your spam tag is: ", spamTag); 49 | 50 | async.doWhilst(function(callback) { 51 | console.log("send async transfer"); 52 | 53 | iota.api.getNodeInfo(function(error, nodeInfo) { 54 | 55 | if (error) { 56 | console.log("we have error: " + error); 57 | if (isSpamming) { 58 | $("#spam-msg").html(UI.format(error)).show(); 59 | } else { 60 | $("#spam-msg").hide(); 61 | } 62 | } 63 | 64 | // check if synced 65 | if (nodeInfo.latestSolidSubtangleMilestoneIndex === nodeInfo.latestMilestoneIndex) { 66 | 67 | iota.api.sendTransfer("999999999999999999999999999999999999999999999999999999999999999999999999999999999", connection.depth, connection.minWeightMagnitude, [{"address": "999999999999999999999999999999999999999999999999999999999999999999999999999999999", "value": 0, "tag": spamTag}], function(error) { 68 | if (!error) { 69 | console.log("no error"); 70 | spamCount++; 71 | $("#spam-cnt").html(spamCount); 72 | $("#spam-msg").hide(); 73 | } else { 74 | console.log("we have error: " + error); 75 | if (isSpamming) { 76 | $("#spam-msg").html(UI.format(error)).show(); 77 | } else { 78 | $("#spam-msg").hide(); 79 | } 80 | } 81 | 82 | // 1sec delay for each spam 83 | setTimeout(function() { 84 | callback(null); 85 | }, 1000) 86 | 87 | }); 88 | 89 | } else { 90 | 91 | console.log("You are not synced, cannot spam! Retrying in 30secs"); 92 | // 5sec delay for each spam 93 | setTimeout(function() { 94 | callback(null); 95 | }, 30000) 96 | } 97 | }) 98 | 99 | }, function() { 100 | return isSpamming == true; 101 | }, function() { 102 | console.log("Stopped spamming"); 103 | }); 104 | }); 105 | } 106 | 107 | return UI; 108 | }(UI || {}, jQuery)); 109 | -------------------------------------------------------------------------------- /ui/js/ui.addresses.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | var hasGenerated = false; 3 | 4 | UI.onOpenAddressStack = function() { 5 | if (hasGenerated) { 6 | return; 7 | } 8 | 9 | var $stack = $("#generate-address-stack"); 10 | 11 | var $loader = $stack.find(".loading-ring"); 12 | var $result = $stack.find(".padded"); 13 | var $btn = $stack.find(".btn").first(); 14 | 15 | $loader.hide(); 16 | 17 | var latestAddress = iota.utils.addChecksum(connection.accountData.latestAddress); 18 | 19 | if (latestAddress != $btn.data("address")) { 20 | updateGeneratedAddress(latestAddress, true); 21 | 22 | $btn.loadingUpdate("attach_to_tangle", {"noIcon": true, "initial": "attach_to_tangle", "loading": "attaching_to_tangle"}); 23 | 24 | UI.animateStacks(0); 25 | } 26 | } 27 | 28 | UI.handleAddressGeneration = function() { 29 | $("#generate-address-btn").on("click", function(e) { 30 | e.preventDefault(); 31 | e.stopPropagation(); 32 | 33 | hasGenerated = true; 34 | 35 | var $stack = $("#generate-address-stack"); 36 | 37 | var $loader = $stack.find(".loading-ring"); 38 | var $result = $stack.find(".padded"); 39 | var $btn = $stack.find(".btn").first(); 40 | 41 | $stack.addClass("loading"); 42 | 43 | try { 44 | var gotAddress = $btn.data("address"); 45 | 46 | if (!gotAddress) { 47 | $result.css("visibility", "hidden"); 48 | $loader.css("bottom", $btn.outerHeight() + 10).show(); 49 | } else { 50 | $loader.hide(); 51 | } 52 | 53 | UI.isDoingPOW = true; 54 | 55 | iota.api.getNewAddress(connection.seed, {"checksum": true}, function(error, newAddress) { 56 | $loader.fadeOut(); 57 | 58 | if (error) { 59 | console.log(error); 60 | UI.formError("generate-address", error); 61 | $stack.removeClass("loading"); 62 | UI.isDoingPOW = false; 63 | return; 64 | } 65 | 66 | if (newAddress != $btn.data("address")) { 67 | updateGeneratedAddress(newAddress); 68 | $result.css("opacity", 0).css("visibility", "visible").fadeTo("slow", 1); 69 | } else { 70 | $result.css("visibility", "visible"); 71 | } 72 | 73 | newAddress = iota.utils.noChecksum(newAddress); 74 | 75 | UI.animateStacks(200); 76 | 77 | iota.api.sendTransfer(connection.seed, connection.depth, connection.minWeightMagnitude, [{"address": newAddress, "value": 0, "message": "", "tag": ""}], function(error, transfers) { 78 | UI.isDoingPOW = false; 79 | if (error) { 80 | UI.formError("generate-address", error); 81 | } else { 82 | $btn.data("address", ""); 83 | console.log("UI.handleAddressGeneration: Attached to Tangle"); 84 | UI.formSuccess("generate-address", "address_attached", {"initial": "generate_new_address", "loading": "attaching_to_tangle"}); 85 | UI.updateState(1000); 86 | } 87 | $stack.removeClass("loading"); 88 | }); 89 | }); 90 | } catch (error) { 91 | console.log(error); 92 | UI.formError("generate-address", error); 93 | } 94 | }); 95 | } 96 | 97 | function updateGeneratedAddress(address, notYetGenerated) { 98 | var $stack = $("#generate-address-stack"); 99 | var $btn = $stack.find(".btn").first(); 100 | 101 | address = UI.format(address); 102 | 103 | $btn.data("address", address); 104 | 105 | if ($(document).height() <= 620 || $(document).width() <= 440) { 106 | var qrCodeSize = 110; 107 | } else { 108 | var qrCodeSize = 150; 109 | } 110 | 111 | $("#generate-address-result").html(address); 112 | $("#generate-address-qr-code").empty().qrcode({text: JSON.stringify({"address": address}), fill: "#000", background: "#fff", size: qrCodeSize}); 113 | 114 | $stack.find(".clipboard").attr("data-clipboard-text", address); 115 | } 116 | 117 | return UI; 118 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /app/windows/js/already_running_process.js: -------------------------------------------------------------------------------- 1 | const electron = require("electron"); 2 | const path = require("path"); 3 | 4 | var isDevelopment = String(process.env.NODE_ENV).trim() === "development"; 5 | var resourcesDirectory = isDevelopment ? "../../" : "../../../"; 6 | 7 | var __entityMap = { 8 | "&": "&", 9 | "<": "<", 10 | ">": ">", 11 | '"': '"', 12 | "'": ''', 13 | "/": '/' 14 | }; 15 | 16 | String.prototype.escapeHTML = function() { 17 | return String(this).replace(/[&<>"'\/]/g, function(s) { 18 | return __entityMap[s]; 19 | }); 20 | } 21 | 22 | var UI = (function(UI, undefined) { 23 | UI.initialize = function() { 24 | document.getElementById("quit-btn").addEventListener("click", function(e) { 25 | electron.remote.getCurrentWindow().close(); 26 | }); 27 | 28 | document.getElementById("continue-btn").addEventListener("click", function(e) { 29 | var btns = document.getElementsByClassName("btn"); 30 | for (var i=0; i": ">", 11 | '"': '"', 12 | "'": ''', 13 | "/": '/' 14 | }; 15 | 16 | String.prototype.escapeHTML = function() { 17 | return String(this).replace(/[&<>"'\/]/g, function(s) { 18 | return __entityMap[s]; 19 | }); 20 | } 21 | 22 | var UI = (function(UI, undefined) { 23 | UI.initialize = function() { 24 | document.getElementById("quit-btn").addEventListener("click", function(e) { 25 | electron.ipcRenderer.send("quit"); 26 | }); 27 | } 28 | 29 | UI.showContextMenu = function(e) { 30 | var template = [ 31 | { 32 | label: UI.t("cut"), 33 | accelerator: "CmdOrCtrl+X", 34 | role: "cut", 35 | }, 36 | { 37 | label: UI.t("copy"), 38 | accelerator: "CmdOrCtrl+C", 39 | role: "copy" 40 | }, 41 | { 42 | label: UI.t("paste"), 43 | accelerator: "CmdOrCtrl+V", 44 | role: "paste" 45 | } 46 | ]; 47 | 48 | const menu = electron.remote.Menu.buildFromTemplate(template); 49 | menu.popup(electron.remote.getCurrentWindow(), e.x, e.y); 50 | } 51 | 52 | UI.show = function(params) { 53 | if (params) { 54 | if (params.title) { 55 | UI.changeElementLanguage("title", params.title); 56 | document.getElementById("title").style.display = "block"; 57 | } else { 58 | document.getElementById("title").style.display = "none"; 59 | } 60 | if (params.message) { 61 | UI.changeElementLanguage("message", params.message); 62 | document.getElementById("message").style.display = "block"; 63 | } else { 64 | document.getElementById("message").style.display = "none"; 65 | } 66 | } 67 | 68 | UI.updateContentSize(); 69 | 70 | document.body.addEventListener("contextmenu", UI.showContextMenu, false); 71 | 72 | setTimeout(function() { 73 | electron.remote.getCurrentWindow().show(); 74 | }, 20); 75 | } 76 | 77 | UI.updateContentSize = function() { 78 | electron.remote.getCurrentWindow().setContentSize(600, parseInt(document.documentElement.scrollHeight, 10) + parseInt(document.getElementById("footer").scrollHeight, 10), false); 79 | } 80 | 81 | UI.makeMultilingual = function(currentLanguage, callback) { 82 | i18n = i18next 83 | .use(window.i18nextXHRBackend) 84 | .init({ 85 | lng: currentLanguage, 86 | fallbackLng: "en", 87 | backend: { 88 | loadPath: path.join(resourcesDirectory, "locales", "{{lng}}", "{{ns}}.json") 89 | }, 90 | debug: false 91 | }, function(err, t) { 92 | updateUI(); 93 | callback(); 94 | }); 95 | } 96 | 97 | UI.t = function(message, options) { 98 | if (message.match(/^[a-z\_]+$/i)) { 99 | return UI.format(i18n.t(message, options)); 100 | } else { 101 | return UI.format(message); 102 | } 103 | } 104 | 105 | UI.format = function(text) { 106 | return String(text).escapeHTML(); 107 | } 108 | 109 | UI.changeLanguage = function(language, callback) { 110 | i18n.changeLanguage(language, function(err, t) { 111 | updateUI(); 112 | if (callback) { 113 | callback(); 114 | } 115 | }); 116 | } 117 | 118 | UI.changeElementLanguage = function(el, key) { 119 | document.getElementById(el).innerHTML = UI.t(key); 120 | document.getElementById(el).setAttribute("data-i18n", key.match(/^[a-z\_]+$/i ? key : "")); 121 | } 122 | 123 | function updateUI() { 124 | var i18nList = document.querySelectorAll('[data-i18n]'); 125 | i18nList.forEach(function(v){ 126 | if (v.dataset.i18n) { 127 | v.innerHTML = UI.t(v.dataset.i18n, v.dataset.i18nOptions); 128 | } 129 | }); 130 | } 131 | 132 | return UI; 133 | }(UI || {})); 134 | 135 | window.addEventListener("load", UI.initialize, false); 136 | 137 | electron.ipcRenderer.on("show", function(event, params) { 138 | UI.makeMultilingual(params.language, function() { 139 | UI.show(params); 140 | }); 141 | }); 142 | 143 | electron.ipcRenderer.on("changeLanguage", function(event, language) { 144 | UI.changeLanguage(language, function() { 145 | UI.updateContentSize(); 146 | }); 147 | }); -------------------------------------------------------------------------------- /ui/js/ui.pasteTrytes.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | var isProcessing = false; 3 | 4 | UI.showPasteTrytes = function(callback) { 5 | console.log("UI.showPasteTrytes"); 6 | 7 | if (UI.isLocked) { 8 | console.log("UI.showPasteTrytes: UI is locked"); 9 | return; 10 | } else if (!connection.seed) { 11 | UI.notify("error", "please_log_in_first"); 12 | return; 13 | } 14 | 15 | $("#paste-trytes-modal h1").html("Paste Trytes"); 16 | $("#process-trytes, #pasted-trytes").val(""); 17 | $("#paste-trytes-group").show(); 18 | $("#process-trytes-group").hide(); 19 | 20 | $("#pasted-trytes").focus(); 21 | 22 | var $modal = $("#paste-trytes-modal"); 23 | 24 | var modal = $modal.remodal({hashTracking: false, closeOnOutsideClick: false, closeOnEscape: false}); 25 | modal.open(); 26 | } 27 | 28 | function parseTrytesToBundle(trytes) { 29 | var bundleTxs = []; 30 | 31 | if (iota.valid.isTrytes(trytes)) { 32 | var bundle = [trytes]; 33 | } else { 34 | try { 35 | var bundle = JSON.parse(trytes); 36 | } catch (err) { 37 | bundle = null; 38 | } 39 | } 40 | 41 | var trytesError = false; 42 | 43 | if ($.isArray(bundle)) { 44 | $.each(bundle, function(index, trytes) { 45 | if (!iota.valid.isTrytes(trytes)) { 46 | trytesError = true; 47 | return false; 48 | } else { 49 | var transaction = iota.utils.transactionObject(trytes); 50 | if (transaction) { 51 | bundleTxs.push(transaction); 52 | } else { 53 | trytesError = true; 54 | return false; 55 | } 56 | } 57 | }); 58 | } 59 | 60 | if (trytesError || !bundleTxs || bundleTxs.length == 0) { 61 | return false; 62 | } 63 | 64 | return bundleTxs; 65 | } 66 | 67 | UI.handlePastingTrytes = function() { 68 | $(document).on("closed", "#paste-trytes-modal", function (e) { 69 | if (isProcessing) { 70 | isProcessing = false; 71 | $("#process-pasted-trytes-btn").loadingReset("process_trytes"); 72 | iota.api.interruptAttachingToTangle(); 73 | } 74 | }); 75 | 76 | $("#verify-pasted-trytes-btn").on("click", function(e) { 77 | var trytes = $("#pasted-trytes").val(); 78 | 79 | var bundleTxs = parseTrytesToBundle($("#pasted-trytes").val()); 80 | 81 | if (!bundleTxs) { 82 | $("#verify-pasted-trytes-btn").loadingError("invalid_trytes_or_input", {"initial": "verify_trytes"}); 83 | return; 84 | } else if (!iota.utils.isBundle(bundleTxs)) { 85 | $("#verify-pasted-trytes-btn").loadingError("invalid_signature", {"initial": "process_trytes"}); 86 | return; 87 | } 88 | 89 | var html = "
    "; 90 | 91 | for (var i=0; i
" + UI.formatAmount(bundleTxs[i].value) + "
"; 93 | } 94 | 95 | html += ""; 96 | 97 | $("#process-trytes").html(html); 98 | $("#paste-trytes-modal h1").html(UI.t("verify_trytes")); 99 | $("#process-trytes-group").show(); 100 | $("#paste-trytes-group").hide(); 101 | $("#process-pasted-trytes-completed").val(0); 102 | 103 | $("#verify-pasted-trytes-btn").loadingReset("verify_trytes"); 104 | }); 105 | 106 | $("#process-pasted-trytes-btn").on("click", function(e) { 107 | var bundleTxs = parseTrytesToBundle($("#pasted-trytes").val()); 108 | 109 | if ($("#process-pasted-trytes-completed").val() == 1) { 110 | $("#process-pasted-trytes-btn").loadingError("already_processed", {"initial": "process_trytes"}); 111 | return; 112 | } else if (!bundleTxs) { 113 | $("#process-pasted-trytes-btn").loadingError("invalid_trytes_or_input", {"initial": "process_trytes"}); 114 | return; 115 | } else if (!iota.utils.isBundle(bundleTxs)) { 116 | $("#process-pasted-trytes-btn").loadingError("invalid_signature", {"initial": "process_trytes"}); 117 | return; 118 | } 119 | 120 | var trytes = []; 121 | 122 | $.each(bundleTxs, function(index, transaction) { 123 | trytes.push(iota.utils.transactionTrytes(transaction)); 124 | }); 125 | 126 | trytes = trytes.reverse(); 127 | 128 | console.log(trytes); 129 | 130 | isProcessing = true; 131 | 132 | UI.isDoingPOW = true; 133 | iota.api.sendTrytes(trytes, connection.depth, connection.minWeightMagnitude, function(error, transfers) { 134 | UI.isDoingPOW = false; 135 | if (error) { 136 | console.log("Process Pasted Trytes: Error"); 137 | console.log(error); 138 | $("#process-pasted-trytes-btn").loadingError(error); 139 | } else { 140 | console.log("Process Pasted Trytes: Success"); 141 | $("#process-pasted-trytes-btn").loadingSuccess("transaction_completed"); 142 | $("#process-pasted-trytes-completed").val(1); 143 | UI.updateState(1000); 144 | } 145 | }); 146 | }); 147 | } 148 | 149 | return UI; 150 | }(UI || {}, jQuery)); -------------------------------------------------------------------------------- /ui/js/ui.update.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.updateIntervalTime = 0; 3 | UI.isDoingPOW = false; 4 | 5 | var isUpdatingState = false; 6 | var updateInterval = null; 7 | 8 | var stopStateInterval = false; 9 | 10 | UI.resetState = function(timeout) { 11 | console.log("UI.resetState"); 12 | 13 | if (!connection.seed) { 14 | UI.loginFormShown = false; 15 | } 16 | UI.initializationTime = new Date().getTime(); 17 | UI.initialConnection = false; 18 | isUpdatingState = false; 19 | UI.updateState(timeout); 20 | } 21 | 22 | UI.updateState = function(timeout) { 23 | console.log("UI.updateState: " + timeout); 24 | 25 | if (timeout) { 26 | setTimeout(function() { 27 | UI.createStateInterval(UI.updateIntervalTime, true); 28 | }, timeout); 29 | } else { 30 | UI.createStateInterval(UI.updateIntervalTime, true); 31 | } 32 | } 33 | 34 | UI.createStateInterval = function(ms, immediately) { 35 | if (stopStateInterval) { 36 | return; 37 | } 38 | // If connecting to a light wallet, minimum state interval is set to 1 minute. 39 | if (connection.lightWallet && ms < 60000) { 40 | ms = 60000; 41 | } 42 | 43 | UI.updateIntervalTime = ms; 44 | 45 | if (updateInterval) { 46 | clearTimeout(updateInterval); 47 | } 48 | 49 | if (immediately) { 50 | ms = 0; 51 | } 52 | 53 | console.log("UI.createStateInterval: " + UI.updateIntervalTime + ", " + ms); 54 | console.log(new Date()); 55 | 56 | updateInterval = setTimeout(function() { 57 | console.log("In update interval: " + isUpdatingState + ", " + UI.isLoggingIn + ", " + UI.isDoingPOW); 58 | console.log(new Date()); 59 | 60 | if (!isUpdatingState && !UI.isLoggingIn && !UI.isDoingPOW) { 61 | isUpdatingState = true; 62 | 63 | console.log("Execute interval"); 64 | 65 | iota.api.getNodeInfo(function(error, info) { 66 | connection.nodeInfo = info; 67 | 68 | console.log("Got node info"); 69 | console.log(new Date()); 70 | 71 | if (connection.seed) { 72 | iota.api.getAccountData(connection.seed, function(error, accountData) { 73 | console.log("Got account data"); 74 | console.log(new Date()); 75 | 76 | if (!error) { 77 | connection.previousAccountData = connection.accountData; 78 | connection.accountData = accountData; 79 | } 80 | 81 | isUpdatingState = false; 82 | 83 | UI.createStateInterval(UI.updateIntervalTime); 84 | if (!error) { 85 | UI.update(); 86 | } 87 | }); 88 | } else { 89 | if (error && connection.lightWallet) { 90 | //Show error specifically for light nodes... 91 | UI.notify("error", "could_not_connect_to_remote_node"); 92 | $("#error-btn").addClass("no-connection"); 93 | if (!connection.seed) { 94 | UI.showLoginForm = true; 95 | } 96 | } 97 | UI.createStateInterval(UI.updateIntervalTime); 98 | isUpdatingState = false; 99 | UI.update(); 100 | } 101 | }); 102 | } else { 103 | console.log("Skipping update interval"); 104 | } 105 | }, ms); 106 | } 107 | 108 | UI.stopStateInterval = function() { 109 | clearTimeout(updateInterval); 110 | stopStateInterval = true; 111 | } 112 | 113 | UI.startStateInterval = function() { 114 | stopStateInterval = false; 115 | } 116 | 117 | UI.update = function() { 118 | if (!UI.initialConnection && connection.nodeInfo) { 119 | console.log("We have an initial connection."); 120 | UI.initialConnection = true; 121 | if (connection.nodeInfo.appName.match(/testnet/i)) { 122 | connection.testNet = true; 123 | if (connection.minWeightMagnitude < 9) { 124 | connection.minWeightMagnitude = 9; 125 | } 126 | } else if (connection.minWeightMagnitude < 14) { 127 | connection.minWeightMagnitude = 14; 128 | } 129 | if (connection.inApp && connection.lightWallet) { 130 | updateAppInfo({"name": connection.nodeInfo.appName, "version": connection.nodeInfo.appVersion, "testnet": connection.testNet}); 131 | } 132 | $(document).trigger("initialConnection"); 133 | if (!connection.seed) { 134 | // After initial connection, update state every 2 seconds 135 | UI.createStateInterval(2000, false); 136 | } 137 | } 138 | 139 | if (connection.nodeInfo && connection.inApp && connection.lightWallet) { 140 | var data = {}; 141 | if (connection.nodeInfo.latestSolidSubtangleMilestoneIndex) { 142 | data.latestSolidSubtangleMilestoneIndex = connection.nodeInfo.latestSolidSubtangleMilestoneIndex; 143 | } 144 | if (connection.nodeInfo.latestMilestoneIndex) { 145 | data.latestMilestoneIndex = connection.nodeInfo.latestMilestoneIndex; 146 | } 147 | updateStatusBar(data); 148 | } 149 | 150 | if (!connection.seed) { 151 | if (!UI.showLoginForm) { 152 | UI.showLoginForm = true; 153 | } else if (!UI.loginFormShown) { 154 | UI.fadeInLoginForm(); 155 | } else { 156 | UI.updateLoginForm(); 157 | } 158 | } else { 159 | if (connection.accountData) { 160 | UI.updateBalance(); 161 | } 162 | 163 | UI.updateHistory(); 164 | } 165 | } 166 | 167 | return UI; 168 | }(UI || {}, jQuery)); 169 | -------------------------------------------------------------------------------- /app/js/server-ipc.js: -------------------------------------------------------------------------------- 1 | const ipcRenderer = require("electron").ipcRenderer; 2 | const clipboard = require("electron").clipboard; 3 | 4 | var ccurl = false; 5 | 6 | var isLightWallet = require("electron").remote.getGlobal("lightWallet"); 7 | 8 | //only load for light wallets 9 | if (isLightWallet) { 10 | try { 11 | ccurl = require("./ccurl-interface"); 12 | } catch (err) { 13 | alert(err); 14 | ccurl = false; 15 | } 16 | } 17 | 18 | ipcRenderer.on("showNodeInfo", function() { 19 | if (typeof(UI) != "undefined") { 20 | if (!UI.initialConnection) { 21 | UI.notify("error", (isLightWallet ? "could_not_connect_to_remote_node" : "could_not_connect_to_node")); 22 | } else { 23 | UI.showNodeInfo(function(error, identifier, html) { 24 | if (!error) { 25 | ipcRenderer.send("showModal", identifier, html); 26 | } else { 27 | UI.notify("error", error); 28 | } 29 | }); 30 | } 31 | } 32 | }); 33 | 34 | ipcRenderer.on("showPeers", function() { 35 | if (typeof(UI) != "undefined") { 36 | if (!UI.initialConnection) { 37 | UI.notify("error", (isLightWallet ? "could_not_connect_to_remote_node" : "could_not_connect_to_node")); 38 | } else { 39 | UI.showPeers(function(error, identifier, html) { 40 | if (!error) { 41 | ipcRenderer.send("showModal", identifier, html); 42 | } else { 43 | UI.notify("error", error); 44 | } 45 | }); 46 | } 47 | } 48 | }); 49 | 50 | ipcRenderer.on("showFAQ", function() { 51 | if (typeof(UI) != "undefined") { 52 | UI.openHelpMenu(); 53 | } 54 | }); 55 | 56 | ipcRenderer.on("showNetworkSpammer", function() { 57 | if (typeof(UI) != "undefined") { 58 | UI.showNetworkSpammer(); 59 | } 60 | }); 61 | 62 | ipcRenderer.on("pasteTrytes", function() { 63 | if (typeof(UI) != "undefined") { 64 | UI.showPasteTrytes(); 65 | } 66 | }); 67 | 68 | ipcRenderer.on("hideAlerts", function() { 69 | if (typeof(UI) != "undefined") { 70 | UI.hideAlerts(); 71 | } 72 | }); 73 | 74 | ipcRenderer.on("setFocus", function(event, focus) { 75 | if (typeof(UI) != "undefined") { 76 | UI.hasFocus = focus; 77 | } 78 | }); 79 | 80 | ipcRenderer.on("toggleStatusBar", function(event, show) { 81 | if (typeof(UI) != "undefined") { 82 | if (show) { 83 | UI.startStatusBarTracking(); 84 | } else { 85 | UI.stopStatusBarTracking(); 86 | } 87 | } 88 | }); 89 | 90 | ipcRenderer.on("hideStatusBar", function() { 91 | if (typeof(UI) != "undefined") { 92 | UI.stopStatusBarTracking(); 93 | } 94 | }); 95 | 96 | ipcRenderer.on("notify", function(event, type, message, options) { 97 | if (typeof(UI) != "undefined") { 98 | UI.notify(type, message, options); 99 | } 100 | }); 101 | 102 | ipcRenderer.on("changeLanguage", function(event, language) { 103 | if (typeof(UI) != "undefined") { 104 | UI.changeLanguage(language); 105 | } 106 | }); 107 | 108 | ipcRenderer.on("handleURL", function(event, url) { 109 | if (typeof(UI) != "undefined") { 110 | UI.handleURL(url); 111 | } 112 | }); 113 | 114 | ipcRenderer.on("openHelpMenu", function() { 115 | if (typeof(UI) != "undefined") { 116 | UI.openHelpMenu(); 117 | } 118 | }); 119 | 120 | ipcRenderer.on("shutdown", function() { 121 | if (typeof(UI) != "undefined") { 122 | UI.shutdown(); 123 | } 124 | }); 125 | 126 | ipcRenderer.on("updateSettings", function(event, settings) { 127 | UI.updateSettings(settings); 128 | }); 129 | 130 | ipcRenderer.on("stopCcurl", function(event, callback) { 131 | console.log("in stopCcurl renderer"); 132 | if (ccurl && connection.ccurlProvider) { 133 | console.log("calling ccurlInterruptAndFinalize with " + connection.ccurlProvider); 134 | ccurl.ccurlInterruptAndFinalize(connection.ccurlProvider); 135 | } 136 | 137 | console.log("Calling relaunchApplication"); 138 | ipcRenderer.send("relaunchApplication", true); 139 | }); 140 | 141 | ipcRenderer.on('showRecovery', function(event, callback) { 142 | console.log('enter recovery tool') 143 | if (typeof(UI) !== "undefined") { 144 | UI.showRecoveryModal() 145 | } 146 | }) 147 | 148 | function _hoverAmountStart(amount) { 149 | ipcRenderer.send("hoverAmountStart", amount); 150 | } 151 | 152 | function _hoverAmountStop() { 153 | ipcRenderer.send("hoverAmountStop"); 154 | } 155 | 156 | function _editNodeConfiguration() { 157 | ipcRenderer.send("editNodeConfiguration"); 158 | } 159 | 160 | function _rendererIsReady() { 161 | ipcRenderer.send("rendererIsReady", process.pid); 162 | } 163 | 164 | function _relaunchApplication() { 165 | ipcRenderer.send("relaunchApplication"); 166 | } 167 | 168 | function _updateStatusBar(data) { 169 | ipcRenderer.send("updateStatusBar", data); 170 | } 171 | 172 | function _updateAppInfo(data) { 173 | ipcRenderer.send("updateAppInfo", data); 174 | } 175 | 176 | function _clearSeedFromClipboard(seed) { 177 | if (clipboard.readText() == seed) { 178 | clipboard.clear(); 179 | } 180 | } 181 | 182 | /* 183 | function _logUINotification(type, message) { 184 | ipcRenderer.send("logUINotification", type, message); 185 | } 186 | */ 187 | 188 | process.once("loaded", function() { 189 | global.backendLoaded = true; 190 | global.updateStatusBar = _updateStatusBar; 191 | global.hoverAmountStart = _hoverAmountStart; 192 | global.hoverAmountStop = _hoverAmountStop; 193 | global.editNodeConfiguration = _editNodeConfiguration; 194 | global.rendererIsReady = _rendererIsReady; 195 | global.relaunchApplication = _relaunchApplication; 196 | global.updateAppInfo = _updateAppInfo; 197 | global.clearSeedFromClipboard = _clearSeedFromClipboard; 198 | 199 | if (typeof(ccurl) != "undefined") { 200 | global.ccurl = ccurl; 201 | } 202 | //global.logUINotification = _logUINotification; 203 | }); 204 | -------------------------------------------------------------------------------- /app/js/ccurl-interface.js: -------------------------------------------------------------------------------- 1 | var ffi = require('ffi'); 2 | var isInitialized = false; 3 | 4 | let libcurl = require('curl.lib.js'); 5 | let webglAvailable = false; 6 | try { 7 | libcurl.init(); 8 | webglAvailable = true; 9 | } catch (e) {} 10 | const MAX_TIMESTAMP_VALUE = (Math.pow(3,27) - 1) / 2; 11 | 12 | var ccurlProvider = function(ccurlPath) { 13 | if (!ccurlPath) { 14 | console.log("ccurl-interface: no path supplied, returning"); 15 | return false; 16 | } 17 | 18 | var fullPath = ccurlPath + '/libccurl'; 19 | 20 | try { 21 | // Define libccurl to be used for finding the nonce 22 | var libccurl = ffi.Library(fullPath, { 23 | ccurl_pow : [ 'string', [ 'string', 'int'] ], 24 | ccurl_pow_finalize : [ 'void', [] ], 25 | ccurl_pow_interrupt: [ 'void', [] ] 26 | }); 27 | 28 | // Check to make sure the functions are available 29 | if (!libccurl.hasOwnProperty("ccurl_pow") || !libccurl.hasOwnProperty("ccurl_pow_finalize") || !libccurl.hasOwnProperty("ccurl_pow_interrupt")) { 30 | throw new Error("Could not load hashing library."); 31 | } 32 | 33 | return libccurl; 34 | } catch (err) { 35 | console.log(err); 36 | return false; 37 | } 38 | } 39 | 40 | var ccurlFinalize = function(libccurl) { 41 | if (isInitialized) { 42 | try { 43 | if (libccurl && libccurl.hasOwnProperty("ccurl_pow_finalize")) { 44 | libccurl.ccurl_pow_finalize(); 45 | } 46 | } catch (err) { 47 | console.log(err); 48 | } 49 | } 50 | } 51 | 52 | var ccurlInterrupt = function(libccurl) { 53 | if (isInitialized) { 54 | try { 55 | if(connection.ccurl && libccurl && libccurl.hasOwnProperty("ccurl_pow_interrupt")) { 56 | libccurl.ccurl_pow_interrupt(); 57 | } else { 58 | libcurl.interrupt(); 59 | } 60 | } catch (err) { 61 | console.log(err); 62 | } 63 | } 64 | } 65 | 66 | var ccurlInterruptAndFinalize = function(libccurl) { 67 | ccurlInterrupt(libccurl); 68 | ccurlFinalize(libccurl); 69 | } 70 | 71 | var ccurlHashing = function(libccurl, trunkTransaction, branchTransaction, minWeightMagnitude, trytes, callback) { 72 | if (!libccurl.hasOwnProperty("ccurl_pow")) { 73 | return callback(new Error("Hashing not available")); 74 | } 75 | 76 | var iotaObj = iota; 77 | 78 | // inputValidator: Check if correct hash 79 | if (!iotaObj.valid.isHash(trunkTransaction)) { 80 | 81 | return callback(new Error("Invalid trunkTransaction")); 82 | } 83 | 84 | // inputValidator: Check if correct hash 85 | if (!iotaObj.valid.isHash(branchTransaction)) { 86 | 87 | return callback(new Error("Invalid branchTransaction")); 88 | } 89 | 90 | // inputValidator: Check if int 91 | if (!iotaObj.valid.isValue(minWeightMagnitude)) { 92 | 93 | return callback(new Error("Invalid minWeightMagnitude")); 94 | } 95 | 96 | // inputValidator: Check if array of trytes 97 | // if (!iotaObj.valid.isArrayOfTrytes(trytes)) { 98 | // 99 | // return callback(new Error("Invalid trytes supplied")); 100 | // } 101 | 102 | isInitialized = true; 103 | 104 | var finalBundleTrytes = []; 105 | var previousTxHash; 106 | var i = 0; 107 | 108 | function loopTrytes() { 109 | 110 | getBundleTrytes(trytes[i], function(error) { 111 | 112 | if (error) { 113 | 114 | return callback(error); 115 | 116 | } else { 117 | 118 | i++; 119 | 120 | if (i < trytes.length) { 121 | 122 | loopTrytes(); 123 | 124 | } else { 125 | 126 | // reverse the order so that it's ascending from currentIndex 127 | return callback(null, finalBundleTrytes.reverse()); 128 | 129 | } 130 | } 131 | }); 132 | } 133 | 134 | function getBundleTrytes(thisTrytes, callback) { 135 | // PROCESS LOGIC: 136 | // Start with last index transaction 137 | // Assign it the trunk / branch which the user has supplied 138 | // IF there is a bundle, chain the bundle transactions via 139 | // trunkTransaction together 140 | 141 | var txObject = iotaObj.utils.transactionObject(thisTrytes); 142 | txObject.tag = txObject.tag || txObject.obsoleteTag; 143 | txObject.attachmentTimestamp = Date.now(); 144 | txObject.attachmentTimestampLowerBound = 0; 145 | txObject.attachmentTimestampUpperBound = MAX_TIMESTAMP_VALUE; 146 | // If this is the first transaction, to be processed 147 | // Make sure that it's the last in the bundle and then 148 | // assign it the supplied trunk and branch transactions 149 | if (!previousTxHash) { 150 | 151 | 152 | // Check if last transaction in the bundle 153 | if (txObject.lastIndex !== txObject.currentIndex) { 154 | return callback(new Error("Wrong bundle order. The bundle should be ordered in descending order from currentIndex")); 155 | } 156 | 157 | txObject.trunkTransaction = trunkTransaction; 158 | txObject.branchTransaction = branchTransaction; 159 | } else { 160 | // Chain the bundle together via the trunkTransaction (previous tx in the bundle) 161 | // Assign the supplied trunkTransaciton as branchTransaction 162 | txObject.trunkTransaction = previousTxHash; 163 | txObject.branchTransaction = trunkTransaction; 164 | } 165 | 166 | var newTrytes = iotaObj.utils.transactionTrytes(txObject); 167 | 168 | switch (connection.ccurl) { 169 | case 0: { 170 | libcurl.pow({trytes: newTrytes, minWeight: minWeightMagnitude}).then(function(nonce) { 171 | var returnedTrytes = newTrytes.substr(0, 2673-81).concat(nonce); 172 | var newTxObject= iotaObj.utils.transactionObject(returnedTrytes); 173 | 174 | // Assign the previousTxHash to this tx 175 | var txHash = newTxObject.hash; 176 | previousTxHash = txHash; 177 | 178 | finalBundleTrytes.push(returnedTrytes); 179 | callback(null); 180 | }).catch(callback); 181 | break; 182 | } 183 | default: { 184 | // cCurl updates the nonce as well as the transaction hash 185 | libccurl.ccurl_pow.async(newTrytes, minWeightMagnitude, function(error, returnedTrytes) { 186 | 187 | if (error) { 188 | return callback(error); 189 | } else if (returnedTrytes == null) { 190 | return callback("Interrupted"); 191 | } 192 | 193 | var newTxObject= iotaObj.utils.transactionObject(returnedTrytes); 194 | 195 | // Assign the previousTxHash to this tx 196 | var txHash = newTxObject.hash; 197 | previousTxHash = txHash; 198 | 199 | finalBundleTrytes.push(returnedTrytes); 200 | 201 | return callback(null); 202 | }); 203 | } 204 | } 205 | } 206 | loopTrytes(); 207 | } 208 | 209 | module.exports = { 210 | 'ccurlProvider': ccurlProvider, 211 | 'ccurlHashing': ccurlHashing, 212 | 'ccurlInterrupt': ccurlInterrupt, 213 | 'ccurlFinalize': ccurlFinalize, 214 | 'ccurlInterruptAndFinalize': ccurlInterruptAndFinalize 215 | } 216 | -------------------------------------------------------------------------------- /app/windows/js/init_error.js: -------------------------------------------------------------------------------- 1 | const electron = require("electron"); 2 | const path = require("path"); 3 | 4 | var isDevelopment = String(process.env.NODE_ENV).trim() === "development"; 5 | var resourcesDirectory = isDevelopment ? "../../" : "../../../"; 6 | 7 | var __entityMap = { 8 | "&": "&", 9 | "<": "<", 10 | ">": ">", 11 | '"': '"', 12 | "'": ''', 13 | "/": '/' 14 | }; 15 | 16 | String.prototype.escapeHTML = function() { 17 | return String(this).replace(/[&<>"'\/]/g, function(s) { 18 | return __entityMap[s]; 19 | }); 20 | } 21 | 22 | var UI = (function(UI, undefined) { 23 | var isLightWallet = false; 24 | 25 | UI.initialize = function() { 26 | document.getElementById("quit-btn").addEventListener("click", function(e) { 27 | document.getElementById("quit-btn").disabled = true; 28 | document.getElementById("restart-btn").disabled = true; 29 | document.getElementById("settings-btn").disabled = true; 30 | document.getElementById("download-java-btn").disabled = true; 31 | 32 | electron.ipcRenderer.send("quit"); 33 | }); 34 | document.getElementById("restart-btn").addEventListener("click", function(e) { 35 | document.getElementById("quit-btn").disabled = true; 36 | document.getElementById("restart-btn").disabled = true; 37 | document.getElementById("settings-btn").disabled = true; 38 | document.getElementById("download-java-btn").disabled = true; 39 | 40 | UI.relaunchApplication(); 41 | }); 42 | document.getElementById("download-java-btn").addEventListener("click", function(e) { 43 | document.getElementById("quit-btn").disabled = true; 44 | document.getElementById("restart-btn").disabled = true; 45 | document.getElementById("settings-btn").disabled = true; 46 | document.getElementById("download-java-btn").disabled = true; 47 | 48 | UI.showNoJavaInstalledWindow(); 49 | }); 50 | document.getElementById("settings-btn").addEventListener("click", function(e) { 51 | document.getElementById("quit-btn").disabled = true; 52 | document.getElementById("restart-btn").disabled = true; 53 | document.getElementById("settings-btn").disabled = true; 54 | document.getElementById("download-java-btn").disabled = true; 55 | 56 | UI.showSetupWindow(isLightWallet ? "light-node" : "full-node"); 57 | }); 58 | } 59 | 60 | UI.showContextMenu = function(e) { 61 | var template = [ 62 | { 63 | label: UI.t("cut"), 64 | accelerator: "CmdOrCtrl+X", 65 | role: "cut", 66 | }, 67 | { 68 | label: UI.t("copy"), 69 | accelerator: "CmdOrCtrl+C", 70 | role: "copy" 71 | }, 72 | { 73 | label: UI.t("paste"), 74 | accelerator: "CmdOrCtrl+V", 75 | role: "paste" 76 | } 77 | ]; 78 | 79 | const menu = electron.remote.Menu.buildFromTemplate(template); 80 | menu.popup(electron.remote.getCurrentWindow(), e.x, e.y); 81 | } 82 | 83 | UI.show = function(params) { 84 | if (params) { 85 | isLightWallet = params.lightWallet == 1; 86 | if (params.title) { 87 | document.getElementById("title").innerHTML = UI.format(params.title); 88 | document.getElementById("title").style.display = "block"; 89 | } else { 90 | document.getElementById("title").style.display = "none"; 91 | } 92 | if (params.message) { 93 | document.getElementById("message").innerHTML = UI.format(params.message); 94 | document.getElementById("message").style.display = "block"; 95 | } else { 96 | document.getElementById("message").style.display = "none"; 97 | } 98 | 99 | if (params.serverOutput && params.serverOutput.length) { 100 | var log = params.serverOutput.join("\n"); 101 | log = log.replace(/\n\s*\n/g, "\n"); 102 | 103 | if (!log || params.serverOutput.length == 1) { 104 | log = UI.t("no_server_output"); 105 | } 106 | 107 | document.getElementById("server-output").value = log; 108 | document.getElementById("server-output-section").style.display = "block"; 109 | //document.getElementById("server-output").scrollTop = document.getElementById("server-output").scrollHeight; 110 | } else { 111 | document.getElementById("server-output-section").style.display = "none"; 112 | } 113 | } 114 | 115 | UI.updateContentSize(); 116 | 117 | document.body.addEventListener("contextmenu", UI.showContextMenu, false); 118 | 119 | setTimeout(function() { 120 | electron.remote.getCurrentWindow().show(); 121 | }, 20); 122 | } 123 | 124 | UI.showNoJavaInstalledWindow = function() { 125 | electron.ipcRenderer.send("showNoJavaInstalledWindow", {"downloadImmediatelyIfWindows": true}); 126 | } 127 | 128 | UI.relaunchApplication = function() { 129 | electron.ipcRenderer.send("relaunchApplication"); 130 | } 131 | 132 | UI.showSetupWindow = function(section) { 133 | electron.ipcRenderer.send("showSetupWindow", {"section": section}); 134 | } 135 | 136 | UI.updateContentSize = function() { 137 | electron.remote.getCurrentWindow().setContentSize(600, parseInt(document.documentElement.scrollHeight, 10) + parseInt(document.getElementById("footer").scrollHeight, 10), false); 138 | } 139 | 140 | UI.makeMultilingual = function(currentLanguage, callback) { 141 | i18n = i18next 142 | .use(window.i18nextXHRBackend) 143 | .init({ 144 | lng: currentLanguage, 145 | fallbackLng: "en", 146 | backend: { 147 | loadPath: path.join(resourcesDirectory, "locales", "{{lng}}", "{{ns}}.json") 148 | }, 149 | debug: false 150 | }, function(err, t) { 151 | updateUI(); 152 | callback(); 153 | }); 154 | } 155 | 156 | UI.t = function(message, options) { 157 | if (message.match(/^[a-z\_]+$/i)) { 158 | return UI.format(i18n.t(message, options)); 159 | } else { 160 | return UI.format(message); 161 | } 162 | } 163 | 164 | UI.format = function(text) { 165 | return String(text).escapeHTML(); 166 | } 167 | 168 | UI.changeLanguage = function(language, callback) { 169 | i18n.changeLanguage(language, function(err, t) { 170 | updateUI(); 171 | if (callback) { 172 | callback(); 173 | } 174 | }); 175 | } 176 | 177 | UI.changeElementLanguage = function(el, key) { 178 | document.getElementById(el).innerHTML = UI.t(key); 179 | document.getElementById(el).setAttribute("data-i18n", key.match(/^[a-z\_]+$/i ? key : "")); 180 | } 181 | 182 | function updateUI() { 183 | var i18nList = document.querySelectorAll('[data-i18n]'); 184 | i18nList.forEach(function(v){ 185 | if (v.dataset.i18n) { 186 | v.innerHTML = UI.t(v.dataset.i18n, v.dataset.i18nOptions); 187 | } 188 | }); 189 | } 190 | 191 | return UI; 192 | }(UI || {})); 193 | 194 | window.addEventListener("load", UI.initialize, false); 195 | 196 | electron.ipcRenderer.on("show", function(event, params) { 197 | UI.makeMultilingual(params.language, function() { 198 | UI.show(params); 199 | }); 200 | }); 201 | 202 | electron.ipcRenderer.on("changeLanguage", function(event, language) { 203 | UI.changeLanguage(language, function() { 204 | UI.updateContentSize(); 205 | }); 206 | }); -------------------------------------------------------------------------------- /ui/js/other/loading-btn.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | function updateButtonContent($btn, message, iconType) { 3 | switch (iconType) { 4 | case "loading": 5 | icon = " "; 6 | break; 7 | case "success": 8 | icon = " "; 9 | break; 10 | case "error": 11 | icon = " "; 12 | break; 13 | default: 14 | icon = ""; 15 | break; 16 | } 17 | 18 | var parsed, i18nKey; 19 | 20 | parsed = UI.parseMessage(message, true); 21 | message = icon + parsed[0]; 22 | i18nKey = parsed[1]; 23 | 24 | if (!$btn.find(".content").length) { 25 | $btn.html(""); 26 | } 27 | 28 | $btn.find(".content").html(message); 29 | 30 | if (i18nKey) { 31 | $btn.data("i18n", i18nKey); 32 | } else { 33 | $btn.data("i18n", ""); 34 | } 35 | } 36 | 37 | $.fn.loadingInitialize = function(){ 38 | return this.each(function(){ 39 | var resetTimeout; 40 | var barTimeout; 41 | var messageTimeout; 42 | 43 | var startTime; 44 | 45 | var $btn = $(this); 46 | var $bar = $(''); 47 | 48 | //todo: if updateMessage is called before barTimeout it is overwritten by it! 49 | $btn.on("updateMessage", function(e, data) { 50 | clearTimeout(messageTimeout); 51 | 52 | if (data.timeout) { 53 | messageTimeout = setTimeout(function() { 54 | updateButtonContent($btn, data.msg, data.icon); 55 | $btn.data("updated", true); 56 | }, data.timeout); 57 | } else { 58 | updateButtonContent($btn, data.msg, data.icon); 59 | $btn.data("updated", true); 60 | } 61 | }); 62 | 63 | $btn.on("click", function(e) { 64 | if (!$btn.hasClass("loading") && !$btn.hasClass("success") && !$btn.hasClass("error")) { 65 | $btn.removeClass("loading success error reset").addClass("loading").attr("disabled", "disabled"); 66 | 67 | startTime = new Date().getTime(); 68 | 69 | $("body").css("cursor", "progress"); 70 | 71 | var msTimeout = $btn.data("bar-timeout"); 72 | 73 | if (!msTimeout) { 74 | msTimeout = 200; 75 | } 76 | 77 | // Only start showing the bar if the action is not finished within 200 ms. 78 | barTimeout = setTimeout(function() { 79 | // If the message has already been updated before barTimeout is called, then of course we do not overwrite it again. 80 | //if (!$btn.data("updated")) { 81 | updateButtonContent($btn, $btn.data("loading") ? $btn.data("loading") : "loading", "loading"); 82 | 83 | if (!$btn.hasClass("btn-no-progress-bar")) { 84 | $btn.append($bar); 85 | $bar.fadeIn(800); 86 | } 87 | }, msTimeout); 88 | } else { 89 | e.preventDefault(); 90 | // Prevent the event from propagating to other click handlers (IMMEDIATEPropagation) 91 | e.stopImmediatePropagation(); 92 | 93 | if ($(this).hasClass("wait")) { 94 | clearTimeout(messageTimeout); 95 | $btn.removeClass("loading success error reset wait").addClass("reset").find(".content").html(UI.t($btn.data("initial")).toUpperCase()); 96 | $btn.data("i18n", $btn.data("initial")); 97 | } 98 | } 99 | }); 100 | 101 | $btn.on("finished", function(e, data) { 102 | if (!data) { 103 | data = {}; 104 | } 105 | 106 | $("body").css("cursor", "default"); 107 | 108 | $bar.remove(); 109 | 110 | clearTimeout(barTimeout); 111 | 112 | var message = ""; 113 | 114 | if (data.msg) { 115 | message = data.msg; 116 | } else if (data.type) { 117 | message = $btn.data(data.type); 118 | } 119 | 120 | if (!message && data.type) { 121 | message = data.type; 122 | } else if (!message) { 123 | message = "submit"; 124 | } 125 | 126 | if (data.initial && data.initial.match(/^[a-z\_]+$/i)) { 127 | $btn.data("initial", data.initial); 128 | } 129 | if (data.loading && data.loading.match(/^[a-z\_]+$/i)) { 130 | $btn.data("loading", data.loading); 131 | } 132 | 133 | $btn.data("updated", ""); 134 | 135 | $btn.removeClass("loading success error reset").addClass(data.type); 136 | 137 | clearTimeout(messageTimeout); 138 | 139 | updateButtonContent($btn, message, data.type); 140 | 141 | if (data.type == "success" || data.type == "error") { 142 | var timeTaken = new Date().getTime() - startTime; 143 | 144 | clearTimeout(resetTimeout); 145 | 146 | var autoReset = $btn.data("auto-reset"); 147 | 148 | if (!autoReset && timeTaken > 5000) { 149 | // If time taken is larger than 5 seconds, user must click the button. 150 | $btn.addClass("wait").removeAttr("disabled"); 151 | } else { 152 | //Else, The user will have to click the button to reset it. 153 | resetTimeout = setTimeout(function() { 154 | clearTimeout(messageTimeout); 155 | $btn.removeClass("loading success error reset").addClass("reset").removeAttr("disabled").find(".content").html(UI.t($btn.data("initial")).toUpperCase()); 156 | $btn.data("i18n", $btn.data("initial")); 157 | }, 2500); 158 | } 159 | } else { 160 | $btn.removeAttr("disabled"); 161 | } 162 | }); 163 | }); 164 | }; 165 | 166 | $.fn.loadingSuccess = function(msg, options) { 167 | if (typeof msg == "object") { 168 | msg = (msg.message ? msg.message : ""); 169 | } 170 | 171 | console.log("$.fn.loadingSuccess: " + msg); 172 | 173 | if (!options) { 174 | options = {}; 175 | } 176 | 177 | $.extend(options, {"type": "success", "msg": msg}); 178 | 179 | return this.first().trigger("finished", options); 180 | }; 181 | 182 | $.fn.loadingError = function(msg, options) { 183 | if (typeof msg == "object") { 184 | msg = (msg.message ? msg.message : ""); 185 | } 186 | 187 | console.log("$.fn.loadingError: " + msg); 188 | 189 | if (!options) { 190 | options = {}; 191 | } 192 | 193 | $.extend(options, {"type": "error", "msg": msg}); 194 | 195 | return this.first().trigger("finished", options); 196 | }; 197 | 198 | $.fn.loadingReset = function(msg, options) { 199 | console.log("$.fn.loadingReset: " + msg); 200 | 201 | if (!options) { 202 | options = {}; 203 | } 204 | 205 | $.extend(options, {"type": "reset", "msg": msg}); 206 | 207 | return this.first().trigger("finished", options); 208 | }; 209 | 210 | $.fn.loadingUpdate = function(msg, options) { 211 | console.log("$.fn.loadingUpdate: " + msg); 212 | 213 | var $btn = this.first(); 214 | 215 | if (!options) { 216 | options = {}; 217 | } 218 | 219 | if (options.initial && options.initial.match(/^[a-z\_]+$/i)) { 220 | $btn.data("initial", options.initial); 221 | } 222 | if (options.loading && options.loading.match(/^[a-z\_]+$/i)) { 223 | $btn.data("loading", options.loading); 224 | } 225 | 226 | var timeout = (options.timeout ? options.timeout : 0); 227 | 228 | return this.first().trigger("updateMessage", {"msg": msg, "icon": options.noIcon ? "" : "loading", "timeout": timeout}); 229 | }; 230 | })(jQuery); -------------------------------------------------------------------------------- /ui/js/ui.init.js: -------------------------------------------------------------------------------- 1 | var iota; 2 | 3 | var connection = {"accountData" : false, 4 | "previousAccountData" : false, 5 | "isLoggedIn" : false, 6 | "showStatus" : false, 7 | "inApp" : false, 8 | "isSpamming" : false, 9 | "handleURL" : false, 10 | "testNet" : false, 11 | "host" : "http://localhost", 12 | "port" : 14265, 13 | "depth" : 3, 14 | "minWeightMagnitude" : 14, 15 | "ccurl" : 0, 16 | "ccurlPath" : null, 17 | "lightWallet" : false, 18 | "allowShortSeedLogin" : false, 19 | "keccak" : false, 20 | "language" : "en"}; 21 | 22 | var __entityMap = { 23 | "&": "&", 24 | "<": "<", 25 | ">": ">", 26 | '"': '"', 27 | "'": ''' 28 | }; 29 | 30 | String.prototype.escapeHTML = function() { 31 | return String(this).replace(/[&<>"']/g, function(s) { 32 | return __entityMap[s]; 33 | }); 34 | }; 35 | 36 | if (typeof document.hasFocus === "undefined") { 37 | document.hasFocus = function () { 38 | return document.visibilityState == "visible"; 39 | } 40 | } 41 | 42 | $(document).ready(function() { 43 | UI.start(); 44 | }); 45 | 46 | var UI = (function(UI, $, undefined) { 47 | UI.initializationTime = 0; 48 | UI.initialConnection = false; 49 | 50 | UI.isLocked = false; 51 | UI.hasFocus = true; 52 | 53 | UI.start = function() { 54 | console.log("UI.start: Initialization"); 55 | 56 | UI.initializationTime = new Date().getTime(); 57 | 58 | var interruptAttachingToTangle = false; 59 | 60 | if (typeof(URLSearchParams) != "undefined" && parent) { 61 | var params = new URLSearchParams(location.search.slice(1)); 62 | connection.inApp = params.get("inApp") == 1; 63 | connection.showStatus = params.get("showStatus") == 1; 64 | if (params.has("host")) { 65 | connection.host = params.get("host"); 66 | } 67 | if (params.has("port")) { 68 | connection.port = params.get("port"); 69 | } 70 | if (params.has("depth")) { 71 | connection.depth = parseInt(params.get("depth"), 10); 72 | } 73 | if (params.has("minWeightMagnitude")) { 74 | connection.minWeightMagnitude = parseInt(params.get("minWeightMagnitude"), 10); 75 | } 76 | if (params.has("ccurl")) { 77 | connection.ccurl = parseInt(params.get("ccurl"), 10); 78 | } 79 | if (params.has("ccurlPath")) { 80 | connection.ccurlPath = params.get("ccurlPath"); 81 | } 82 | if (params.has("language")) { 83 | connection.language = params.get("language"); 84 | } 85 | if (params.has("allowShortSeedLogin")) { 86 | connection.allowShortSeedLogin = params.get("allowShortSeedLogin") == 1; 87 | } 88 | if (params.has("interrupt")) { 89 | interruptAttachingToTangle = true; 90 | } 91 | if (params.has("keccak")) { 92 | connection.keccak = params.get("keccak") == 1; 93 | } 94 | } 95 | 96 | UI.makeMultilingual(connection.language, function() { 97 | var d = document.documentElement.style; 98 | var supported = ("flex" in d || "msFlex" in d || "webkitFlex" in d || "webkitBoxFlex" in d); 99 | if (!supported || String(2779530283277761) != "2779530283277761") { 100 | showOutDatedBrowserMessage(); 101 | return; 102 | } 103 | 104 | if (connection.inApp && (typeof(backendLoaded) == "undefined" || !backendLoaded)) { 105 | showBackendConnectionError(); 106 | return; 107 | } 108 | 109 | iota = new IOTA({ 110 | "host": connection.host, 111 | "port": connection.port 112 | }); 113 | 114 | if (connection.host != "http://localhost") { 115 | connection.lightWallet = true; 116 | if (!connection.inApp || typeof(ccurl) == "undefined" || !ccurl) { 117 | if (typeof(ccurl) == "undefined") { 118 | console.log("ccurl is undefined"); 119 | } else if (!ccurl) { 120 | console.log("ccurl is false"); 121 | } else { 122 | console.log("..."); 123 | } 124 | showLightWalletErrorMessage(); 125 | return; 126 | } else { 127 | connection.ccurlProvider = ccurl.ccurlProvider(connection.ccurlPath); 128 | if (!connection.ccurlProvider) { 129 | console.log("Did not get ccurlProvider from " + connection.ccurlPath); 130 | return; 131 | } 132 | } 133 | // Overwrite iota lib with light wallet functionality 134 | $.getScript("js/iota.lightwallet.js").done(function() { 135 | if (interruptAttachingToTangle) { 136 | iota.api.interruptAttachingToTangle(function() {}); 137 | } 138 | setTimeout(initialize, 100); 139 | }).fail(function(jqxhr, settings, exception) { 140 | console.log("Could not load iota.lightwallet.js"); 141 | showLightWalletErrorMessage(); 142 | }); 143 | } else { 144 | if (interruptAttachingToTangle) { 145 | iota.api.interruptAttachingToTangle(function() {}); 146 | } 147 | setTimeout(initialize, 100); 148 | } 149 | }); 150 | } 151 | 152 | function initialize() { 153 | $("body").show(); 154 | 155 | // Set notification options 156 | toastr.options.positionClass = "toast-top-center"; 157 | // Need not escape, UI.notify already does that. 158 | // toastr.options.escapeHtml = true; 159 | 160 | // Hide pages 161 | $("#app, #login").hide(); 162 | 163 | // Initialize button handlers 164 | $(".btn:not(.btn-no-loading)").loadingInitialize(); 165 | 166 | // Enable copy to clipboard 167 | var clipboard = new Clipboard(".clipboard"); 168 | clipboard.on("success", function(e) { 169 | UI.notify("success", "copied_to_clipboard"); 170 | }); 171 | 172 | // Show full amounts on click 173 | $("body").on("click", ".amount.long", function(e) { 174 | if ($(this).hasClass("detailed")) { 175 | $(this).parent().removeClass("detailed"); 176 | $(this).removeClass("detailed").html(UI.format($(this).data("short"))).hide().fadeIn(); 177 | } else { 178 | $(this).parent().addClass("detailed"); 179 | $(this).addClass("detailed").html(UI.format($(this).data("long"))).hide().fadeIn(); 180 | } 181 | 182 | $(this).css("font-size", ""); 183 | 184 | var currentFontSize = parseInt($(this).css("font-size"), 10); 185 | var parentWidth = $(this).parent().width(); 186 | 187 | while ($(this).width() > parentWidth) { 188 | $(this).css("font-size", --currentFontSize); 189 | } 190 | }); 191 | 192 | UI.showLoginScreen(); 193 | 194 | // Until we have a server connection we will check every 500ms.. 195 | UI.createStateInterval(500, true); 196 | 197 | // Enable app message listening 198 | if (connection.inApp) { 199 | UI.inAppInitialize(); 200 | } 201 | } 202 | 203 | function showErrorMessage(error) { 204 | document.body.innerHTML = "
" + UI.format(error) + "
"; 205 | document.body.style.display = "block"; 206 | } 207 | 208 | function showLightWalletErrorMessage() { 209 | showErrorMessage(UI.t("could_not_load_light_wallet_functionality")); 210 | } 211 | 212 | function showBackendConnectionError() { 213 | showErrorMessage(UI.t("could_not_load_required_backend_files")); 214 | } 215 | 216 | function showOutdatedBrowserMessage() { 217 | console.log("showOutdatedBrowserMessage"); 218 | 219 | var html = ""; 220 | 221 | html += "
"; 222 | html += "" + UI.t("browser_out_of_date") + ""; 223 | html += ""; 228 | html += "
"; 229 | 230 | $("body").html(html).show(); 231 | } 232 | 233 | return UI; 234 | }(UI || {}, jQuery)); 235 | -------------------------------------------------------------------------------- /ui/js/ui.login.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | UI.showLoginForm = false; 3 | UI.loginFormShown = false; 4 | UI.isLoggingIn = false; 5 | UI.isLoggingOut = false; 6 | UI.isShuttingDown = false; 7 | 8 | var loginGradientInterval; 9 | var _seedError; 10 | var _loginFormShownCallback; 11 | 12 | UI.showLoginScreen = function() { 13 | console.log("UI.showLoginScreen"); 14 | 15 | $("#app").hide(); 16 | 17 | $("#login").show(); 18 | 19 | loginGradientInterval = UI.applyGradientAnimation("#login", [[77, 193, 181], [40, 176, 162], [0, 132, 118], [0, 104, 93]]); 20 | 21 | setTimeout(function() { 22 | clearInterval(loginGradientInterval); 23 | }, 60000); 24 | 25 | UI.handleRecovery(); 26 | UI.handleHelpMenu(); 27 | UI.handleNetworkSpamming(); 28 | UI.handlePastingTrytes(); 29 | 30 | $("#login .logo").hide().fadeIn(1000, function() { 31 | if (UI.showLoginForm) { 32 | UI.fadeInLoginForm(); 33 | } else { 34 | UI.showLoginForm = true; 35 | } 36 | }); 37 | 38 | $("#login-password").on("keydown keyup", function(e) { 39 | if (e.keyCode == 13 && !$("#login-btn").is(":disabled")) { 40 | $("#login-btn").trigger("click"); 41 | } 42 | 43 | var seed = $(this).val(); 44 | 45 | $checksum = $("#login-checksum"); 46 | 47 | $checksum.removeClass(); 48 | 49 | if (!seed) { 50 | $checksum.html("").addClass("help icon").attr("title", "");; 51 | } else if (seed.match(/[^A-Z9]/) || seed.match(/^[9]+$/)) { 52 | $checksum.html("").addClass("invalid icon").attr("title", UI.t("seed_character_set")); 53 | } else if (seed.length < 60 && !connection.allowShortSeedLogin) { 54 | $checksum.html("<60").addClass("invalid").show().attr("title", UI.t("seed_too_short")); 55 | } else if (seed.length > 81) { 56 | $checksum.html(">81").addClass("invalid").show().attr("title", UI.t("seed_too_long")); 57 | } else { 58 | try { 59 | var checksum = iota.utils.addChecksum(seed, 3, false).substr(-3); 60 | if (checksum != "999") { 61 | $checksum.html(UI.format(checksum)).attr("title", UI.t("seed_checksum")); 62 | } else { 63 | $checksum.html("").addClass("invalid icon").attr("title", UI.t("seed_character_set")); 64 | } 65 | } catch (err) { 66 | console.log(err); 67 | $checksum.html("").addClass("invalid icon").attr("title", UI.t("seed_character_set")); 68 | } 69 | } 70 | 71 | seed = ""; 72 | }); 73 | 74 | $("#login-checksum").on("click", function(e) { 75 | if ($(this).hasClass("icon")) { 76 | UI.openHelpMenu(); 77 | } 78 | }); 79 | 80 | $("#error-btn").on("click", function(e) { 81 | e.preventDefault(); 82 | 83 | if (connection.inApp) { 84 | editNodeConfiguration(); 85 | } 86 | }); 87 | 88 | $("#login-btn").on("click", function(e) { 89 | try { 90 | var seed = String($("#login-password").val()); 91 | 92 | if (!seed) { 93 | throw UI.t("seed_is_required"); 94 | } else if (seed.match(/[^A-Z9]/) || seed.match(/^[9]+$/)) { 95 | throw UI.t("invalid_characters"); 96 | } else if (seed.length < 60) { 97 | if (connection.allowShortSeedLogin) { 98 | _seedError = UI.t("seed_not_secure"); 99 | } else { 100 | throw UI.t("seed_too_short"); 101 | } 102 | } else if (seed.length > 81) { 103 | throw UI.t("seed_too_long"); 104 | } 105 | 106 | if (connection.inApp) { 107 | clearSeedFromClipboard(seed); 108 | } 109 | 110 | while (seed.length < 81) { 111 | seed += "9"; 112 | } 113 | 114 | connection.seed = seed; 115 | } catch (error) { 116 | console.log("UI.login: Error"); 117 | console.log(error); 118 | $("#login-btn").loadingError(error); 119 | $("#login-password").focus(); 120 | return; 121 | } 122 | 123 | seed = ""; 124 | 125 | UI.isLoggingIn = true; 126 | 127 | setTimeout(function() { 128 | iota.api.getAccountData(connection.seed, function(error, accountData) { 129 | UI.isLoggingIn = false; 130 | 131 | connection.accountData = accountData; 132 | 133 | if (error) { 134 | connection.seed = ""; 135 | console.log(error); 136 | if (error.message.match(/This operations cannot be executed: The subtangle has not been updated yet/i)) { 137 | $("#login-btn").loadingError("not_synced"); 138 | } else { 139 | $("#login-btn").loadingError("connection_refused"); 140 | } 141 | UI.initialConnection = false; 142 | UI.createStateInterval(500, false); 143 | } else { 144 | $("#login-password").val(""); 145 | $("#login-btn").loadingReset("login", {"icon": "fa-cog fa-spin fa-fw"}); 146 | 147 | UI.showAppScreen(); 148 | } 149 | }); 150 | }, 150); 151 | }); 152 | } 153 | 154 | UI.showAppScreen = function() { 155 | console.log("UI.showAppScreen"); 156 | 157 | clearInterval(loginGradientInterval); 158 | 159 | // After logging in, update state every minute 160 | UI.createStateInterval(60000, false); 161 | 162 | UI.update(); 163 | 164 | $("#app").css("z-index", 1000).fadeIn(400, function() { 165 | $("#login").remove(); 166 | }); 167 | 168 | UI.animateStacks(0); 169 | 170 | if (_seedError) { 171 | var options = {timeOut: 10000, 172 | extendedTimeOut: 10000}; 173 | 174 | UI.notify("error", _seedError, options); 175 | } 176 | 177 | $(window).on("resize", function() { 178 | UI.animateStacks(0); 179 | }); 180 | 181 | $(".logout").on("click", function(e) { 182 | e.preventDefault(); 183 | e.stopPropagation(); 184 | 185 | if (UI.isLoggingOut) { 186 | return; 187 | } 188 | 189 | UI.isLoggingOut = true; 190 | 191 | var params = { 192 | "inApp": 1, 193 | "showStatus": connection.showStatus ? 1 : 0, 194 | "host": connection.host, 195 | "port": connection.port, 196 | "depth": connection.depth, 197 | "minWeightMagnitude": connection.minWeightMagnitude, 198 | "ccurl": connection.ccurl, 199 | "ccurlPath": connection.ccurlPath, 200 | "language": connection.language, 201 | "allowShortSeedLogin": connection.allowShortSeedLogin ? 1 : 0, 202 | "interrupt": 1, 203 | "keccak": connection.keccak ? 1 : 0 204 | } 205 | 206 | window.location.href = "index.html?" + $.param(params); 207 | }); 208 | 209 | UI.handleTransfers(); 210 | UI.handleAddressGeneration(); 211 | UI.handleHistory(); 212 | 213 | $("#app").on("click", ".stack:not(.open)", function(e) { 214 | e.preventDefault(); 215 | e.stopPropagation(); 216 | $(".stack.open").removeClass("open").addClass("closing"); 217 | $(this).removeClass("closed").addClass("open opening"); 218 | 219 | UI.animateStacks(200); 220 | 221 | var $stack = $(this); 222 | 223 | var onOpen = $stack.data("onopen"); 224 | 225 | if (onOpen && UI[onOpen]) { 226 | UI[onOpen](); 227 | } 228 | 229 | // Should be done in callback instead.. 230 | setTimeout(function() { 231 | $(".stack.closing").removeClass("closing"); 232 | $(".stack:not(.open)").addClass("closed"); 233 | $(".stack.open").removeClass("opening"); 234 | 235 | var onOpenCompleted = $stack.data("onopencompleted"); 236 | 237 | if (onOpenCompleted && UI[onOpenCompleted]) { 238 | setTimeout(function() { 239 | UI[onOpenCompleted](); 240 | }, 25); 241 | } 242 | }, 205); 243 | }); 244 | 245 | if (connection.handleURL) { 246 | UI.handleURL(); 247 | } 248 | } 249 | 250 | UI.fadeInLoginForm = function() { 251 | UI.loginFormShown = true; 252 | 253 | var $form = $("#login-form"); 254 | 255 | $form.find(":input").hide(); 256 | // Hackety hack 257 | if ($("#error-btn").hasClass("no-connection")) { 258 | $("#error-btn").show(); 259 | } 260 | $form.fadeIn(400); 261 | 262 | UI.updateLoginForm(); 263 | } 264 | 265 | UI.updateLoginForm = function() { 266 | if (!connection.nodeInfo) { 267 | console.log("UI.updateLoginForm: No node info"); 268 | if (connection.inApp && !UI.initialConnection) { 269 | var timeTaken = new Date().getTime() - UI.initializationTime; 270 | if (timeTaken >= 500 && timeTaken < 10000) { 271 | if (!$("#error-btn").hasClass("no-connection")) { 272 | $("#login-btn, #login-password").hide(); 273 | $("#error-btn").addClass("no-connection").html(UI.t("connecting")).fadeIn(); 274 | } 275 | } 276 | } else { 277 | $("#login-btn, #login-password").hide(); 278 | $("#error-btn").removeClass("no-connection").html(UI.t("connection_refused")).show(); 279 | if (UI.updateIntervalTime != 500) { 280 | UI.createStateInterval(500, false); 281 | } 282 | } 283 | } else if (!$("#login-password").is(":visible")) { 284 | console.log("UI.updateLoginForm: Fade in"); 285 | 286 | var fadeIn = false; 287 | 288 | if ($("#error-btn").hasClass("no-connection") && $("#error-btn").is(":visible")) { 289 | fadeIn = true; 290 | } 291 | 292 | $("#error-btn").hide(); 293 | 294 | if (fadeIn) { 295 | $("#login-btn, #login-password").fadeIn(); 296 | } else { 297 | $("#login-btn, #login-password").show(); 298 | } 299 | 300 | $("#login-password").focus(); 301 | 302 | if (_loginFormShownCallback) { 303 | _loginFormShownCallback(); 304 | } 305 | } 306 | } 307 | 308 | UI.shutdown = function() { 309 | UI.isShuttingDown = true; 310 | } 311 | 312 | return UI; 313 | }(UI || {}, jQuery)); 314 | -------------------------------------------------------------------------------- /ui/js/ui.transfers.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | var modal, doubleSpend, $stack; 3 | 4 | UI.handleTransfers = function() { 5 | $stack = $("#transfer-stack"); 6 | 7 | $("#transfer-btn").on("click", function(e) { 8 | console.log("UI.handleTransfers: Click"); 9 | 10 | if ($("#transfer-autofill").val() == "1") { 11 | UI.formError("transfer", "are_you_sure", {"initial": "yes_send_now"}); 12 | $("#transfer-autofill").val("0"); 13 | return; 14 | } 15 | 16 | $stack.addClass("loading"); 17 | 18 | var address, amount, tag; 19 | 20 | try { 21 | address = $.trim($("#transfer-address").val()); 22 | 23 | if (!address) { 24 | throw UI.t("address_is_required"); 25 | } else if (address.length == 81) { 26 | throw UI.t("missing_address_checksum"); 27 | } else if (address.length != 90) { 28 | throw UI.t("incorrect_address_length"); 29 | } else if (!address.match(/^[A-Z9]+$/)) { 30 | throw UI.t("invalid_address"); 31 | } else if (!iota.utils.isValidChecksum(address)) { 32 | throw UI.t("incorrect_address_checksum"); 33 | } 34 | 35 | var rawAmount = $.trim($("#transfer-amount").val()); 36 | var rawUnits = $("#transfer-units-value").html(); 37 | 38 | if (!rawAmount) { 39 | throw UI.t("amount_cannot_be_zero"); 40 | } else { 41 | if(rawAmount < 0){ 42 | throw UI.t("amount_cannot_be_negative"); 43 | } 44 | amount = iota.utils.convertUnits(parseFloat(rawAmount), rawUnits, "i"); 45 | 46 | if (!amount) { 47 | throw UI.t("amount_cannot_be_zero"); 48 | } 49 | } 50 | 51 | if ($("#transfer-tag-container").is(":visible")) { 52 | tag = $.trim($("#transfer-tag").val().toUpperCase()); 53 | 54 | if (tag && (/[^A-Z9]/.test(tag) || tag.length > 27)) { 55 | throw UI.t("tag_is_invalid"); 56 | } 57 | } 58 | } catch (error) { 59 | $stack.removeClass("loading"); 60 | UI.formError("transfer", error); 61 | return; 62 | } 63 | 64 | console.log("Server.transfer: " + address + " -> " + amount); 65 | 66 | UI.isDoingPOW = true; 67 | 68 | getUnspentInputs(connection.seed, 0, amount, function(error, inputs) { 69 | if (error && error.message !== 'Not enough balance') { 70 | UI.isDoingPOW = false; 71 | UI.formError("transfer", error, {"initial": "send_it_now"}); 72 | $stack.removeClass("loading"); 73 | return; 74 | } else if (inputs.allBalance < amount) { 75 | UI.formError("transfer", "not_enough_balance", {"initial": "send_it_now"}); 76 | $stack.removeClass("loading"); 77 | return; 78 | } else if (inputs.totalBalance < amount) { 79 | UI.isDoingPOW = false; 80 | UI.formError("transfer", "key_reuse_error", {"initial": "send_it_now"}); 81 | modal = $("#key-reuse-modal").remodal({hashTracking: false, closeOnOutsideClick: false, closeOnEscape: false}); 82 | modal.open(); 83 | $stack.removeClass("loading"); 84 | return; 85 | } 86 | 87 | var transfers = [{"address": address, "value": amount, "message": "", "tag": tag}]; 88 | var outputsToCheck = transfers.map(transfer => iota.utils.noChecksum(transfer.address)); 89 | var exptectedOutputsLength = outputsToCheck.length; 90 | filterSpentAddresses(outputsToCheck).then(filtered => { 91 | if (filtered.length !== exptectedOutputsLength) { 92 | UI.isDoingPOW = false; 93 | UI.formError("transfer", "sent_to_key_reuse_error", {"initial": "send_it_now"}); 94 | modal = $("#sent-to-key-reuse-modal").remodal({hashTracking: false, closeOnOutsideClick: false, closeOnEscape: false}); 95 | modal.open(); 96 | $stack.removeClass("loading"); 97 | return; 98 | } 99 | iota.api.prepareTransfers(connection.seed, transfers, {"inputs": inputs.inputs}, function(error, trytes) { 100 | if (error) { 101 | UI.formError("transfer", error, {"initial": "send_it_now"}); 102 | $stack.removeClass("loading"); 103 | return; 104 | } 105 | var sentToInputs = false; 106 | trytes.forEach(transactionTrytes => { 107 | var tx = iota.utils.transactionObject(transactionTrytes); 108 | if (inputs.inputs.findIndex(input => tx.value > 0 && input.address === tx.address) !== -1) { 109 | sentToInputs = true; 110 | } 111 | }) 112 | if (sentToInputs) { 113 | UI.formError("transfer", "sent_to_inputs", {"initial": "send_it_now"}); 114 | $stack.removeClass("loading"); 115 | return; 116 | } 117 | iota.api.sendTrytes(trytes, connection.depth, connection.minWeightMagnitude, (error, transfers) => { 118 | UI.isDoingPOW = false; 119 | if (error) { 120 | UI.formError("transfer", error, {"initial": "send_it_now"}); 121 | } else { 122 | console.log("UI.handleTransfers: Success"); 123 | UI.formSuccess("transfer", "transfer_completed", {"initial": "send_it_now"}); 124 | UI.updateState(1000); 125 | } 126 | $stack.removeClass("loading"); 127 | }); 128 | }); 129 | }).catch(err => { 130 | UI.formError('transfer', err, {initial: 'send_it_now'}) 131 | $stack.removeClass("loading") 132 | }); 133 | }) 134 | }); 135 | 136 | $("#key-reuse-close-btn").on("click", function(e) { 137 | modal.close(); 138 | $("#key-reuse-close-btn").loadingReset("close"); 139 | }); 140 | 141 | $("#sent-to-key-reuse-close-btn").on("click", function(e) { 142 | modal.close(); 143 | $("#sent-to-key-reuse-close-btn").loadingReset("close"); 144 | }); 145 | 146 | $("#transfer-units-value").on("click", function(e) { 147 | var $overlay = $("#overlay"); 148 | var $select = $(''); 157 | 158 | $overlay.show(); 159 | 160 | $("#transfer-units-select").remove(); 161 | 162 | $("body").append($select); 163 | 164 | var offset = $(this).offset(); 165 | 166 | $select.css({"position": "absolute", "top": (offset.top + $(this).innerHeight() + 15) + "px", "left": (offset.left) + "px", "width": $(this).outerWidth() + "px"}).addClass("active"); 167 | 168 | $select.on("click", "li", function(e) { 169 | $select.removeClass("active"); 170 | $("#transfer-units-value").html($(this).html()); 171 | $overlay.hide().off("click.transfer"); 172 | $(window).off("resize.transfer"); 173 | }); 174 | 175 | $overlay.on("click.transfer", function(e) { 176 | $select.removeClass("active"); 177 | $(this).hide().off("click.transfer"); 178 | $(window).off("resize.transfer"); 179 | }); 180 | 181 | $(window).on("resize.transfer", function() { 182 | var $rel = $("#transfer-units-value") 183 | var offset = $rel.offset(); 184 | $select.css({"position": "absolute", "top": (offset.top + $rel.innerHeight() + 15) + "px", "left": (offset.left) + "px", "width": $rel.outerWidth() + "px"}); 185 | }); 186 | }); 187 | 188 | $("#transfer-units-select").on("click", function(e) { 189 | e.preventDefault(); 190 | e.stopPropagation(); 191 | 192 | var $ul = $(this).find("ul"); 193 | $ul.addClass("active"); 194 | $ul.find("li").click(function(e) { 195 | e.preventDefault(); 196 | e.stopPropagation(); 197 | 198 | $ul.find("li").unbind(); 199 | $ul.find("li").removeClass("selected"); 200 | $(this).addClass("selected"); 201 | $ul.removeClass("active"); 202 | $("body").unbind("click.dropdown"); 203 | }); 204 | 205 | $("body").on("click.dropdown", function(e) { 206 | $ul.removeClass("active"); 207 | $("body").unbind("click.dropdown"); 208 | }); 209 | }); 210 | } 211 | 212 | UI.onOpenTransferStack = function() { 213 | if ($("#transfer-address").val() == "") { 214 | $("#transfer-address").focus(); 215 | } 216 | } 217 | 218 | return UI; 219 | }(UI || {}, jQuery)); 220 | 221 | 222 | function filterSpentAddresses (addresses) { 223 | return new Promise((resolve, reject) => { 224 | iota.api.wereAddressesSpentFrom( 225 | iota.valid.isArrayOfHashes(addresses) ? addresses : addresses.map(address => address.address), 226 | (err, wereSpent) => err ? reject(err) : resolve(addresses.filter((address, i) => !wereSpent[i])) 227 | ) 228 | }) 229 | } 230 | 231 | function getUnspentInputs (seed, start, threshold, inputs, cb) { 232 | if (arguments.length === 4) { 233 | cb = arguments[3] 234 | inputs = {inputs: [], totalBalance: 0, allBalance: 0} 235 | } 236 | iota.api.getInputs(seed, {start: start, threshold: threshold}, (err, res) => { 237 | if (err) { 238 | cb(err, inputs) 239 | return 240 | } 241 | inputs.allBalance += res.inputs.reduce((sum, input) => sum + input.balance, 0) 242 | filterSpentAddresses(res.inputs).then(filtered => { 243 | var collected = filtered.reduce((sum, input) => sum + input.balance, 0) 244 | var diff = threshold - collected 245 | if (diff > 0) { 246 | var ordered = res.inputs.sort((a, b) => a.keyIndex - b.keyIndex).reverse() 247 | var end = ordered[0].keyIndex 248 | getUnspentInputs(seed, end + 1, diff, {inputs: inputs.inputs.concat(filtered), totalBalance: inputs.totalBalance + collected, allBalance: inputs.allBalance}, cb) 249 | } else { 250 | cb(null, {inputs: inputs.inputs.concat(filtered), totalBalance: inputs.totalBalance + collected, allBalance: inputs.allBalance}) 251 | } 252 | }).catch(err => cb(err, inputs)) 253 | }) 254 | } 255 | -------------------------------------------------------------------------------- /ui/js/ui.utils.js: -------------------------------------------------------------------------------- 1 | var UI = (function(UI, $, undefined) { 2 | var i18n; 3 | 4 | UI.hideAlerts = function() { 5 | $(".remodal-wrapper, .remodal-overlay").remove(); 6 | $("html").removeClass("remodal-is-locked"); 7 | } 8 | 9 | UI.formatAmount = function(amount) { 10 | if (typeof(amount) != "integer") { 11 | amount = parseInt(amount, 10); 12 | } 13 | 14 | var units = negative = formattedAmount = "", afterComma = "", beforeComma = "", hidden = "", afterCommaDigits = 0; 15 | 16 | if (amount < 0) { 17 | amount = Math.abs(amount); 18 | negative = "-"; 19 | } 20 | 21 | /* 22 | 1 Kiota = 10³ iota = 1,000 iota 23 | 1 Miota = 10⁶ iota = 1,000,000 iota 24 | 1 Giota = 10⁹ iota = 1,000,000,000 iota 25 | 1 Tiota = 10¹² iota = 1,000,000,000,000 iota 26 | 1 Piota = 10¹⁵ iota = 1,000,000,000,000,000 iota 27 | */ 28 | 29 | if (amount >= 1000000000000000) { 30 | units = "Pi"; 31 | afterCommaDigits = 15; 32 | } else if (amount >= 1000000000000) { 33 | units = "Ti"; 34 | afterCommaDigits = 12; 35 | } else if (amount >= 1000000000) { 36 | units = "Gi"; 37 | afterCommaDigits = 9; 38 | } else if (amount >= 1000000) { 39 | units = "Mi"; 40 | afterCommaDigits = 6; 41 | } else { 42 | units = ""; 43 | afterCommaDigits = 0; 44 | } 45 | 46 | amount = amount.toString(); 47 | 48 | var digits = amount.split("").reverse(); 49 | 50 | for (var i=0; i 0 && j % 3 == 0) { 62 | beforeComma = "'" + beforeComma; 63 | } 64 | beforeComma = digits[i] + beforeComma; 65 | j++; 66 | } 67 | 68 | if (afterComma.length > 1) { 69 | hidden = afterComma.substring(1).replace(/0+$/, ""); 70 | afterComma = afterComma[0]; 71 | } 72 | 73 | var short = negative + beforeComma + (afterComma ? "." + afterComma : "") + (hidden ? "+" : "") + " " + units; 74 | var long = (hidden ? short.replace("+", hidden) : ""); 75 | 76 | long = UI.format(long); 77 | short = UI.format(short); 78 | amount = UI.format(negative + amount); 79 | 80 | if (long) { 81 | var output = "" + short + ""; 82 | } else { 83 | var output = "" + short + ""; 84 | } 85 | 86 | return output; 87 | } 88 | 89 | UI.formatForClipboard = function(text, id) { 90 | text = UI.format(text); 91 | if (id) { 92 | id = UI.format(id); 93 | } 94 | 95 | return "" + text + ""; 96 | } 97 | 98 | UI.formatDate = function(timestamp, full) { 99 | if (timestamp<1262304000000) { 100 | timestamp = timestamp * 1000 101 | } 102 | var date = new Date(timestamp); 103 | 104 | return ("0"+date.getDate()).substr(-2) + "/" + ("0"+(date.getMonth()+1)).substr(-2) + (full ? "/" + date.getFullYear() : "") + " " + ("0"+date.getHours()).substr(-2) + ":" + ("0"+date.getMinutes()).substr(-2); 105 | } 106 | 107 | UI.format = function(text) { 108 | return String(text).escapeHTML(); 109 | } 110 | 111 | UI.notify = function(type, message, options) { 112 | console.log("UI.notify: " + message); 113 | 114 | if (!options) { 115 | options = {}; 116 | } 117 | 118 | var parsedMessage = UI.parseMessage(message, options); 119 | 120 | if (type == "error") { 121 | toastr.error(parsedMessage, "", options); 122 | } else if (type == "success") { 123 | toastr.success(parsedMessage, "", options); 124 | } else if (type == "warning") { 125 | toastr.warning(parsedMessage, "", options); 126 | } else { 127 | toastr.info(parsedMessage, "", options); 128 | } 129 | 130 | UI.notifyDesktop(message, options, true); 131 | } 132 | 133 | UI.isFocused = function() { 134 | return ((connection.inApp && UI.hasFocus) || (!connection.inApp && document.hasFocus())); 135 | } 136 | 137 | UI.notifyDesktop = function(message, options, ifNotFocused) { 138 | console.log("UI.notifyDesktop: " + message); 139 | 140 | if (arguments.length == 1) { 141 | options = {}; 142 | ifNotFocused = false; 143 | } else if (arguments.length >= 2) { 144 | if (typeof(options) == "boolean") { 145 | ifNotFocused = options; 146 | options = {}; 147 | } 148 | } 149 | 150 | if (ifNotFocused && UI.isFocused()) { 151 | return; 152 | } 153 | 154 | var parsedMessage = UI.parseMessage(message, options); 155 | 156 | parsedMessage = parsedMessage.replace('"', '"'); 157 | parsedMessage = parsedMessage.replace(''', "'"); 158 | 159 | if (!("Notification" in window)) { 160 | return; 161 | } else if (Notification.permission === "granted") { 162 | var notification = new Notification("IOTA Wallet", {"body": parsedMessage}); 163 | } else if (Notification.permission !== "denied") { 164 | Notification.requestPermission(function (permission) { 165 | if (permission === "granted") { 166 | var notification = new Notification("IOTA Wallet", {"body": parsedMessage}); 167 | } 168 | }); 169 | } 170 | } 171 | 172 | UI.makeMultilingual = function(currentLanguage, callback) { 173 | i18n = i18next 174 | .use(window.i18nextXHRBackend) 175 | .init({ 176 | lng: currentLanguage, 177 | fallbackLng: "en", 178 | defaultValueFromContent: true, 179 | keySeparator: false, 180 | nsSeparator: false, 181 | backend: { 182 | loadPath: "../locales/{{lng}}/{{ns}}.json" 183 | }, 184 | debug: false 185 | }, function(err, t) { 186 | jqueryI18next.init(i18next, $, {useOptionsAttr: true}); 187 | $("*[data-i18n]").localize(); 188 | callback(); 189 | }); 190 | } 191 | 192 | UI.changeLanguage = function(language) { 193 | i18n.changeLanguage(language, function(err, t) { 194 | connection.language = language; 195 | $("*[data-i18n]").localize(); 196 | }); 197 | } 198 | 199 | UI.t = function(message, options) { 200 | if (i18n && message.match(/^[a-z\_]+$/i)) { 201 | return UI.format(i18n.t(message, options)); 202 | } else { 203 | return UI.format(message); 204 | } 205 | } 206 | 207 | UI.formSuccess = function(form, message, options) { 208 | var $stack = $("#" + form + "-stack"); 209 | 210 | $stack.find("input[type=text], input[type=number], textarea").val(""); 211 | $stack.find("select option:first-child").attr("selected", true); 212 | 213 | var $btn = $stack.find(".btn").first(); 214 | 215 | $btn.loadingSuccess(message, options); 216 | 217 | if (!$stack.hasClass("open")) { 218 | UI.notify("success", message); 219 | } else { 220 | UI.notifyDesktop(message, true); 221 | } 222 | } 223 | 224 | UI.formError = function(form, message, options) { 225 | var $stack = $("#" + form + "-stack"); 226 | var $btn = $stack.find(".btn").first(); 227 | 228 | $btn.loadingError(message, options); 229 | 230 | if (!$stack.hasClass("open")) { 231 | UI.notify("error", message); 232 | } else { 233 | UI.notifyDesktop(message, true); 234 | } 235 | } 236 | 237 | UI.formUpdate = function(form, message, options) { 238 | var $stack = $("#" + form + "-stack"); 239 | var $btn = $stack.find(".btn").first(); 240 | 241 | $btn.loadingUpdate(message, options); 242 | } 243 | 244 | UI.updateSettings = function(settings) { 245 | if (settings.hasOwnProperty("minWeightMagnitude")) { 246 | connection.minWeightMagnitude = parseInt(settings.minWeightMagnitude, 10); 247 | } 248 | if (settings.hasOwnProperty("depth")) { 249 | connection.depth = parseInt(settings.depth, 10); 250 | } 251 | 252 | if (settings.hasOwnProperty("ccurl")) { 253 | connection.ccurl = parseInt(settings.ccurl, 10); 254 | } 255 | var changeNode = false; 256 | 257 | if (settings.hasOwnProperty("host") && settings.host != connection.host) { 258 | connection.host = settings.host; 259 | changeNode = true; 260 | } 261 | if (settings.hasOwnProperty("port") && settings.port != connection.port) { 262 | connection.port = settings.port; 263 | changeNode = true; 264 | } 265 | 266 | if (changeNode) { 267 | iota.changeNode({"host": connection.host, "port": connection.port}); 268 | 269 | if (connection.lightWallet) { 270 | iota.api.attachToTangle = localAttachToTangle; 271 | iota.api.interruptAttachingToTangle = localInterruptAttachingToTangle; 272 | } 273 | } 274 | 275 | if (settings.hasOwnProperty("addedNodes") && settings.addedNodes.length) { 276 | iota.api.addNeighbors(settings.addedNodes, function(error, addedNodes) { 277 | if (error || addedNodes === undefined) { 278 | UI.notify("error", "error_whilst_adding_neighbors"); 279 | } else { 280 | UI.notify("success", "added_neighbor", {count: addedNodes}); 281 | } 282 | }); 283 | } 284 | 285 | if (settings.hasOwnProperty("removedNodes") && settings.removedNodes.length) { 286 | iota.api.removeNeighbors(settings.removedNodes, function(error, removedNodes) { 287 | if (error || removedNodes === undefined) { 288 | UI.notify("error", "error_whilst_removing_neighbors"); 289 | } else { 290 | UI.notify("success", "removed_neighbor", {count: removedNodes}); 291 | } 292 | }); 293 | } 294 | 295 | if (settings.hasOwnProperty("allowShortSeedLogin")) { 296 | connection.allowShortSeedLogin = settings.allowShortSeedLogin; 297 | } 298 | 299 | if (changeNode) { 300 | UI.resetState(); 301 | } 302 | } 303 | 304 | UI.parseMessage = function(message, options, returnKey) { 305 | console.log("UI.parseMessage"); 306 | console.log(message); 307 | 308 | if (typeof message == "object" && message.message) { 309 | message = String(message.message); 310 | } else { 311 | message = String(message); 312 | } 313 | 314 | if (arguments.length == 1) { 315 | options = {}; 316 | returnKey = false; 317 | } else if (arguments.length >= 2) { 318 | if (typeof(options) == "boolean") { 319 | returnKey = options; 320 | options = {}; 321 | } 322 | } 323 | 324 | var match; 325 | 326 | if (message.match(/^Invalid Response:/i)) { 327 | message = "invalid_response"; 328 | } else if (message.match(/^No connection to host:/i)) { 329 | message = "no_connection_to_host"; 330 | } else if (match = message.match(/^Request Error: (.*)/i)) { 331 | if (match[1] && match[1].toLowerCase() == "invalid transaction hash") { 332 | message = "invalid_transaction_hash"; 333 | } else { 334 | message = "request_error"; 335 | } 336 | } 337 | 338 | var parsedMessage; 339 | var key = ""; 340 | 341 | if (message.match(/^[a-z\_]+$/i)) { 342 | key = message; 343 | parsedMessage = UI.t(message, options); 344 | } else { 345 | parsedMessage = UI.format(message); 346 | } 347 | 348 | if (returnKey) { 349 | return [parsedMessage, key]; 350 | } else { 351 | return parsedMessage; 352 | } 353 | } 354 | 355 | return UI; 356 | }(UI || {}, jQuery)); 357 | -------------------------------------------------------------------------------- /locales/zh-TW/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "login":"登錄", 3 | "error":"錯誤", 4 | "balance":"餘額", 5 | "send":"轉款", 6 | "recipient_address":"收款位址", 7 | "optional_tag":"標籤(可選)", 8 | "sending":"轉款中……", 9 | "send_it_now":"立即轉款", 10 | "receive":"收款", 11 | "generate_new_address":"生成新位址", 12 | "generating_address":"位址生成中……", 13 | "history":"紀錄", 14 | "transfers":"交易", 15 | "addresses":"位址", 16 | "no_transfers_found":"找不到任何交易。", 17 | "no_addresses_found":"找不到任何位址。", 18 | "bundle_details":"交易包資訊", 19 | "rebroadcasting":"重新廣播交易中……", 20 | "rebroadcast":"重新廣播交易", 21 | "node_info":"節點資訊", 22 | "neighbors":"相鄰節點:{{count}} 個", 23 | "paste_trytes":"貼上三進位代碼", 24 | "paste_trytes_here":"在此貼上三進位代碼(支持陣列或 JSON)", 25 | "verifying":"驗證中……", 26 | "verifying_trytes":"驗證三進位代碼", 27 | "processing":"處理中……", 28 | "process_trytes":"處理三進位代碼", 29 | "network_spammer":"進行垃圾交易", 30 | "help_network_spamming":"進行垃圾交易有助提高 Tangle 效率。", 31 | "spamming":"垃圾交易進行中……", 32 | "spam_the_network":"進行垃圾交易", 33 | "x_transactions_generated":" 筆垃圾交易已完成。", 34 | "not_synced":"未同步", 35 | "help":"幫助", 36 | "contact":"聯絡我們", 37 | "privacy_terms":"隱私條款", 38 | "logout":"登出", 39 | "faqs":"常見問題", 40 | "community":"社區", 41 | "join_us":"加入我們", 42 | "terms_agreements":"條款與協定", 43 | "iota_tos":"IOTA 是開源軟件,最初由 IOTA AS 發明,後轉交 IOTA Foundation 負責維護和繼續開發。軟件(客戶端及 GUI)發布後,IOTA AS 及 IOTA Foundation 將不再對其負責。用戶須為自己透過 GUI 進行的所有交易負責,IOTA AS 及 IOTA Foundation 對用戶可能遭遇的任何錯誤及輸入錯誤免責。", 44 | "iota_consult":"若你對 GUI 的操作有任何疑問,請查閱《常見問題》。若有更進一步的疑問,可到 IOTA 社區提問和交流。", 45 | "attaching_to_tangle":"附加到 Tangle 中……", 46 | "attach_to_tangle":"附加到 Tangle", 47 | "attach_tangle_before_using_address":"使用位址前,須先確定已將之附加到 Tangle。", 48 | "fill_all_fields":"填寫所有欄位", 49 | "invalid_characters":"種子碼有無效字符", 50 | "mixed_case_characters":"種子碼有小寫英文字母", 51 | "new_seed_too_short":"種子碼過短", 52 | "new_seed_too_long":"種子碼過長", 53 | "not_matching":"種子碼不匹配", 54 | "invalid_input":"輸入無效", 55 | "hash":"Hash", 56 | "persistence":"進度", 57 | "confirmed":"已確認", 58 | "pending":"檢測中", 59 | "cannot_close_whilst_rebroadcasting":"重新廣播中,不能關閉。", 60 | "transaction_rebroadcasted_successfully":"成功重新廣播交易", 61 | "rebroadcast_completed":"重新廣播完成", 62 | "genesis":"始源帳戶", 63 | "show_bundle":"顯示交易包", 64 | "transfer":"{{count}} 筆交易 ", 65 | "transfer_plural":"{{count}} 筆交易", 66 | "address":"{{count}} 個位址", 67 | "address_plural":"{{count}} 個位址", 68 | "could_not_load_light_wallet_functionality":"未能載入簡易節點功能", 69 | "could_not_load_required_backend_files":"未能載入所需後靖檔案。", 70 | "browser_out_of_date":"瀏覽器版本過舊。請下載使用下列瀏覽器:", 71 | "google_chrome":"Google Chrome", 72 | "mozilla_firefox":"Mozilla Firefox", 73 | "opera":"Opera", 74 | "seed_not_secure":"你輸入的種子碼不夠安全,請加入更多不同字符。", 75 | "seed_is_required":"須提供種子碼", 76 | "connection_refused":"被拒絕連接", 77 | "logging_in":"登錄中……", 78 | "connecting":"連接中……", 79 | "no_neighbors_found":"找不到任何相鄰節點。", 80 | "please_log_in_first":"請先登錄。", 81 | "invalid_trytes_or_input":"三進位代碼或輸入資訊無效", 82 | "invalid_signature":"此簽名無效", 83 | "already_processed":"已處理", 84 | "transaction_completed":"交易完成", 85 | "yes_send_now":"確認立即轉款", 86 | "address_is_required":"須提供位址", 87 | "missing_address_checksum":"找不到位址校驗總和", 88 | "incorrect_address_length":"位址長度不正確", 89 | "incorrect_address_checksum":"位址校驗總和不正確", 90 | "amount_cannot_be_zero":"數值不能為零", 91 | "tag_is_invalid":"此標記無效", 92 | "ignoring_invalid_tag_value":"標記值無效忽略中。", 93 | "wont_overwrite_transfer_fields":"交易欄位已填上內容,覆蓋無效。", 94 | "transfer_fields_prefilled_link":"已從你點擊的 URL 獲取資訊自動填寫交易欄位內容。", 95 | "unknown_or_invalid_url":"未知或無效 URL。", 96 | "error_whilst_adding_neighbors":"添加相鄰節點時出錯。", 97 | "added_neighbor":"已添加 {{count}} 個相鄰節點。", 98 | "added_neighbor_plural":"已添加 {{count}} 個相鄰節點。", 99 | "error_whilst_removing_neighbors":"刪除相鄰節點時出錯。", 100 | "removed_neighbor":"已刪除 {{count}} 個相鄰節點。", 101 | "removed_neighbor_plural":"已刪除 {{count}} 個相鄰節點。", 102 | "new_user_read_faq":"新用戶? 先看看《常見問題》吧!", 103 | "windows_32_bit_unsupported":"目前不支援 32 位元視窗系統。", 104 | "iota_wallet_testnet":"IOTA 錢包 Testnet", 105 | "iota_wallet":"IOTA 錢包", 106 | "settings_file_does_not_exist":"設定檔案不存在", 107 | "not_supported":"不支持", 108 | "hide_status_bar":"隱藏狀態列", 109 | "show_status_bar":"顯示狀態列", 110 | "toggle_web_inspector":"開啟檢查工具", 111 | "enter_full_screen":"進入全屏", 112 | "exit_full_screen":"退出全屏", 113 | "undo":"撤銷", 114 | "redo":"重做", 115 | "cut":"剪下", 116 | "copy":"複製", 117 | "paste":"貼上", 118 | "select_all":"選擇所有", 119 | "edit":"編輯", 120 | "view":"查看", 121 | "switch_language":"切換語言", 122 | "switch":"切換", 123 | "tools":"工具", 124 | "view_node_info":"查看節點資訊", 125 | "view_neighbors":"查看相鄰節點", 126 | "view_server_log":"查看伺服器日誌", 127 | "open_database_folder":"打開資料庫檔案夾", 128 | "edit_node_configuration":"編輯節點配置", 129 | "edit_neighbors":"編輯相鄰節點", 130 | "options":"選項", 131 | "switch_to_light_node":"切換成簡易節點", 132 | "switch_to_full_node":"切換成完整節點", 133 | "save_account_data_locally":"在本地保存帳戶資料", 134 | "remove_local_account_data":"刪除本地帳戶資料", 135 | "window":"視窗", 136 | "minimize":"最小化", 137 | "close":"關閉", 138 | "faq":"常見問題", 139 | "official_website":"官方網站", 140 | "forum":"論壇", 141 | "chat":"聊天", 142 | "documentation":"文獻資料", 143 | "about_iota_wallet":"關於 IOTA 錢包", 144 | "preferences":"選項", 145 | "services":"服務", 146 | "hide_iota_wallet":"隱藏 IOTA 錢包", 147 | "hide_others":"隱藏其他", 148 | "show_all":"全部顯示", 149 | "quit":"退出", 150 | "bring_all_to_front":"全部移到最上層", 151 | "server_exited":"已退出伺服器", 152 | "iota_server_process_exited":"已退出 IOTA 伺服器程序。", 153 | "server_address_already_in_use":"已在使用此伺服器位址,請先關閉在 port {{port}} 運行的程序和服務。", 154 | "initalization_alert":"初始化警告", 155 | "server_initialization_error_occurred":"發生伺服器初始化錯誤。", 156 | "testnet_node_from_mainnet_connection":"你正嘗試將 mainnet 錢包連接到 testnet 節點,我們建議不要這樣做……", 157 | "mainnet_node_from_testnet_connection":"你正嘗試將 mainnet 節點連接到 testnet 錢包,我們建議不要這樣做……", 158 | "iri":"IRI", 159 | "server_log":"伺服器日誌", 160 | "last_messages_from_server_log":"以下是伺服器日誌最近紀錄的資訊", 161 | "save":"保存", 162 | "ok":"OK", 163 | "cancel":"取消", 164 | "yes":"是", 165 | "no":"否", 166 | "cpu":"CPU", 167 | "open_at_login":"登錄時開啟", 168 | "add_neighbor_node":"添加相鄰節點", 169 | "confirm_add_node_to_config":"確定要在伺服器配置添加此節點?", 170 | "yes_add_node":"是,添加此節點", 171 | "no_cancel":"取消", 172 | "node_config":"節點配置", 173 | "host":"主機", 174 | "min_weight_magnitude":"最低量級", 175 | "node_port":"節點埠", 176 | "depth":"深度", 177 | "neighboring_nodes":"相鄰節點", 178 | "node_settings_format":"你可以按下面的格式添加節點(一行一個)", 179 | "update_available":"有可用更新。", 180 | "update_being_downloaded":"有可用更新。下載中……", 181 | "new_update_available":"有可用更新。", 182 | "version_is_downloaded_ready_to_install":"{{版本}} 版本下載完成,並準備好進行安裝。", 183 | "install_now":"現在安裝", 184 | "install_on_quit":"退出時安裝", 185 | "update_error":"更新錯誤", 186 | "error_during_update_check":"檢查更新時出錯。", 187 | "checking_for_updates":"檢查更新中。", 188 | "checking_for_updates_please_wait":"檢查更新中,請稍候...", 189 | "no_updates":"沒有更新", 190 | "no_updates_available":"當前沒有更新。", 191 | "shutdown_in_progress":"正在關閉", 192 | "shutting_down_iota":"IOTA 關閉中……請稍候……", 193 | "error_please_restart":"出現錯誤,伺服器已退出。請重開程式。", 194 | "process_already_running":"已在運行此程序……", 195 | "iota_process_already_running_choice":"已有 IOTA 程序在運行中。如果你已在運行另一個 IOTA 程序,請先關閉該程序,然後再點撃「繼續」。", 196 | "continue":"繼續", 197 | "server_output":"伺服器輸出", 198 | "download_64_bit_java":"下載 64 位元 JAVA", 199 | "edit_settings":"編輯設置", 200 | "restart":"重開", 201 | "drag_to_applications_folder":"拖到應用程式資料夾", 202 | "drag_to_applications_folder_no_execution_from_dmg":"將應用程式拖動到應用程式資料夾,並且不會從 DMG 打開。", 203 | "java_not_found":"找不到 JAVA……", 204 | "correct_java_version_not_found":"在系統上找不到正確版本的 JAVA。", 205 | "sixtyfour_bit_java":"64-bit java", 206 | "click_to_download_or_switch_to_light_node":"點撃下面的按鈕開始下載 ,你也可以改用不需要 JAVA 的簡易節點。", 207 | "click_to_download_and_reopen_or_switch_to_light_node":"點撃下面的按鈕開始下載 ,並在安裝後重開錢包。你也可以改用不需要 JAVA 的簡易節點。", 208 | "click_to_download_or_use_terminal":"點撃下面的按鈕開始下載,或在終端輸入以下的安裝指令:", 209 | "or_depending_on_your_system":"或(按系統而定):", 210 | "light_node_alternative_no_java":"你也可以改用不需要 JAVA 的簡易節點。", 211 | "download":"下載", 212 | "choose_wallet_type":"選擇錢包類型:", 213 | "light_node_or_full_node":"選用簡易節點還是完整節點?", 214 | "light_node_description":"簡易節點會連接到遠端節點時,持有人可以是你或其他人。", 215 | "light_node":"簡易節點", 216 | "full_node":"完整節點", 217 | "full_node_description":"完整節點會下載 Tangle 到你的硬碟並進行同步。需要安裝 JAVA。", 218 | "add_in_following_format_example":"添加格式例子:\nhttp://example.com:12345", 219 | "server_port":"伺服器埠", 220 | "start":"開始", 221 | "could_not_load_hashing_library":"未能載入 hash 庫", 222 | "hashing_not_available":"沒有可用的 hashing", 223 | "invalid_trunk_transaction":"此主交易無效", 224 | "invalid_branch_transaction":"此分支交易無效", 225 | "invalid_minweight_magnitude":"最低量級無效", 226 | "interrupted":"被中斷", 227 | "wrong_bundle_order":"交易包次序錯誤", 228 | "no_server_output":"沒有伺服器輸出。", 229 | "downloading_java":"JAVA 下載中……", 230 | "java_being_downloaded":"JAVA 下載中,請稍候……", 231 | "no_response_15s":"15 秒內未有回應。", 232 | "installing_java":"JAVA 安裝中……", 233 | "java_being_installed":"JAVA 安裝中,請稍候……", 234 | "installation_failed":"安裝失敗", 235 | "installation_failed_install_manually":"安裝失敗,請手動安裝。安裝包路徑:{{location}}。", 236 | "java_downloaded":"JAVA 安裝包下載完成", 237 | "java_downloaded_please_install":"JAVA 安裝包已下載到 {{location}}。請在安裝完成後重開此應用程式。", 238 | "incorrect_status_code":"狀態碼不正確。", 239 | "could_not_match_regex":"未能匹配正則運算式。", 240 | "download_failed":"下載失敗", 241 | "download_java_manually":"**點撃此處**手動下載及安裝 JAVA。", 242 | "download_java_jre_manually":"**點撃此處**手動下載及安裝 JAVA(JRE 版本)。", 243 | "full_node_settings":"完整節點設置:", 244 | "light_node_settings":"簡易節點設置:", 245 | "seed_password":"種子碼 / 密碼", 246 | "address_attached":"附加的位址", 247 | "are_you_sure":"是否確定?", 248 | "could_not_connect_to_remote_node":"無法連接到遠端節點。", 249 | "could_not_connect_to_node":"無法連接到節點。", 250 | "change_language":"更改語言", 251 | "english":"English", 252 | "chinese":"中文(繁體)", 253 | "french":"Français", 254 | "german":"Deutsch", 255 | "greek":"Ελληνικά", 256 | "italian":"Italiano", 257 | "japanese":"日本語", 258 | "spanish":"Español", 259 | "turkish":"Türkçe", 260 | "dutch":"Nederlands", 261 | "about":"關於", 262 | "hide":"隱藏", 263 | "electron":"Electron", 264 | "submit":"提交", 265 | "success":"成功", 266 | "copied_to_clipboard":"已複製到剪貼簿。", 267 | "udp_receiver_port":"UDP 接收埠", 268 | "tcp_receiver_port":"TCP 接收埠", 269 | "invalid":"無效", 270 | "required":"必填", 271 | "reattaching":"重新添加交易中……", 272 | "reattach":"重新添加交易", 273 | "cannot_close_whilst_reattaching":"重新添加中,不能關閉。", 274 | "transaction_reattached_successfully":"成功重新添加交易", 275 | "reattach_completed":"完成重新添加交易", 276 | "transfer_completed":"交易完成", 277 | "send_limit":"傳送限制(Mbit/s)", 278 | "db_location":"資料庫位置", 279 | "invalid_seed":"種子碼無效", 280 | "amount":"金額", 281 | "select_your_host":"Select Your Host", 282 | "custom":"Custom", 283 | "custom_host":"Custom Host", 284 | "verify_trytes":"驗證三進位代碼", 285 | "allow_short_seed_login":"Allow Short Seed Login", 286 | "chinese_simplified":"中文(简体)", 287 | "chinese_traditional":"中文 (繁體)", 288 | "portugese":"Português", 289 | "russian":"Русский", 290 | "swedish":"Svenska", 291 | "korean":"Korean", 292 | "seed":"Seed", 293 | "seed_too_short":"Seed too Short", 294 | "seed_too_long":"Seed too Long", 295 | "could_not_connect":"Could Not Connect", 296 | "no_connection":"No Connection", 297 | "submit_bug_report":"Submit Bug Report", 298 | "bug_report":"Bug Report", 299 | "issue":"Issue", 300 | "title":"Title", 301 | "description":"Description", 302 | "username":"Username", 303 | "password":"Password", 304 | "send_using_github_account":"Send Using GitHub Account", 305 | "send_using_email":"Send Using Email", 306 | "describe_issue":"Describe the Issue in Detail", 307 | "invalid_address":"Invalid Address", 308 | "seed_checksum":"Seed Checksum", 309 | "invalid_response":"Invalid Response", 310 | "no_connection_to_host":"No Connection to Host", 311 | "request_error":"Request Error" 312 | } -------------------------------------------------------------------------------- /app/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | background: #028b7e; 5 | min-height: 100% !important; 6 | -webkit-font-smoothing: antialiased; 7 | } 8 | 9 | * { 10 | font-size:16px; 11 | font-family: arial, sans-serif; 12 | } 13 | 14 | html, body { 15 | height:100%; 16 | overflow:hidden; 17 | } 18 | 19 | #server { 20 | width: 100%; 21 | height: 100%; 22 | transition: 0.5s all; 23 | } 24 | 25 | /* TINGLE MODAL */ 26 | 27 | .tingle-modal * { 28 | box-sizing: border-box; 29 | } 30 | 31 | .tingle-modal { 32 | position: fixed; 33 | top: 0; 34 | right: 0; 35 | bottom: 0; 36 | left: 0; 37 | z-index: 1000; 38 | z-index: 1000; 39 | visibility: hidden; 40 | overflow-y: auto; 41 | background: rgba(0, 0, 0, .6); 42 | opacity: 0; 43 | padding: 10px 10px 0; 44 | text-align: center; 45 | overflow: auto; 46 | -webkit-transition: opacity .2s ease; 47 | transition: opacity .2s ease;; 48 | } 49 | 50 | .tingle-modal-box { 51 | padding: 35px; 52 | width: 100%; 53 | position: static; 54 | top: auto; 55 | left: auto; 56 | right: auto; 57 | bottom: auto; 58 | vertical-align: middle; 59 | display: inline-block; 60 | -webkit-transform: scale(0.7); 61 | -moz-transform: scale(0.7); 62 | -ms-transform: scale(0.7); 63 | transform: scale(0.7); 64 | opacity: 0; 65 | -webkit-transition: all 0.3s; 66 | -moz-transition: all 0.3s; 67 | transition: all 0.3s; 68 | background: #fff; 69 | } 70 | 71 | .tingle-modal:after, .tingle-modal-box { 72 | vertical-align: middle; 73 | } 74 | 75 | .tingle-modal:after { 76 | display: inline-block; 77 | height: 100%; 78 | margin-left: -0.05em; 79 | content: ""; 80 | } 81 | 82 | .tingle-modal > .tingle-modal__close { 83 | display: none; 84 | } 85 | 86 | .tingle-modal__close { 87 | position: absolute; 88 | top: 0; 89 | left: 0; 90 | display: block; 91 | overflow: visible; 92 | width: 35px; 93 | height: 35px; 94 | margin: 0; 95 | padding: 0; 96 | cursor: pointer; 97 | text-decoration: none; 98 | color: #95979c; 99 | border: none; 100 | outline: none; 101 | background: transparent; 102 | font-size: 25px; 103 | line-height: normal; 104 | font-weight: bold; 105 | z-index: 1000; 106 | } 107 | 108 | .tingle-modal-box__content, .tingle-modal-box__footer { 109 | padding: 0; 110 | background: #fff; 111 | text-align: center; 112 | } 113 | 114 | .tingle-modal-box__footer::after { 115 | display: table; 116 | clear: both; 117 | content: ""; 118 | } 119 | 120 | .tingle-modal-box__content p:first-child { 121 | margin-top: 0; 122 | } 123 | 124 | @media only screen and (min-width: 641px) { 125 | .tingle-modal-box { 126 | max-width: 700px; 127 | } 128 | } 129 | 130 | .tingle-modal-box textarea { 131 | width:100%; 132 | font-family:"Courier New",courier; 133 | } 134 | 135 | .tingle-modal-box__content h1 { 136 | margin: 0; 137 | padding: 0; 138 | margin-bottom: 20px; 139 | text-transform: uppercase; 140 | font-size: 28px; 141 | font-weight: 300; 142 | text-align: center; 143 | } 144 | 145 | .tingle-btn { 146 | width: 100%; 147 | outline: none; 148 | display: block; 149 | color: #fff; 150 | text-transform: uppercase; 151 | text-align: center; 152 | text-decoration: none; 153 | font-size: 24px; 154 | border: none; 155 | cursor: pointer; 156 | background: #3b2b70; 157 | padding: 20px; 158 | margin: 0; 159 | margin-top: 15px; 160 | } 161 | 162 | .tingle-btn--default { 163 | background-color: #3498db; 164 | } 165 | 166 | .update-downloaded .tingle-btn { 167 | width: 48%; 168 | } 169 | 170 | .update-downloaded .tingle-btn--primary { 171 | float: left; 172 | } 173 | 174 | .update-downloaded .tingle-btn--default { 175 | float: right; 176 | } 177 | 178 | .tingle-enabled { 179 | overflow: hidden; 180 | height: 100%; 181 | } 182 | 183 | .tingle-modal--visible .tingle-modal-box__footer { 184 | bottom: 0; 185 | } 186 | 187 | .tingle-modal--visible { 188 | visibility: visible; 189 | opacity: 1; 190 | } 191 | 192 | .tingle-modal--visible .tingle-modal-box { 193 | -webkit-transform: scale(1); 194 | -moz-transform: scale(1); 195 | -ms-transform: scale(1); 196 | transform: scale(1); 197 | opacity: 1; 198 | } 199 | 200 | ::-webkit-scrollbar { 201 | background-color: transparent; 202 | width: 8px; 203 | height: 16px; 204 | } 205 | 206 | ::-webkit-scrollbar-thumb { 207 | border-radius: 10px; 208 | background-color: #a4a8ab; 209 | } 210 | 211 | label, span.label { 212 | font-weight:bold; 213 | text-align:left; 214 | font-size:22px; 215 | margin:0; 216 | margin-bottom: 5px; 217 | padding: 0; 218 | display: block; 219 | } 220 | 221 | span.label { 222 | display: inline-block; 223 | } 224 | 225 | input { 226 | box-sizing: border-box; 227 | width: 100%; 228 | border: 0; 229 | outline: 0; 230 | background: transparent; 231 | border-bottom: 1px solid #7e8688; 232 | color: #000; 233 | padding: 0; 234 | font-size: 20px; 235 | } 236 | 237 | .input-group { 238 | margin-bottom: 10px; 239 | } 240 | 241 | .input-group-last { 242 | margin-bottom: 0 !important; 243 | } 244 | 245 | ::-webkit-input-placeholder { 246 | color: #7e8688; 247 | } 248 | 249 | :-moz-placeholder { 250 | color: #7e8688; 251 | opacity: 1; 252 | } 253 | 254 | ::-moz-placeholder { 255 | color: #7e8688; 256 | opacity: 1; 257 | } 258 | 259 | :-ms-input-placeholder { 260 | color: #7e8688; 261 | } 262 | 263 | :placeholder-shown { 264 | color: #7e8688; 265 | } 266 | 267 | #status-bar, #new-user { 268 | display: none; 269 | background: #f0f0f0; 270 | color: rgba(0, 0, 0, 0.6); 271 | box-sizing: border-box; 272 | padding-left: 5px; 273 | padding-right: 5px; 274 | height:20px; 275 | line-height: 20px; 276 | display: none; 277 | } 278 | 279 | #status-bar { 280 | justify-content: space-between; 281 | } 282 | 283 | #new-user { 284 | background: #FFBA3A; 285 | color: #000; 286 | text-align: center; 287 | cursor: pointer; 288 | } 289 | 290 | #status-bar span { 291 | font-size: 14px; 292 | } 293 | 294 | body.status-bar-active #server, body.new-user-active #server { 295 | height: calc(100% - 20px); 296 | } 297 | 298 | body.status-bar-active #status-bar { 299 | display: flex; 300 | 301 | } 302 | 303 | body.new-user-active #new-user { 304 | display: block; 305 | } 306 | 307 | #status-bar-giota span { 308 | font-weight: bold; 309 | } 310 | 311 | body.full-node #status-bar-milestone, body.full-node #status-bar-solid-milestone { 312 | cursor: pointer; 313 | } 314 | 315 | /* 316 | #status-bar ul { 317 | margin: 0; 318 | padding: 0; 319 | } 320 | 321 | #status-bar ul li { 322 | display: inline-block; 323 | font-size: 14px; 324 | margin: 0; 325 | padding: 0; 326 | } 327 | 328 | #status-bar ul li:after { 329 | content:"•"; 330 | margin-left: 5px; 331 | margin-right: 5px; 332 | }*/ 333 | 334 | 335 | @media only screen and (max-width: 460px) { 336 | .tingle-modal-box { 337 | padding: 20px; 338 | } 339 | } 340 | 341 | @media only screen and (max-width: 400px) { 342 | .tingle-modal-box { 343 | padding: 15px; 344 | } 345 | 346 | input { 347 | font-size: 18px; 348 | } 349 | 350 | label, span.label { 351 | font-size: 16px; 352 | } 353 | } 354 | 355 | .list ul { 356 | list-style-type: none; 357 | margin: 0; 358 | padding: 0; 359 | } 360 | 361 | .list li:last-child { 362 | border-bottom: none !important; 363 | } 364 | 365 | .list li:first-child { 366 | padding-top: 0 !important; 367 | } 368 | 369 | .list li { 370 | display: -webkit-box; 371 | display: -ms-flexbox; 372 | display: -webkit-flex; 373 | display: flex; 374 | justify-content: space-between; 375 | align-items: center; 376 | padding-top: 10px; 377 | padding-bottom: 10px; 378 | border-bottom: 1px solid #efefef; 379 | } 380 | 381 | .list li > div { 382 | display: inline-block; 383 | } 384 | 385 | .list .address, .overflow-text { 386 | white-space: nowrap; 387 | overflow: hidden; 388 | text-overflow: ellipsis; 389 | -o-text-overflow: ellipsis; 390 | width: 100%; 391 | -webkit-text-overflow: ellipsis; 392 | } 393 | 394 | .list .value { 395 | padding-left: 15px; 396 | text-align: right; 397 | width: auto; 398 | font-weight: bold; 399 | margin-right: 0 !important; 400 | } 401 | 402 | .list p { 403 | margin-right: 50px; 404 | margin-left: 50px; 405 | } 406 | 407 | .list .details { 408 | overflow: hidden; 409 | } 410 | 411 | .list .details.details-milestone .address { 412 | overflow: none; 413 | } 414 | 415 | .list .value.value-latestSolidSubtangleMilestone, .list .value.value-latestMilestone { 416 | white-space: nowrap; 417 | overflow: hidden; 418 | text-overflow: ellipsis; 419 | -o-text-overflow: ellipsis; 420 | width: 100%; 421 | -webkit-text-overflow: ellipsis; 422 | } 423 | 424 | .hash { 425 | color: #696969; 426 | } 427 | 428 | .peers-modal .contents { 429 | max-height: 450px; 430 | overflow: none; 431 | overflow-y: auto; 432 | padding-right: 5px; 433 | } 434 | 435 | .clipboard { 436 | cursor: pointer; 437 | } 438 | 439 | @media only screen and (max-width: 980px) { 440 | h1 { 441 | padding-left: 30px; 442 | padding-top: 30px; 443 | margin-bottom: 30px; 444 | } 445 | 446 | .list .value { 447 | margin-right: 30px; 448 | } 449 | 450 | .list p { 451 | margin-right: 30px; 452 | margin-left: 30px; 453 | } 454 | } 455 | 456 | @media only screen and (max-height: 735px), only screen and (max-width: 519px) { /* 519px */ 457 | h1 { 458 | padding-left: 20px; 459 | padding-top: 20px; 460 | margin-bottom: 20px; 461 | } 462 | 463 | .list .value { 464 | margin-right: 20px; 465 | } 466 | 467 | .list p { 468 | margin-right: 20px; 469 | margin-left: 20px; 470 | } 471 | } 472 | 473 | @media only screen and (max-height: 620px), only screen and (max-width: 440px) { /* 440px */ 474 | h1 { 475 | padding-left: 15px; 476 | padding-top: 15px; 477 | margin-bottom: 15px; 478 | } 479 | 480 | .list .value { 481 | margin-right: 15px; 482 | } 483 | 484 | .list p { 485 | margin-right: 15px; 486 | margin-left: 15px; 487 | } 488 | } 489 | 490 | @media only screen and (max-height: 582px), only screen and (max-width: 414px) { /* 414px */ 491 | h1 { 492 | font-size: 24px; 493 | } 494 | } 495 | 496 | .label--checkbox { 497 | position: relative; 498 | cursor: pointer; 499 | } 500 | 501 | .checkbox { 502 | position: relative; 503 | top: -0.375rem; 504 | margin: 0 1rem 0 0; 505 | cursor: pointer; 506 | display:inline; 507 | width:auto; 508 | } 509 | 510 | .checkbox:before { 511 | -webkit-transition: all 0.3s ease-in-out; 512 | -moz-transition: all 0.3s ease-in-out; 513 | transition: all 0.3s ease-in-out; 514 | content: ""; 515 | position: absolute; 516 | left: 0; 517 | z-index: 1; 518 | width: 1rem; 519 | height: 1rem; 520 | border: 2px solid #e0e0e0; 521 | } 522 | .checkbox:checked:before { 523 | -webkit-transform: rotate(-45deg); 524 | -moz-transform: rotate(-45deg); 525 | -ms-transform: rotate(-45deg); 526 | -o-transform: rotate(-45deg); 527 | transform: rotate(-45deg); 528 | height: .5rem; 529 | border-color: #000; 530 | border-top-style: none; 531 | border-right-style: none; 532 | margin-top: 2px; 533 | } 534 | 535 | .checkbox:after { 536 | content: ""; 537 | position: absolute; 538 | top: -0.125rem; 539 | left: 0; 540 | width: 1.1rem; 541 | height: 1.1rem; 542 | background: #fff; 543 | cursor: pointer; 544 | } 545 | 546 | .error { 547 | color: red; 548 | } 549 | 550 | .file-path { 551 | overflow: hidden; 552 | white-space: nowrap; 553 | text-overflow: ellipsis; 554 | direction: rtl; 555 | text-align: left; 556 | } 557 | 558 | button.small { 559 | padding: 2px; 560 | background: gray; 561 | color: white; 562 | border-radius: 3px; 563 | outline: none; 564 | border: none; 565 | cursor: pointer; 566 | margin: 0; 567 | } 568 | 569 | #server_config_host_select, #server_config_curl_implementation_select { 570 | width: 100%; 571 | } 572 | 573 | hr { 574 | border: none; 575 | height: 1px; 576 | color: #7e8688; 577 | background-color: #7e8688; 578 | } 579 | -------------------------------------------------------------------------------- /locales/zh-CN/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "login":"登录", 3 | "error":"错误", 4 | "balance":"余额", 5 | "send":"发送", 6 | "recipient_address":"接收人地址", 7 | "optional_tag":"可选标签", 8 | "sending":"发送中……", 9 | "send_it_now":"立刻发送", 10 | "receive":"接收", 11 | "generate_new_address":"生成新地址", 12 | "generating_address":"地址生成中……", 13 | "history":"历史", 14 | "transfers":"转账", 15 | "addresses":"地址", 16 | "no_transfers_found":"没有找到转账记录。", 17 | "no_addresses_found":"没有找到地址。", 18 | "bundle_details":"Bundle Details", 19 | "rebroadcasting":"重新广播中……", 20 | "rebroadcast":"重新广播", 21 | "node_info":"节点信息", 22 | "neighbors":"邻域 ({{count}})", 23 | "paste_trytes":"粘贴Trytes", 24 | "paste_trytes_here":"在这里粘贴你的Trytes(以数组排列或者基于JavaScript语言轻量级数据交换格式排列)", 25 | "verifying":"验证中……", 26 | "verifying_trytes":"验证Trytes", 27 | "processing":"处理中……", 28 | "process_trytes":"处理Trytes", 29 | "network_spammer":"网络攻击者", 30 | "help_network_spamming":"已处理", 31 | "spamming":"交易完成", 32 | "spam_the_network":"攻击网络", 33 | "x_transactions_generated":"生成了X笔交易。", 34 | "not_synced":"不同步", 35 | "help":"帮助", 36 | "contact":"联系", 37 | "privacy_terms":"隐私&条款", 38 | "logout":"退出", 39 | "faqs":"常见问题解答", 40 | "community":"社区", 41 | "join_us":"加入我们", 42 | "terms_agreements":"条款&协议", 43 | "iota_tos":"IOTA是一个开源的软件,由IOTA AS进行开发,之后转交给了IOTA基金会进行维护和进一步开发。至于该软件(客户端和用户界面)发布后的一切事项,IOTA AS和IOTA基金会将不承担任何责任。通过这一界面进行的所有交易由用户负责。对于用户可能遇到的错误或者乌龙事件,IOTA AS和IOTA基金会不承担任何责任。", 44 | "iota_consult":"如果您不清楚如何操作用户界面,请查看常见问题解答。如果仍不清楚可以咨询IOTA社区。", 45 | "attaching_to_tangle":"添加Tangle中……", 46 | "attach_to_tangle":"添加Tangle", 47 | "attach_tangle_before_using_address":"在使用地址之前确保Tangle已经添加完成。", 48 | "fill_all_fields":"填满所有字段", 49 | "invalid_characters":"无效字符", 50 | "mixed_case_characters":"大小写混合字符", 51 | "new_seed_too_short":"新种子太短", 52 | "new_seed_too_long":"新种子太长", 53 | "not_matching":"不匹配", 54 | "invalid_input":"无效输入", 55 | "hash":"哈希", 56 | "persistence":"存留", 57 | "confirmed":"已确认", 58 | "pending":"等待确认", 59 | "cannot_close_whilst_rebroadcasting":"重新广播中无法关闭。", 60 | "transaction_rebroadcasted_successfully":"交易重新广播成功", 61 | "rebroadcast_completed":"重新广播完成", 62 | "genesis":"创始", 63 | "show_bundle":"Show Bundle", 64 | "transfer":"{{count}} 笔转账", 65 | "transfer_plural":"{{count}} 两笔转账", 66 | "address":"{{count}} 个地址", 67 | "address_plural":"{{count}} 两个地址", 68 | "could_not_load_light_wallet_functionality":"无法加载完整轻钱包", 69 | "could_not_load_required_backend_files":"无法加载所需后端文件。", 70 | "browser_out_of_date":"您的浏览器已版本过低。请下载下列最新的免费浏览器:", 71 | "google_chrome":"谷歌浏览器", 72 | "mozilla_firefox":"火狐浏览器", 73 | "opera":"欧朋浏览器", 74 | "seed_not_secure":"您的种子字符数不足,将面临安全问题。", 75 | "seed_is_required":"需要输入种子", 76 | "connection_refused":"连接失败", 77 | "logging_in":"登录中……", 78 | "connecting":"连接中……", 79 | "no_neighbors_found":"没有发现邻域。", 80 | "please_log_in_first":"请先登录。", 81 | "invalid_trytes_or_input":"无效Trytes或输入", 82 | "invalid_signature":"无效签名", 83 | "already_processed":"Already processed", 84 | "transaction_completed":"Transaction completed", 85 | "yes_send_now":"是的,立刻发送", 86 | "address_is_required":"需要输入地址", 87 | "missing_address_checksum":"缺少地址校验码", 88 | "incorrect_address_length":"地址长度错误", 89 | "incorrect_address_checksum":"地址校验码错误", 90 | "amount_cannot_be_zero":"数量不能为零", 91 | "tag_is_invalid":"无效标签", 92 | "ignoring_invalid_tag_value":"标签值无效。已忽略……", 93 | "wont_overwrite_transfer_fields":"转账字段已填写完毕,不会覆盖。", 94 | "transfer_fields_prefilled_link":"转账字段已在上个链接中填写完毕。", 95 | "unknown_or_invalid_url":"未知或无效的URL。", 96 | "error_whilst_adding_neighbors":"添加邻域有误", 97 | "added_neighbor":"添加 {{count}} 个领域", 98 | "added_neighbor_plural":"添加两 {{count}} 个领域", 99 | "error_whilst_removing_neighbors":"移除邻域有误", 100 | "removed_neighbor":"移除 {{count}} 个邻域", 101 | "removed_neighbor_plural":"移除两 {{count}} 个邻域", 102 | "new_user_read_faq":"第一次使用IOTA?先看看FAQ吧!", 103 | "windows_32_bit_unsupported":"目前不支持Windows 32-位", 104 | "iota_wallet_testnet":"IOTA钱包测试网", 105 | "iota_wallet":"IOTA钱包", 106 | "settings_file_does_not_exist":"配置文件不存在", 107 | "not_supported":"不支持", 108 | "hide_status_bar":"隐藏状态栏", 109 | "show_status_bar":"显示状态栏", 110 | "toggle_web_inspector":"启动web检查器", 111 | "enter_full_screen":"全屏模式", 112 | "exit_full_screen":"退出全屏", 113 | "undo":"撤销", 114 | "redo":"重做", 115 | "cut":"剪切", 116 | "copy":"复制", 117 | "paste":"粘贴", 118 | "select_all":"全选", 119 | "edit":"编辑", 120 | "view":"查看", 121 | "switch_language":"切换语言", 122 | "switch":"切换", 123 | "tools":"工具", 124 | "view_node_info":"查看节点信息", 125 | "view_neighbors":"查看邻域", 126 | "view_server_log":"查看服务器日志", 127 | "open_database_folder":"公开数据库文件夹", 128 | "edit_node_configuration":"编辑节点配置", 129 | "edit_neighbors":"编辑邻居节点", 130 | "options":"选项", 131 | "switch_to_light_node":"切换到轻节点", 132 | "switch_to_full_node":"切换到全节点", 133 | "save_account_data_locally":"本地保存账户数据", 134 | "remove_local_account_data":"移除本地账户数据", 135 | "window":"窗口", 136 | "minimize":"最小化", 137 | "close":"关闭", 138 | "faq":"常见问题解答", 139 | "official_website":"官方网站", 140 | "forum":"论坛", 141 | "chat":"聊天", 142 | "documentation":"文献资料", 143 | "about_iota_wallet":"关于IOTA钱包", 144 | "preferences":"参数选择", 145 | "services":"服务", 146 | "hide_iota_wallet":"隐藏IOTA钱包", 147 | "hide_others":"隐藏其它", 148 | "show_all":"显示全部", 149 | "quit":"退出", 150 | "bring_all_to_front":"全部置顶", 151 | "server_exited":"退出服务器", 152 | "iota_server_process_exited":"IOTA服务器进程已退出。", 153 | "server_address_already_in_use":"这个服务器地址已经在使用中。请关闭所有运行在端口 {{port}} 的apps和服务。", 154 | "initalization_alert":"初始化警报", 155 | "server_initialization_error_occurred":"服务器初始化错误。", 156 | "testnet_node_from_mainnet_connection":"您的主网钱包正在和测试网节点建立连接。不建议您这么做……", 157 | "mainnet_node_from_testnet_connection":"您的测试网钱包正在和主网节点建立连接。不建议您这么做……", 158 | "iri":"国际化资源标识符", 159 | "server_log":"服务器日志", 160 | "last_messages_from_server_log":"以下是服务器日志记录的最后一段信息", 161 | "save":"保存", 162 | "ok":"好的", 163 | "cancel":"取消", 164 | "yes":"是", 165 | "no":"否", 166 | "cpu":"中央处理器", 167 | "open_at_login":"登录时打开", 168 | "add_neighbor_node":"添加邻域节点", 169 | "confirm_add_node_to_config":"您是否确认将这一节点添加到自己的服务器配置中?", 170 | "yes_add_node":"是,添加这个节点", 171 | "no_cancel":"否,取消", 172 | "node_config":"节点配置", 173 | "host":"主机", 174 | "min_weight_magnitude":"最小重量级", 175 | "node_port":"节点端口", 176 | "depth":"深度", 177 | "neighboring_nodes":"邻域节点", 178 | "node_settings_format":"以下列格式呈现节点(一个一行)", 179 | "update_available":"可用更新", 180 | "update_being_downloaded":"有可用更新,正在下载。", 181 | "new_update_available":"可用更新", 182 | "version_is_downloaded_ready_to_install":"版本 {{version}} 已下载,正在准备安装。", 183 | "install_now":"立刻安装", 184 | "install_on_quit":"Install on quit", 185 | "update_error":"更新错误", 186 | "error_during_update_check":"检查更新时出现错误。", 187 | "checking_for_updates":"检查更新。", 188 | "checking_for_updates_please_wait":"检查更新中,请等待……", 189 | "no_updates":"没有可用更新", 190 | "no_updates_available":"没有可用更新", 191 | "shutdown_in_progress":"关闭运行中进程", 192 | "shutting_down_iota":"关闭IOTA中……请等待。", 193 | "error_please_restart":"出现错误,服务器已退出。请重启应用。", 194 | "process_already_running":"程序运行中……", 195 | "iota_process_already_running_choice":"IOTA进程已在运行中。如有另一个IOTA应用在运行,请在继续下一步操作前关闭这一应用。如没有,点击“继续”。", 196 | "continue":"继续", 197 | "server_output":"服务器输出", 198 | "download_64_bit_java":"下载64-位Java", 199 | "edit_settings":"编辑设置", 200 | "restart":"重启", 201 | "drag_to_applications_folder":"拖动到应用文件夹", 202 | "drag_to_applications_folder_no_execution_from_dmg":"拖动这一应用到应用文件夹,不要在数据管理组(SMG)中打开。", 203 | "java_not_found":"未找到Java……", 204 | "correct_java_version_not_found":"您的系统中未找到正确的java版本。", 205 | "sixtyfour_bit_java":"64-位java", 206 | "click_to_download_or_switch_to_light_node":"点击下方按钮开始下载。也可切换到轻节点,无需使用java。", 207 | "click_to_download_and_reopen_or_switch_to_light_node":"点击下方按钮开始下载。安装完毕之后重新打开钱包。也可切换到轻节点,无需使用java。", 208 | "click_to_download_or_use_terminal":"点击下方按钮开始下载,或者在终端输入以下命令进行安装:", 209 | "or_depending_on_your_system":"或者(取决于您的系统):", 210 | "light_node_alternative_no_java":"也可切换到轻节点,无需使用java。", 211 | "download":"下载", 212 | "choose_wallet_type":"选择钱包类型:", 213 | "light_node_or_full_node":"您想运行在轻节点模式还是全节点模式?", 214 | "light_node_description":"轻节点与远程节点连接,持有者可以是您也可以是其他人。", 215 | "light_node":"轻节点", 216 | "full_node":"全节点", 217 | "full_node_description":"全节点将会下载并且同步您的磁盘,需要安装java。", 218 | "add_in_following_format_example":"以下列格式进行添加:http://例子.com:12345", 219 | "server_port":"服务器端口", 220 | "start":"开始", 221 | "could_not_load_hashing_library":"不能加载哈希库", 222 | "hashing_not_available":"不能进行哈希运算", 223 | "invalid_trunk_transaction":"无效的trunk交易", 224 | "invalid_branch_transaction":"无效的branch交易", 225 | "invalid_minweight_magnitude":"无效的最小权重", 226 | "interrupted":"已中断", 227 | "wrong_bundle_order":"错误的包序列", 228 | "no_server_output":"没有服务器输出", 229 | "downloading_java":"正在下载 java...", 230 | "java_being_downloaded":"正在下载Java程序包,请稍等...", 231 | "no_response_15s":"在 15 秒内没有响应。", 232 | "installing_java":"正在安装 Java...", 233 | "java_being_installed":"正在安装Java中,请稍等...", 234 | "installation_failed":"安装失败!", 235 | "installation_failed_install_manually":"安装失败,请手动进行安装。安装文件位于{{location}}", 236 | "java_downloaded":"Java已下载成功", 237 | "java_downloaded_please_install":"Java has been downloaded to {{location}} - please install it and reopen this app after installation.", 238 | "incorrect_status_code":"Incorrect status code.", 239 | "could_not_match_regex":"Could not match regex.", 240 | "download_failed":"下载失败!", 241 | "download_java_manually":"Please **click here** to download and install java manually.", 242 | "download_java_jre_manually":"Please **click here** to download and install java manually (JRE version).", 243 | "full_node_settings":"Full Node Settings:", 244 | "light_node_settings":"Light Node Settings:", 245 | "seed_password":"Seed / Password", 246 | "address_attached":"Address Attached", 247 | "are_you_sure":"确定?", 248 | "could_not_connect_to_remote_node":"Could not connect to remote node.", 249 | "could_not_connect_to_node":"无法连接到主机", 250 | "change_language":"更改语言", 251 | "english":"English", 252 | "chinese":"中文", 253 | "french":"Français", 254 | "german":"Deutsch", 255 | "greek":"Ελληνικά", 256 | "italian":"Italiano", 257 | "japanese":"日本語", 258 | "spanish":"Español", 259 | "turkish":"Türkçe", 260 | "dutch":"Nederlands", 261 | "about":"About", 262 | "hide":"Hide", 263 | "electron":"Electron", 264 | "submit":"Submit", 265 | "success":"Success", 266 | "copied_to_clipboard":"Copied to Clipboard.", 267 | "udp_receiver_port":"UDP 接收端口", 268 | "tcp_receiver_port":"TCP 接收端口", 269 | "invalid":"Invalid", 270 | "required":"Required", 271 | "reattaching":"Reattaching...", 272 | "reattach":"REATTACH", 273 | "cannot_close_whilst_reattaching":"Cannot close whilst reattaching.", 274 | "transaction_reattached_successfully":"Transaction reattached successfully", 275 | "reattach_completed":"Reattach completed", 276 | "transfer_completed":"Transfer completed", 277 | "send_limit":"Send Limit (Mbit/s)", 278 | "db_location":"Database Location", 279 | "invalid_seed":"Invalid Seed", 280 | "amount":"Amount", 281 | "select_your_host":"选择主机", 282 | "custom":"Custom", 283 | "custom_host":"Custom Host", 284 | "verify_trytes":"Verify Trytes", 285 | "allow_short_seed_login":"Allow Short Seed Login", 286 | "chinese_simplified":"中文(简体)", 287 | "chinese_traditional":"中文(繁體)", 288 | "portugese":"Português", 289 | "russian":"Русский", 290 | "swedish":"Svenska", 291 | "korean":"韩语", 292 | "seed":"Seed", 293 | "seed_too_short":"Seed too Short", 294 | "seed_too_long":"Seed too Long", 295 | "could_not_connect":"无法连接", 296 | "no_connection":"沒有連接", 297 | "submit_bug_report":"Submit Bug Report", 298 | "bug_report":"Bug Report", 299 | "issue":"Issue", 300 | "title":"Title", 301 | "description":"Description", 302 | "username":"Username", 303 | "password":"密码", 304 | "send_using_github_account":"Send Using GitHub Account", 305 | "send_using_email":"Send Using Email", 306 | "describe_issue":"描述问题的细节", 307 | "invalid_address":"Invalid Address", 308 | "seed_checksum":"Seed Checksum", 309 | "invalid_response":"Invalid Response", 310 | "no_connection_to_host":"No Connection to Host", 311 | "request_error":"Request Error" 312 | } -------------------------------------------------------------------------------- /locales/ko/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "login":"로그인", 3 | "error":"에러", 4 | "balance":"잔액", 5 | "send":"보내기", 6 | "recipient_address":"받는이 주소", 7 | "optional_tag":"태그 입력", 8 | "sending":"보내는 중...", 9 | "send_it_now":"지금 보내기", 10 | "receive":"받기", 11 | "generate_new_address":"새 주소 생성하기", 12 | "generating_address":"주소 만드는 중...", 13 | "history":"내역", 14 | "transfers":"트랜스퍼", 15 | "addresses":"주소", 16 | "no_transfers_found":"트랜스퍼를 찾을 수 없음", 17 | "no_addresses_found":"주소를 찾을 수 없음", 18 | "bundle_details":"번들 세부사항", 19 | "rebroadcasting":"리브로드캐스트 중...", 20 | "rebroadcast":"리브로드캐스트하기", 21 | "node_info":"노드 정보", 22 | "neighbors":"이웃들 ({{count}})", 23 | "paste_trytes":"Trytes 붙여넣기", 24 | "paste_trytes_here":"당신의 Trytes를 여기에 붙여넣기하시오. (Array or JSON representation)", 25 | "verifying":"확인 중...", 26 | "verifying_trytes":"Trytes 확인하기", 27 | "processing":"프로세스 중...", 28 | "process_trytes":"Trytes 프로세스하기", 29 | "network_spammer":"네트워크 스패머", 30 | "help_network_spamming":"스패밍으로 네트워크를 도와주십시오.", 31 | "spamming":"스팸 중...", 32 | "spam_the_network":"네트워크 스팸하기.", 33 | "x_transactions_generated":"X 트랜잭션 생성됨.", 34 | "not_synced":"동기화되지 않음", 35 | "help":"도움", 36 | "contact":"문의하기", 37 | "privacy_terms":"개인 정보 보호 약관", 38 | "logout":"로그아웃", 39 | "faqs":"FAQ", 40 | "community":"커뮤니티", 41 | "join_us":"IOTA 커뮤니티에 참여하기", 42 | "terms_agreements":"동의서 조항", 43 | "iota_tos":"IOTA는 IOTA AS에 의해 처음으로 개발되어 IOTA Foundation에 프로그램 정비와 더 나아간 발전을 위해 넘겨진 오픈소스 소프트웨어입니다. 그렇기 때문에 IOTA AS와 IOTA Foundation 는 이 소프트웨어(Client와 GUI)의 개시 이후의 책임을 지지 않습니다. Graphical User Interface(GUI)를 통해 이루어진 모든 거래들은 사용자의 책임이고 IOTA AS와 IOTA Foundation는 어떠한 에러나 사용자의 의도치 않은 오타 등에 관한 책임을 지지 않습니다.", 44 | "iota_consult":"GUI를 어떻게 사용해야하는지 잘 모르겠다면 FAQ를 참고하십시오. 만일 그래도 어려움을 겪는다면 IOTA 커뮤니티에 문의하십시오.", 45 | "attaching_to_tangle":"Tangle에 연결하는 중...", 46 | "attach_to_tangle":"Tangle에 연결하기", 47 | "attach_tangle_before_using_address":"주소를 사용하기 전에 반드시 Tangle에 연결하십시오.", 48 | "fill_all_fields":"모든 사항에 기입하시오.", 49 | "invalid_characters":"인식 불가능한 글자입니다.", 50 | "mixed_case_characters":"대/소문자 혼합", 51 | "new_seed_too_short":"새로운 씨드/비밀번호가 너무 짧습니다.", 52 | "new_seed_too_long":"새로운 씨드/비밀번호가 너무 깁니다.", 53 | "not_matching":"일치하지 않음", 54 | "invalid_input":"부정확한 인풋입니다.", 55 | "hash":"해쉬", 56 | "persistence":"지속", 57 | "confirmed":"확인됨", 58 | "pending":"보류", 59 | "cannot_close_whilst_rebroadcasting":"리브로드캐스트하는 중에는 닫을 수 없습니다.", 60 | "transaction_rebroadcasted_successfully":" 리브로드캐스팅 성공", 61 | "rebroadcast_completed":"리브로드캐스팅 완료", 62 | "genesis":"제네시스", 63 | "show_bundle":"번들 보이기", 64 | "transfer":"{{count}} 트랜스퍼", 65 | "transfer_plural":"{{count}} 트랜스퍼들", 66 | "address":"{{count}} 주소", 67 | "address_plural":"{{count}} 주소들", 68 | "could_not_load_light_wallet_functionality":"라이트 지갑 기능을 불러올 수 없음", 69 | "could_not_load_required_backend_files":"필요한 백앤드 파일들을 불러올 수 없음.", 70 | "browser_out_of_date":"웹브라우저가 오래된 버전입니다. 훌륭하고도 무료인 이 최신 브라우저들 중 하나를 설치해주십시오.:", 71 | "google_chrome":"구글 크롬", 72 | "mozilla_firefox":"모질라 파이어폭스", 73 | "opera":"오페라", 74 | "seed_not_secure":"씨드/비밀번호에 충분한 글자가 포함되어 있지 않습니다. 안전하지 않습니다.", 75 | "seed_is_required":"씨드/비밀번호가 필요합니다. ", 76 | "connection_refused":"연결 거부됨", 77 | "logging_in":"로그인 중...", 78 | "connecting":"연결 중...", 79 | "no_neighbors_found":"이웃을 찾을 수 없음.", 80 | "please_log_in_first":"먼저 로그인을 하십시오.", 81 | "invalid_trytes_or_input":"인식 불가능한 Trytes 이거나 인풋입니다.", 82 | "invalid_signature":"부정확한 서명", 83 | "already_processed":"이미 프로세스됨.", 84 | "transaction_completed":"거래 완료됨.", 85 | "yes_send_now":"네, 지금 보내겠습니다.", 86 | "address_is_required":"주소가 필요합니다.", 87 | "missing_address_checksum":"누락된 주소 체크섬", 88 | "incorrect_address_length":"부정확한 주소 길이", 89 | "incorrect_address_checksum":"부정확한 주소 체크섬", 90 | "amount_cannot_be_zero":"금액이 0일 수 없습니다.", 91 | "tag_is_invalid":"태그가 옳지 않습니다.", 92 | "ignoring_invalid_tag_value":"옳지 않은 태그 값입니다. 무시하겠습니다.", 93 | "wont_overwrite_transfer_fields":"트랜스퍼 칸은 이미 기재되었습니다. 중복 기재는 불가능합니다.", 94 | "transfer_fields_prefilled_link":"이 링크을 클릭하면 트랜스퍼 칸들은 이미 기재되어있습니다.", 95 | "unknown_or_invalid_url":"알 수 없는/부정확한 URL", 96 | "error_whilst_adding_neighbors":"이웃들을 추가하는 중 에러 발생", 97 | "added_neighbor":"{{count}}명의 이웃이 추가되었습니다.", 98 | "added_neighbor_plural":"{{count}}명의 이웃들이 추가되었습니다.", 99 | "error_whilst_removing_neighbors":"이웃들을 삭제하는 중 에러 발생", 100 | "removed_neighbor":"{{count}}명의 이웃을 삭제하였습니다.", 101 | "removed_neighbor_plural":"{{count}}명의 이웃들을 삭제하였습니다.", 102 | "new_user_read_faq":"새로운 사용자이신가요? FAQ 먼저 읽어보세요!", 103 | "windows_32_bit_unsupported":"Windows 32-bit는 현재로선 지원되지 않습니다.", 104 | "iota_wallet_testnet":"IOTA 지갑 테스트넷", 105 | "iota_wallet":"IOTA 지갑", 106 | "settings_file_does_not_exist":"Settings file이 존재하지 않습니다", 107 | "not_supported":"지원되지 않음", 108 | "hide_status_bar":"상태 바 숨기기", 109 | "show_status_bar":"상태 바 보이기", 110 | "toggle_web_inspector":"토글 웹 인스펙터", 111 | "enter_full_screen":"전체 창 열기", 112 | "exit_full_screen":"전체 창 닫기", 113 | "undo":"취소", 114 | "redo":"다시 하기", 115 | "cut":"삭제", 116 | "copy":"복사", 117 | "paste":"붙여넣기", 118 | "select_all":"전체 선택", 119 | "edit":"수정", 120 | "view":"보기", 121 | "switch_language":"언어 설정", 122 | "switch":"바꾸기", 123 | "tools":"도구", 124 | "view_node_info":"노드 정보 보기", 125 | "view_neighbors":"이웃들 보기", 126 | "view_server_log":"서버 로그 보기", 127 | "open_database_folder":"데이터베이스 폴더 열기", 128 | "edit_node_configuration":"노드 배열 수정하기", 129 | "edit_neighbors":"이웃들 수정하기", 130 | "options":"옵션", 131 | "switch_to_light_node":"라이트 노드로 바꾸기", 132 | "switch_to_full_node":"풀 노드로 바꾸기", 133 | "save_account_data_locally":"계정 데이터 로컬로 저장", 134 | "remove_local_account_data":"로컬 계정 데이터 삭제", 135 | "window":"창", 136 | "minimize":"최소화", 137 | "close":"닫기", 138 | "faq":"자주 하는 질문", 139 | "official_website":"공식 웹사이트", 140 | "forum":"포럼 ", 141 | "chat":"채팅", 142 | "documentation":"설명서", 143 | "about_iota_wallet":"IOTA 지갑에 대해서", 144 | "preferences":"선호", 145 | "services":"서비스", 146 | "hide_iota_wallet":"IOTA 지갑 숨기기", 147 | "hide_others":"Others 숨기기", 148 | "show_all":"전부 펼치기", 149 | "quit":"중단하기", 150 | "bring_all_to_front":"전부 앞으로", 151 | "server_exited":"서버 종료됨", 152 | "iota_server_process_exited":"IOTA 서버 프로세스가 종료되었습니다.", 153 | "server_address_already_in_use":"서버 주소가 이미 사용중입니다. 포트 {{port}}에 작동되고 있는 앱이나 서비스 등을 먼저 종료하십시오.", 154 | "initalization_alert":"초기화 알림", 155 | "server_initialization_error_occurred":"서버 초기화 에러 발생", 156 | "testnet_node_from_mainnet_connection":"메인넷 지갑에서 테스트넷 노드로 연결되고 있습니다. 이것은 권장되지 않습니다...", 157 | "mainnet_node_from_testnet_connection":"테스트넷 지갑에서 메인넷 노드로 연결되고 있습니다. 이것은 권장되지 않습니다...", 158 | "iri":"IRI", 159 | "server_log":"서버 로그", 160 | "last_messages_from_server_log":"아래는 서버 로그에서 온 최신 메시지들입니다.", 161 | "save":"저장하기", 162 | "ok":"예", 163 | "cancel":"취소하기", 164 | "yes":"네", 165 | "no":"아니오", 166 | "cpu":"CPU", 167 | "open_at_login":"로그인에 열기", 168 | "add_neighbor_node":"이웃 노드 추가하기", 169 | "confirm_add_node_to_config":"이 노드를 당신의 서버 배열에 추가하고 싶은 게 확실합니까?", 170 | "yes_add_node":"네, 이 노드를 추가하십시오.", 171 | "no_cancel":"아니오, 취소하겠습니다.", 172 | "node_config":"노드 배열", 173 | "host":"호스트 ", 174 | "min_weight_magnitude":"최소 중량 크기", 175 | "node_port":"노드 포트 ", 176 | "depth":"깊이", 177 | "neighboring_nodes":"주변 노드들", 178 | "node_settings_format":"이와 같은 포맷으로 노드들을 추가하시오. (한 줄 당 하나)", 179 | "update_available":"업데이트 불가", 180 | "update_being_downloaded":"업데이트가 가능하고 지금 다운로드되어지고 있습니다.", 181 | "new_update_available":"새 업테이트 가능", 182 | "version_is_downloaded_ready_to_install":"버전 {{version}}이 지금 다운로드되어 지고 있고 설치될 준비가 되었습니다.", 183 | "install_now":"지금 설치하기", 184 | "install_on_quit":"프로그램 종료하고 설치하기", 185 | "update_error":"업데이트 에러", 186 | "error_during_update_check":"업데이트 확인 중 에러가 발생하였습니다.", 187 | "checking_for_updates":"업데이트 확인 중", 188 | "checking_for_updates_please_wait":"업데이트 확인 중이오니 기다려주십시오.", 189 | "no_updates":"업데이트 없음", 190 | "no_updates_available":"현재 가능한 업데이트 없음", 191 | "shutdown_in_progress":"종료하는 중", 192 | "shutting_down_iota":"IOTA 종료 중... 기다려주십시오.", 193 | "error_please_restart":"에러가 발생했습니다, 서버가 중단되었습니다. 다시 어플리케이션을 시작하십시오.", 194 | "process_already_running":"이미 프로세스 진행 중...", 195 | "iota_process_already_running_choice":"IOTA 프로세스가 이미 진행중입니다. 다른 IOTA 어플리케이션을 진행중이시라면, 다시 시작하기 전 중단하십시오. 아니면, '계속 하기'를 클릭하십시오.", 196 | "continue":"계속 하기", 197 | "server_output":"서버 아웃풋", 198 | "download_64_bit_java":"64 비트 Java를 다운로드하십시오.", 199 | "edit_settings":"설정 수정하기", 200 | "restart":"다시 시작하기", 201 | "drag_to_applications_folder":"Applications 폴더로 드래그", 202 | "drag_to_applications_folder_no_execution_from_dmg":"DMG로 어플을 여는 대신에 당신의 Applications 폴더로 드래그하십시오.", 203 | "java_not_found":"Java 찾을 수 없음...", 204 | "correct_java_version_not_found":"시스템에서 올바른 Java 버전을 찾을 수 없습니다.", 205 | "sixtyfour_bit_java":"64-bit java", 206 | "click_to_download_or_switch_to_light_node":"다운로드를 시작하기 위해서 아래 버튼을 클릭하시오. 그렇지 않으면 Java를 필요치 않는 라이트 노드로 바꾸셔도 됩니다.", 207 | "click_to_download_and_reopen_or_switch_to_light_node":"다운로드를 시작하기 위해서 아래 버튼을 클릭하시오. 설치 후 지갑을 다시 여시오. 그렇지 않으면 Java를 필요치 않는 라이트 노드로 바꾸셔도 됩니다.", 208 | "click_to_download_or_use_terminal":"다운로드를 시작하기 위해서 아래 버튼을 클릭하십시오. 혹은 터미널에 아래와 같은 명령을 입력하여 설치하십시오.:", 209 | "or_depending_on_your_system":"혹은 (시스템에 따라):", 210 | "light_node_alternative_no_java":"그렇지 않으면 Java를 필요치 않는 라이트 노드로 바꾸셔도 됩니다.", 211 | "download":"다운로드하기", 212 | "choose_wallet_type":"지갑 타입 선택하기:", 213 | "light_node_or_full_node":"라이트 노드로 작동하시겠습니까, 풀 노드로 작동하시겠습니까?", 214 | "light_node_description":"라이트 노드가 원격 노드로 연결되었습니다. 이 원격 노드는 당신의 소유이거나, 누군가의 소유입니다.", 215 | "light_node":"라이트 노드", 216 | "full_node":"풀 노드", 217 | "full_node_description":"풀 노드가 다운로드 될 것이고 Tangle과 당신의 디스크를 연동시킬 것입니다. 그리고 이것은 Java 설치가 필요합니다.", 218 | "add_in_following_format_example":"이 포맷으로 추가하십시오: http://example.com:12345", 219 | "server_port":"서버 포트", 220 | "start":"시작하기", 221 | "could_not_load_hashing_library":"해싱 라이브러리를 불러올 수 없음", 222 | "hashing_not_available":"해싱 없음", 223 | "invalid_trunk_transaction":"부정확한 trunk 거래", 224 | "invalid_branch_transaction":"부정확한 branch 거래", 225 | "invalid_minweight_magnitude":"부정확한 min weight magnitude", 226 | "interrupted":"중단됨", 227 | "wrong_bundle_order":"잘못된 번들 오더", 228 | "no_server_output":"서버 아웃풋 없음", 229 | "downloading_java":"Java 다운로드 중...", 230 | "java_being_downloaded":"Java가 설치되고있습니다, 기다려주십시오...", 231 | "no_response_15s":"15초동안 무응답", 232 | "installing_java":"Java 설치중...", 233 | "java_being_installed":"Java가 설치되고있습니다, 기다려주십시오...", 234 | "installation_failed":"설치 실패", 235 | "installation_failed_install_manually":"설치가 실패하였습니다. 수동으로 다시 설치하십시오. Setup 파일은 {{location}} 에서 찾을 수 있습니다.", 236 | "java_downloaded":"Java가 다운로드되었습니다.", 237 | "java_downloaded_please_install":"Java가 {{location}} 에 다운로드되었습니다. - 파일을 설치하시고 설치 후 다시 앱을 시작하십시오.", 238 | "incorrect_status_code":"부정확한 상태 코드.", 239 | "could_not_match_regex":"Regex를 매치할 수 없음.", 240 | "download_failed":"다운로드 실패", 241 | "download_java_manually":"**여기를 클릭하십시오** Java 수동설치를 원하신다면", 242 | "download_java_jre_manually":"**여기를 클릭하십시오** Java(JRE version) 수동설치를 원하신다면", 243 | "full_node_settings":"풀 노드 설정:", 244 | "light_node_settings":"라이트 노드 설정:", 245 | "seed_password":"씨드/비밀번호", 246 | "address_attached":"주소 첨부됨", 247 | "are_you_sure":"확실합니까?", 248 | "could_not_connect_to_remote_node":"원격노드에 연결할 수 없음.", 249 | "could_not_connect_to_node":"서버로 연결할 수 없습니다.", 250 | "change_language":"언어 변경", 251 | "english":"영어", 252 | "chinese":"중국어", 253 | "french":"프랑스어", 254 | "german":"독일어", 255 | "greek":"그리스어", 256 | "italian":"이탈리아어", 257 | "japanese":"일본어", 258 | "spanish":"스페인어", 259 | "turkish":"터키어", 260 | "dutch":"네덜란드어", 261 | "about":"더보기", 262 | "hide":"숨기기", 263 | "electron":"일렉트론", 264 | "submit":"제출하기", 265 | "success":"성공", 266 | "copied_to_clipboard":"클립보드에 복사.", 267 | "udp_receiver_port":"UDP 리시버 포트", 268 | "tcp_receiver_port":"TCP 리시버 포트", 269 | "invalid":"인식 불가능", 270 | "required":"필수 사항", 271 | "reattaching":"다시 연결하는 중", 272 | "reattach":"다시 연결하기", 273 | "cannot_close_whilst_reattaching":"다시 연결 하는 동안 닫을 수 없습니다.", 274 | "transaction_reattached_successfully":"트랜잭션이 성공적으로 연결되었습니다.", 275 | "reattach_completed":"연결 완료", 276 | "transfer_completed":"전송 완료", 277 | "send_limit":"전송 제한 (Mbit/초)", 278 | "db_location":"데이터베이스 위치", 279 | "invalid_seed":"잘못된 씨드", 280 | "amount":"금액", 281 | "select_your_host":"호스트를 선택하십시오.", 282 | "custom":"사용자 지정", 283 | "custom_host":"사용자 지정 호스트", 284 | "verify_trytes":"Trytes 확인하기", 285 | "allow_short_seed_login":"짧은 씨드 로그인 허용하기", 286 | "chinese_simplified":"중국어 (간체)", 287 | "chinese_traditional":"중국어 (번체)", 288 | "portugese":"포르투갈어", 289 | "russian":"러시아어", 290 | "swedish":"스웨덴어", 291 | "korean":"한국어", 292 | "seed":"씨드", 293 | "seed_too_short":"씨드가 너무 짧습니다.", 294 | "seed_too_long":"씨드가 너무 깁니다.", 295 | "could_not_connect":"연결할 수 없음", 296 | "no_connection":"연결 되어있지 않습니다.", 297 | "submit_bug_report":"버그 신고하기", 298 | "bug_report":"버그 신고", 299 | "issue":"이슈", 300 | "title":"타이틀", 301 | "description":"세부내용", 302 | "username":"사용자 이름", 303 | "password":"패스워드", 304 | "send_using_github_account":"GitHub 계정을 사용하여 보내기", 305 | "send_using_email":"이메일을 사용하여 보내기", 306 | "describe_issue":"상세하게 이슈를 설명해주십시오.", 307 | "invalid_address":"잘못된 주소", 308 | "seed_checksum":"씨드 체크섬", 309 | "invalid_response":"잘못된 응답", 310 | "no_connection_to_host":"호스트와의 연결이 끊겼습니다.", 311 | "request_error":"요청 오류" 312 | } -------------------------------------------------------------------------------- /locales/ja/translation.json: -------------------------------------------------------------------------------- 1 | { 2 | "login":"ログイン", 3 | "error":"エラー", 4 | "balance":"残高", 5 | "send":"送金する", 6 | "recipient_address":"受取アドレス", 7 | "optional_tag":"任意のタグ", 8 | "sending":"送信中..", 9 | "send_it_now":"今送ります。", 10 | "receive":"受取", 11 | "generate_new_address":"新しいアドレスを生成", 12 | "generating_address":"アドレスを生成中", 13 | "history":"記録", 14 | "transfers":"送信", 15 | "addresses":"アドレス", 16 | "no_transfers_found":"送信なし", 17 | "no_addresses_found":"アドレスなし", 18 | "bundle_details":"バンドルの詳細", 19 | "rebroadcasting":"再ブロードキャスト中...", 20 | "rebroadcast":"再ブロードキャスト", 21 | "node_info":"ノード情報", 22 | "neighbors":"近隣ノード({{value}})", 23 | "paste_trytes":"tryteを貼り付け", 24 | "paste_trytes_here":"ここにtryteをペースト(配列またはJSON表現で)", 25 | "verifying":"検証中...", 26 | "verifying_trytes":"tryteを確認", 27 | "processing":"処理中...", 28 | "process_trytes":"tryteを処理", 29 | "network_spammer":"ネットワークのスパム", 30 | "help_network_spamming":"スパムによるネットワークの援助", 31 | "spamming":"スパム中...", 32 | "spam_the_network":"ネットワークをスパムする", 33 | "x_transactions_generated":"xトランザクション生成済み", 34 | "not_synced":"非同期", 35 | "help":"ヘルプ", 36 | "contact":"コンタクト", 37 | "privacy_terms":"プライバシーと利用規約", 38 | "logout":"ログアウト", 39 | "faqs":"FAQ", 40 | "community":"コミュニティ", 41 | "join_us":"参加しよう", 42 | "terms_agreements":"契約条件", 43 | "iota_tos":"IOTAは、IOTA ASによって最初に開発され、メンテナンスおよびさらなる開発のためにIOTA財団に引き渡されたオープンソースソフトウェアであり、IOTA ASとIOTA Foundationは、立ち上げ後のソフトウェア(クライアントおよびGUI)について一切の責任を負いません。このグラフィカルユーザーインターフェイスを介して行われるすべての取引は、ユーザーが責任を負うものであり、IOTA ASおよびIOTA財団は、ユーザーが遭遇する可能性があるすべてのエラーや意図しない「ファットフィンガー」(株式などの金融取引で、電子取引の注文の誤入力によって、多大な損害を被ること)の類の発生については責任を負いません。", 44 | "iota_consult":"GUIを操作する方法がわからない場合はFAQを参照してください。まだ不確かな場合は、IOTAコミュニティに相談してください。", 45 | "attaching_to_tangle":"タングルにアタッチ中...", 46 | "attach_to_tangle":"タングルにアタッチ", 47 | "attach_tangle_before_using_address":"アドレス使用前にタングルへのアタッチを確認しましょう。", 48 | "fill_all_fields":"すべての空白を埋めましょう", 49 | "invalid_characters":"無効な文字", 50 | "mixed_case_characters":"大文字・小文字の混ざった文字", 51 | "new_seed_too_short":"新しいシードは短すぎます。", 52 | "new_seed_too_long":"新しいシードは長すぎます。", 53 | "not_matching":"合致しません ", 54 | "invalid_input":"無効な入力", 55 | "hash":"ハッシュ", 56 | "persistence":"永続性", 57 | "confirmed":"承認済み", 58 | "pending":"ペンディング中", 59 | "cannot_close_whilst_rebroadcasting":"再ブロードキャスト中は閉じることはできません。", 60 | "transaction_rebroadcasted_successfully":"トランザクションの再ブロードキャスト成功", 61 | "rebroadcast_completed":"再ブロードキャスト成功", 62 | "genesis":"ジェネシス", 63 | "show_bundle":"バンドル表示", 64 | "transfer":"{{count}} 送金", 65 | "transfer_plural":"{{count}} 送金", 66 | "address":"{{count}} アドレス", 67 | "address_plural":"{{count}} アドレス", 68 | "could_not_load_light_wallet_functionality":"ライトwallet機能をロードできませんでした", 69 | "could_not_load_required_backend_files":"必要なファイルをロードできませんでした", 70 | "browser_out_of_date":"あなたのブラウザは古くなっています。最新の無料で優れたブラウザをダウンロードしてください:", 71 | "google_chrome":"Google Chrome", 72 | "mozilla_firefox":"Mozilla Firefox", 73 | "opera":"Opera", 74 | "seed_not_secure":"シードに十分な長さの文字が含まれていません。これは安全ではありません。", 75 | "seed_is_required":"シードが必要です。", 76 | "connection_refused":"接続が拒否されました。", 77 | "logging_in":"ログイン中...", 78 | "connecting":"接続中...", 79 | "no_neighbors_found":"近隣ノードがありません。", 80 | "please_log_in_first":"まずログインしてください。", 81 | "invalid_trytes_or_input":"無効なtryteまたは入力", 82 | "invalid_signature":"無効な署名", 83 | "already_processed":"すでに処理されています。", 84 | "transaction_completed":"トランザクション完了", 85 | "yes_send_now":"はい、すぐ送ります。", 86 | "address_is_required":"アドレスが必要です。", 87 | "missing_address_checksum":"アドレスのチェックサムが抜けています。", 88 | "incorrect_address_length":"アドレス長が不正です。", 89 | "incorrect_address_checksum":"アドレスのチェックサムが不正です。", 90 | "amount_cannot_be_zero":"金額が0ではいけません。", 91 | "tag_is_invalid":"タグが無効です。", 92 | "ignoring_invalid_tag_value":"無効なタグ値、無視します。", 93 | "wont_overwrite_transfer_fields":"送金フィールドは既に記入済みであり、上書きされません", 94 | "transfer_fields_prefilled_link":"送信フィールドは、クリックされたリンクからあらかじめ入力されています。", 95 | "unknown_or_invalid_url":"未知または無効なURL。", 96 | "error_whilst_adding_neighbors":"近隣ノード追加中にエラー。", 97 | "added_neighbor":"近隣ノードを{{count}}つ追加済み", 98 | "added_neighbor_plural":"近隣ノードを{{count}}つ追加済み", 99 | "error_whilst_removing_neighbors":"近隣ノード削除中にエラー。", 100 | "removed_neighbor":"近隣ノードを{{count}}つ削除済み", 101 | "removed_neighbor_plural":"近隣ノードを{{count}}つ削除済み", 102 | "new_user_read_faq":"新しいユーザですか?FAQをまず読みましょう!", 103 | "windows_32_bit_unsupported":"32ビットWindowsは現状サポートされていません。", 104 | "iota_wallet_testnet":"IOTA Wallet Testnet", 105 | "iota_wallet":"IOTA Wallet", 106 | "settings_file_does_not_exist":"設定ファイルがありません。", 107 | "not_supported":"サポートされていません。", 108 | "hide_status_bar":"ステータスバーを隠す", 109 | "show_status_bar":"ステータスバーを表示する", 110 | "toggle_web_inspector":"ウエブインスペクターを閉じるまたは開く", 111 | "enter_full_screen":"フルスクリーンにする", 112 | "exit_full_screen":"Exit Full Screen", 113 | "undo":"もとに戻す", 114 | "redo":"やり直す", 115 | "cut":"切り取り", 116 | "copy":"コピー", 117 | "paste":"貼り付け", 118 | "select_all":"全選択", 119 | "edit":"編集", 120 | "view":"ビュー", 121 | "switch_language":"言語切り替え", 122 | "switch":"切り替え", 123 | "tools":"ツール", 124 | "view_node_info":"ノード情報確認", 125 | "view_neighbors":"近隣ノード確認", 126 | "view_server_log":"サーバーログ確認", 127 | "open_database_folder":"データベースフォルダを開く", 128 | "edit_node_configuration":"ノード設定編集", 129 | "edit_neighbors":"Edit Neighbors", 130 | "options":"オプション", 131 | "switch_to_light_node":"ライトノードに切り替え", 132 | "switch_to_full_node":"フルノードに切り替え", 133 | "save_account_data_locally":"アカウントデータをハードディスクに保存", 134 | "remove_local_account_data":"ハードディスクのアカウントデータを削除", 135 | "window":"ウインドウ", 136 | "minimize":"最小化", 137 | "close":"閉じる", 138 | "faq":"FAQ", 139 | "official_website":"公式ウェブサイト", 140 | "forum":"フォーラム", 141 | "chat":"チャット", 142 | "documentation":"ドキュメント", 143 | "about_iota_wallet":"IOTA Walletについて", 144 | "preferences":"設定", 145 | "services":"サービス", 146 | "hide_iota_wallet":"IOTA Walletを隠す", 147 | "hide_others":"他を隠す", 148 | "show_all":"すべて表示", 149 | "quit":"終了", 150 | "bring_all_to_front":"すべてを前に表示", 151 | "server_exited":"サーバを終了", 152 | "iota_server_process_exited":"IOTAサーバのプロセスは終了", 153 | "server_address_already_in_use":"サーバーアドレスはすでに使用されています。ポート{{port}}で動作している可能性のある他のアプリケーション/サービスを終了してください。", 154 | "initalization_alert":"初期化アラート", 155 | "server_initialization_error_occurred":"サーバ初期化エラーが発生しました。", 156 | "testnet_node_from_mainnet_connection":"mainnetwalletからtestnetノードに接続しています。これはお勧めしません...", 157 | "mainnet_node_from_testnet_connection":"testnetwalletからmainnetノードに接続しています。これはお勧めしません...", 158 | "iri":"IRI", 159 | "server_log":"サーバーログ", 160 | "last_messages_from_server_log":"サーバーログの最後のメッセージは下記通り", 161 | "save":"保存", 162 | "ok":"OK", 163 | "cancel":"キャンセル", 164 | "yes":"はい", 165 | "no":"いいえ", 166 | "cpu":"CPU", 167 | "open_at_login":"ログイン時に開く", 168 | "add_neighbor_node":"近隣ノード追加", 169 | "confirm_add_node_to_config":"このノードをサーバー設定に追加してもよろしいですか?", 170 | "yes_add_node":"はい、このノードを追加します。", 171 | "no_cancel":"いいえ、キャンセルします。", 172 | "node_config":"ノード設定", 173 | "host":"ホスト", 174 | "min_weight_magnitude":"Min Weight Magnitude(PoWの難易度)", 175 | "node_port":"ノードポート", 176 | "depth":"深さ", 177 | "neighboring_nodes":"近隣ノード", 178 | "node_settings_format":"次のフォーマットでのノード(1行1ノード)", 179 | "update_available":"更新が利用可能", 180 | "update_being_downloaded":"更新が利用可能でダウンロード中", 181 | "new_update_available":"新しい更新が利用可能", 182 | "version_is_downloaded_ready_to_install":"バージョン{{version}}がダウンロード済みでインストール可能", 183 | "install_now":"今すぐインストール", 184 | "install_on_quit":"終了時インストール", 185 | "update_error":"更新エラー", 186 | "error_during_update_check":"更新確認中にエラー発生", 187 | "checking_for_updates":"更新確認中", 188 | "checking_for_updates_please_wait":"更新確認中、少し待ちましょう", 189 | "no_updates":"更新なし", 190 | "no_updates_available":"現在利用可能な更新なし", 191 | "shutdown_in_progress":"シャットダウン中", 192 | "shutting_down_iota":"IOTAをシャットダウン中、少し待ちましょう", 193 | "error_please_restart":"エラーが発生しました。サーバーは終了しました。アプリケーションを再起動してください。", 194 | "process_already_running":"プロセスはすでに実行中...", 195 | "iota_process_already_running_choice":"IOTAプロセスはすでに実行中です。別のIOTAアプリケーションを実行している場合は、続行する前に終了してください。それ以外の場合は、[続行]をクリックします。", 196 | "continue":"継続", 197 | "server_output":"サーバ出力", 198 | "download_64_bit_java":"64ビットJavaをダウンロード", 199 | "edit_settings":"設定編集", 200 | "restart":"再起動", 201 | "drag_to_applications_folder":"アプリケーションフォルダにドラッグ", 202 | "drag_to_applications_folder_no_execution_from_dmg":"アプリケーションをDMGから開くのではなく、アプリケーションフォルダにドラッグします。", 203 | "java_not_found":"Javaが見つかりません。", 204 | "correct_java_version_not_found":"正しいJavaバージョンがシステムに見つかりません。", 205 | "sixtyfour_bit_java":"64-bit java", 206 | "click_to_download_or_switch_to_light_node":"ダウンロードを開始するには、下のボタンをクリックしてください。あるいは、Javaを必要としないライトノードに切り替えることもできます。", 207 | "click_to_download_and_reopen_or_switch_to_light_node":"ダウンロードを開始するには、下のボタンをクリックしてください。インストール後にwalletを再度開きます。あるいは、Javaを必要としないライトノードに切り替えることもできます。", 208 | "click_to_download_or_use_terminal":"下のボタンをクリックしてダウンロードを開始するか、端末に以下のコマンドを入力してインストールしてください:", 209 | "or_depending_on_your_system":"(あなたのシステムに依存します)", 210 | "light_node_alternative_no_java":"あるいは、Javaを必要としないライトノードに切り替えることもできます。", 211 | "download":"ダウンロード", 212 | "choose_wallet_type":"walletの種類を選択:", 213 | "light_node_or_full_node":"ライトノード・フルノードどちらを実行しますか。", 214 | "light_node_description":"ライトノードは、あなたまたは他の誰かが所有するリモートノードに接続します。", 215 | "light_node":"ライトノード", 216 | "full_node":"フルノード", 217 | "full_node_description":"フルノードでは、ディスクにタングルをダウンロードして同期します、またJavaをインストールする必要があります。", 218 | "add_in_following_format_example":"次のフォーマットで追加してください: http://example.com:12345", 219 | "server_port":"サーバーポート", 220 | "start":"開始", 221 | "could_not_load_hashing_library":"Could not load hashing library", 222 | "hashing_not_available":"Hashing not available", 223 | "invalid_trunk_transaction":"Invalid trunk transaction", 224 | "invalid_branch_transaction":"Invalid branch transaction", 225 | "invalid_minweight_magnitude":"Invalid minweight magnitude", 226 | "interrupted":"Interrupted", 227 | "wrong_bundle_order":"Wrong bundle order", 228 | "no_server_output":"No server output.", 229 | "downloading_java":"Downloading java...", 230 | "java_being_downloaded":"Java is being downloaded. Please wait...", 231 | "no_response_15s":"No response in 15 seconds.", 232 | "installing_java":"Installing Java...", 233 | "java_being_installed":"Java is being installed, please wait...", 234 | "installation_failed":"Installation Failed", 235 | "installation_failed_install_manually":"The installation has failed, please install manually. The setup file is located at {{location}}.", 236 | "java_downloaded":"Java is Downloaded", 237 | "java_downloaded_please_install":"Java has been downloaded to {{location}} - please install it and reopen this app after installation.", 238 | "incorrect_status_code":"Incorrect status code.", 239 | "could_not_match_regex":"Could not match regex.", 240 | "download_failed":"Download Failed", 241 | "download_java_manually":"Please **click here** to download and install java manually.", 242 | "download_java_jre_manually":"Please **click here** to download and install java manually (JRE version).", 243 | "full_node_settings":"Full Node Settings:", 244 | "light_node_settings":"Light Node Settings:", 245 | "seed_password":"Seed / Password", 246 | "address_attached":"Address Attached", 247 | "are_you_sure":"Are you sure?", 248 | "could_not_connect_to_remote_node":"Could not connect to remote node.", 249 | "could_not_connect_to_node":"Could not connect to node.", 250 | "change_language":"Change Language", 251 | "english":"English", 252 | "chinese":"Chinese", 253 | "french":"French", 254 | "german":"German", 255 | "greek":"Greek", 256 | "italian":"Italian", 257 | "japanese":"Japanese", 258 | "spanish":"Spanish", 259 | "turkish":"Turkish", 260 | "dutch":"Dutch", 261 | "about":"About", 262 | "hide":"Hide", 263 | "electron":"Electron", 264 | "submit":"Submit", 265 | "success":"Success", 266 | "copied_to_clipboard":"Copied to Clipboard.", 267 | "udp_receiver_port":"UDP Receiver Port", 268 | "tcp_receiver_port":"TCP Receiver Port", 269 | "invalid":"Invalid", 270 | "required":"Required", 271 | "reattaching":"Reattaching...", 272 | "reattach":"REATTACH", 273 | "cannot_close_whilst_reattaching":"Cannot close whilst reattaching.", 274 | "transaction_reattached_successfully":"Transaction reattached successfully", 275 | "reattach_completed":"Reattach completed", 276 | "transfer_completed":"Transfer completed", 277 | "send_limit":"Send Limit (Mbit/s)", 278 | "db_location":"Database Location", 279 | "invalid_seed":"Invalid Seed", 280 | "amount":"Amount", 281 | "select_your_host":"Select Your Host", 282 | "custom":"Custom", 283 | "custom_host":"Custom Host", 284 | "verify_trytes":"Verify Trytes", 285 | "allow_short_seed_login":"Allow Short Seed Login", 286 | "chinese_simplified":"Chinese (Simplified)", 287 | "chinese_traditional":"Chinese (Traditional)", 288 | "portugese":"Portugese", 289 | "russian":"Russian", 290 | "swedish":"Swedish", 291 | "korean":"Korean", 292 | "seed":"Seed", 293 | "seed_too_short":"Seed too Short", 294 | "seed_too_long":"Seed too Long", 295 | "could_not_connect":"Could Not Connect", 296 | "no_connection":"No Connection", 297 | "submit_bug_report":"Submit Bug Report", 298 | "bug_report":"Bug Report", 299 | "issue":"Issue", 300 | "title":"Title", 301 | "description":"Description", 302 | "username":"Username", 303 | "password":"Password", 304 | "send_using_github_account":"Send Using GitHub Account", 305 | "send_using_email":"Send Using Email", 306 | "describe_issue":"Describe the Issue in Detail", 307 | "invalid_address":"Invalid Address", 308 | "seed_checksum":"Seed Checksum", 309 | "invalid_response":"Invalid Response", 310 | "no_connection_to_host":"No Connection to Host", 311 | "request_error":"Request Error" 312 | } --------------------------------------------------------------------------------