├── .gitignore ├── README.md ├── _locales ├── en │ └── messages.json ├── ko │ └── messages.json └── zh_CN │ └── messages.json ├── background.js ├── contentscript.js ├── example ├── TestPage_new.html ├── TestPage_old.html └── nebPay.js ├── html ├── check.html ├── contract.html ├── css │ ├── base.css │ ├── bootstrap.css │ ├── bootstrap.min.css │ ├── codemirror.css │ └── ui-block.css ├── images │ ├── background.png │ ├── logo-b.png │ └── logo.png ├── index.html ├── js │ ├── 1-localSave.js │ ├── check.js │ ├── contract.js │ ├── global.js │ ├── home.v1.js │ ├── i18n.js │ ├── index.js │ ├── main.js │ ├── nebulas.js │ ├── options.js │ ├── sendNas.js │ ├── sendOffline.js │ ├── ui-block.js │ └── viewWalletInfo.js ├── lib │ ├── Blob.js │ ├── FileSaver.min.js │ ├── blockies.min.js │ ├── bootbox.min.js │ ├── bootstrap-4.0.0-dist │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ └── bootstrap.min.js.map │ ├── codemirror │ │ ├── codemirror.js │ │ └── javascript.js │ ├── jquery-3.3.1.min.js │ ├── jquery.base64.js │ ├── jquery.qrcode.min.js │ ├── js-beautify-1.7.5 │ │ └── beautify.js │ ├── nebulas.js │ └── prismjs-1.13.0 │ │ ├── prism.css │ │ └── prism.js ├── main.html.ori ├── options.html ├── sendNas.html ├── sendOffline.html ├── server.js ├── viewWalletInfo.html └── welcome.html ├── images ├── background.png ├── glyphicons-halflings-white.png ├── glyphicons-halflings.png ├── icon_128.png ├── icon_19.png ├── icon_38.png ├── logo-b.png ├── logo.png └── nebulas.png ├── inpage.js ├── manifest.json ├── popup.js └── resources ├── add-chrome-extension.png ├── download-from-fithub.png └── extension_options.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.sublime-project 3 | 4 | *.sublime-workspace 5 | 6 | .idea 7 | 8 | .DS_store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebExtensionWallet 2 | 3 | ### 1. Install 4 | This extension is now published on [Chrome web store](https://chrome.google.com/webstore/detail/nasextwallet/gehjkhmhclgnkkhpfamakecfgakkfkco). Wellcome to install and take a try! 5 | 6 | We will keep improving this extension, and any suggestions are welcome! 7 | 8 | **Note:** If you need to test local html files, you need to turn on the "Allow access to file URLs" option at extension management page: 9 | 10 | ![](resources/extension_options.png) 11 | 12 | 13 | ### 2. Brief introduction of using our ExtensionWallet 14 | ``` 15 | (1) In tab `New-Wallet`, you can create your own wallet, and download the keystore files. 16 | (2) In tab `Send-TX`, you can import your keystore file, and then your account will be stored within the extension. 17 | (3) After your account keyfile is imported, you can send NAS to other account address. 18 | (4) After a transaction is sent, you got the transaction hash shown at the bottom of extension page. 19 | (5) Click the transaction hash in tab `Send-TX` to check transaction status 20 | (6) Another way to check your transaction status is to copy your transaction hash to `check-TX` to view the result. 21 | ``` 22 | 23 | ### 3. Instructions on how to use NasExtWallet in your webapp 24 | 25 | Now NasExtWallet supports two different ways to communicate with Dapp page. 26 | 27 | 28 | #### 3.1 Using NebPay SDK 29 | 30 | Please refer to Dapp Example [SuperDictionary](https://github.com/15010159959/super-dictionary) to learn how to use this extension. 31 | 32 | When developing your Dapp page, you can use [NebPay SDK](https://github.com/nebulasio/nebPay) to communicate with ExtensionWallet. Just as the example below. 33 | 34 | To call a SmartContract through extensionWallet, you should use [`nebpay.call`](https://github.com/nebulasio/nebPay/blob/master/doc/NebPay_Introduction.md#call) or [`nebpay.simulateCall`](https://github.com/nebulasio/nebPay/blob/master/doc/NebPay_Introduction.md#simulatecall) to send a transaction as below: 35 | ```js 36 | nebPay.call(to, value, callFunction, callArgs, { 37 | qrcode: { 38 | showQRCode: true 39 | }, 40 | listener: cbCallDapp //specify a listener to handle the transaction result 41 | }); 42 | 43 | function cbCallDapp(resp){ 44 | console.log("response: " + JSON.stringify(resp)) 45 | } 46 | 47 | ``` 48 | 49 | 50 | #### 3.2 Using `postMessage` 51 | 52 | When developing your Dapp page, you can use `postMessage` API to communicate with ExtensionWallet, and use `window.addEventListener` to listen the message answer. Just as the example below. 53 | 54 | To call a smart contract function with extensionWallet, you should use `postMessage` to send a message as below: 55 | ```js 56 | window.postMessage({ 57 | "target": "contentscript", 58 | "data":{ 59 | "to": to, 60 | "value": "0", 61 | "contract":{ //"contract" is a parameter used to deploy a contract or call a smart contract function 62 | "function": func, 63 | "args": para 64 | } 65 | }, 66 | "method": "neb_sendTransaction", 67 | }, "*"); 68 | ``` 69 | 70 | And then you need to add an `eventlistener` to listen the returned message. 71 | ```js 72 | window.addEventListener('message', function(e) { 73 | console.log("message received, msg.data: " + JSON.stringify(e.data)); 74 | if(!!e.data.data.txhash){ 75 | console.log("Transaction hash:\n" + JSON.stringify(e.data.data.txhash, null, '\t')); 76 | } 77 | }) 78 | ``` 79 | 80 | ### 4 how to get account address 81 | 82 | It is useful for Dapp to get the current account address in the extension. Here is the explanation on how to achieve this. 83 | 84 | #### Method 1: 85 | ```js 86 | var userAddress; 87 | 88 | function getUserAddress() { 89 | console.log("********* get account ************") 90 | window.postMessage({ 91 | "target": "contentscript", 92 | "data":{ 93 | }, 94 | "method": "getAccount", 95 | }, "*"); 96 | } 97 | // listen message from contentscript 98 | window.addEventListener('message', function(e) { 99 | // e.detail contains the transferred data (can 100 | console.log("received by page:" + e + ", e.data:" + JSON.stringify(e.data)); 101 | if (!!e.data.data && !!e.data.data.account) { 102 | userAddrerss = e.data.data.account; 103 | } 104 | }) 105 | 106 | ``` 107 | 108 | #### Method 2: 109 | A module `NasExtWallet` is injected to your page if NasExtWallet is installed, then you can use the code below to get user account: 110 | ```js 111 | var userAddress; 112 | 113 | NasExtWallet.getUserAddress(function(addr){ 114 | userAddress = addr; 115 | console.log("user address is : " + addr) 116 | }) 117 | 118 | ``` 119 | 120 | 121 | ### example page 122 | And you can use `example/TestPage.html` to take a test. 123 | 124 | 125 | -------------------------------------------------------------------------------- /_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "NasExtWallet", 4 | "description": "The extension for Nebulas Dapp" 5 | }, 6 | "appDesc": { 7 | "message": "This extension is designed for Nebulas user", 8 | "description":"WebExtensionWallet is a chrome extension for dapp developers to send transactions to Nebulas BlockChain! It now implemented the NebPay SDK." 9 | } 10 | } -------------------------------------------------------------------------------- /_locales/ko/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "NasExtWallet", 4 | "description": "네뷸러스 지갑 확장프로그램" 5 | }, 6 | "appDesc": { 7 | "message": "네뷸러스 사용자들을 위해 개발된 확장프로그램입니다", 8 | "description":"네뷸러스 블록체인에 트랜잭션을 전송하는 DApp 개발자들을 위한 크롬 확장 프로그램입니다! NebPay SDK로 구현되었습니다." 9 | } 10 | } -------------------------------------------------------------------------------- /_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "appName": { 3 | "message": "NasExtWallet", 4 | "description": "星云链钱包插件" 5 | }, 6 | "appDesc": { 7 | "message": "用于星云链的交易发送和Dapp交互", 8 | "description":"主要用于使用及与星云链的Dapp。实现了NebPay接口,可以用来发送交易,调用合约等。" 9 | } 10 | } -------------------------------------------------------------------------------- /background.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var msgCount = 0; 5 | //var unapprovedTxCount = 0; 6 | var unapprovedTxs = []; 7 | 8 | var AccAddress ; 9 | var AccPubKey; 10 | var AccPubKeyString; 11 | 12 | var nebulas = require("nebulas"); 13 | var neb = new nebulas.Neb(); 14 | var gAccount; 15 | var network ,chainId; 16 | 17 | //var sourceName = 'NasExtWallet'; 18 | 19 | function resetNeb() { 20 | network = localSave.getItem("apiPrefix") || "https://testnet.nebulas.io"; 21 | chainId = localSave.getItem("chainId" ) || 1001; 22 | 23 | neb.setRequest(new nebulas.HttpRequest(network)); 24 | } 25 | 26 | 27 | function rpc_call(data, cb) { 28 | if (!AccAddress) { 29 | alert("please import your wallet file into extension") 30 | cb("error: please import wallet file") 31 | return 32 | } 33 | neb.api.getAccountState(AccAddress) 34 | .then(function (accStat) { 35 | //var balance = nebulas.Unit.fromBasic(accStat.balance, "nas"), 36 | //var nonce = parseInt(accStat.nonce) + 1; 37 | return neb.api.call({ 38 | from: AccAddress, 39 | to: data.to, 40 | value: data.value, 41 | nonce: parseInt(accStat.nonce) + 1, 42 | gasPrice: "20000000000", 43 | gasLimit: "400000", 44 | contract: data.contract 45 | }) 46 | }) 47 | .then(function (resp) { 48 | cb(resp) 49 | }) 50 | .catch(function (err) { 51 | console.log("rpc call error: " + JSON.stringify(err)) 52 | cb(err.message || err) 53 | }); 54 | } 55 | 56 | 57 | // massage from web page format is basically like this: 58 | // { 59 | // "src": "contentScript", 60 | // "dst": "background", 61 | // "data": { 62 | // "target": "contentscript", 63 | // "data": { 64 | // "to": "n1vHgvjw6VPPa4P2MQ6xTPdanbbVYPfGQeu", 65 | // "value": "0", 66 | // "contract": { 67 | // "function": "balanceOf", 68 | // "args": "[\"n1JmhE82GNjdZPNZr6dgUuSfzy2WRwmD9zy\"]" 69 | // } 70 | // }, 71 | // "method": "neb_call" 72 | // } 73 | // } 74 | //receive msg from ContentScript and popup.js 75 | chrome.runtime.onConnect.addListener(function(port) { 76 | console.log("Connected ....." + port.name ); 77 | 78 | port.onMessage.addListener(function(msg) { 79 | 80 | msgCount ++; 81 | console.log("msgCount:" + msgCount ); 82 | console.log("msg listened: " + JSON.stringify(msg)); 83 | 84 | if (msg.src === 'contentScript'){ //message from webpage(DApp page) 85 | if (!msg.data) 86 | return; 87 | if (msg.data.method === "neb_sendTransaction"){ 88 | cacheTx(msg.data); 89 | } 90 | else if (msg.data.method === "neb_call"){ 91 | rpc_call(msg.data.data,function (resp) { 92 | port.postMessage({ 93 | //source: sourceName, 94 | neb_call: resp 95 | }) 96 | }) 97 | } 98 | else if (msg.data.method === "getAccount") 99 | port.postMessage({ 100 | //source: sourceName, 101 | account: AccAddress, 102 | accountPubKey: AccPubKey, 103 | accountPubKeyString: AccPubKeyString 104 | }) 105 | } 106 | //********************************** 107 | else if (msg.src === 'popup'){ //message from extension popup page 108 | if (!msg.data) 109 | return; 110 | if (!!msg.data.AccAddress){ 111 | AccAddress = msg.data.AccAddress; 112 | AccPubKey = msg.data.AccPubKey; 113 | AccPubKeyString = msg.data.AccPubKeyString; 114 | } 115 | else if(!!msg.data.changeNetwork){ 116 | if(msg.data.changeNetwork !== network){ 117 | resetNeb(); 118 | } 119 | } 120 | else if (!!msg.data.newWallet){ //user changed wallet, update the wallet right now 121 | restoreAccount(); 122 | } 123 | else if (!!msg.data.getNextTx){ 124 | port.postMessage({ 125 | //source: sourceName, 126 | unapprovedTxs : unapprovedTxs 127 | }) 128 | } 129 | else if (!!msg.data.rejectAll){ 130 | unapprovedTxs.splice(0,unapprovedTxs.length); 131 | updateBadgeText(); 132 | } 133 | else if (!!msg.data.generate || !!msg.data.reject){ 134 | unapprovedTxs.pop(); 135 | updateBadgeText(); 136 | } 137 | else if (!!msg.data.txhash){ 138 | console.log("txhash: " + JSON.stringify(msg.data.txhash)); 139 | //if has serial number, then this message is send from nebpay, 140 | if(msg.serialNumber){ 141 | forwardMsgToPage(msg.serialNumber,msg.data.txhash); 142 | return 143 | } 144 | chrome.tabs.query({}, function(tabs){ //send tx receipt back to web page 145 | for (var i=0; i contentscript -> background) 253 | chrome.runtime.onMessage.addListener( 254 | function(request, sender, sendResponse) { 255 | console.log(sender.tab ? 256 | "from a content script:" + JSON.stringify(sender.tab) : 257 | "from the extension"); 258 | 259 | console.log("request: " + JSON.stringify(request)); 260 | 261 | if(request.logo === "nebulas") { 262 | messagesFromPage[request.params.serialNumber] = {sender: sender.tab, params: request.params}; 263 | 264 | var type = request.params.pay.payload.type; 265 | if (type === "simulateCall"){ // 266 | var data = { 267 | "to":request.params.pay.to, 268 | "value":request.params.pay.value, 269 | "contract":{ 270 | "function":request.params.pay.payload.function, 271 | "args":request.params.pay.payload.args 272 | } 273 | } 274 | rpc_call(data,function (resp) { 275 | forwardMsgToPage(request.params.serialNumber,resp) 276 | // sendResponse({ 277 | // "src": "background", 278 | // "logo": "nebulas", 279 | // "serialNumber": request.params.serialNumber, 280 | // "resp": resp 281 | // }) 282 | }) 283 | }else if (type === "binary" || 284 | type === "deploy" || 285 | type === "call" ){ 286 | var txData = { 287 | "to":request.params.pay.to, 288 | "value":request.params.pay.value, 289 | "gasPrice":request.params.pay.gasPrice, 290 | "gasLimit":request.params.pay.gasLimit, 291 | "serialNumber":request.params.serialNumber, 292 | "callback":request.params.callback 293 | }; 294 | if(type === "deploy") 295 | txData.contract ={ 296 | "source":request.params.pay.payload.source, 297 | "sourceType":request.params.pay.payload.sourceType, 298 | "args":request.params.pay.payload.args 299 | }; 300 | if(type === "call") 301 | txData.contract = { 302 | "function":request.params.pay.payload.function, 303 | "args":request.params.pay.payload.args 304 | }; 305 | cacheTx({data:txData}); 306 | }else { 307 | sendResponse({ 308 | "serialNumber": request.params.serialNumber, "resp": "undefined interface" 309 | }) 310 | } 311 | } 312 | 313 | }); 314 | 315 | //details.reason === 'install' || details.reason === 'update' 316 | chrome.runtime.onInstalled.addListener(function (details) { 317 | if (details.reason === 'install' || details.reason === 'update') { 318 | chrome.tabs.create({url: 'html/welcome.html'}) 319 | } 320 | }) 321 | -------------------------------------------------------------------------------- /contentscript.js: -------------------------------------------------------------------------------- 1 | 2 | function setupInjection (file) { 3 | var s = document.createElement('script'); 4 | s.src = chrome.extension.getURL(file); 5 | var container = document.head || document.documentElement 6 | container.insertBefore(s, container.children[0]) 7 | s.onload = function() {s.remove();}; 8 | } 9 | 10 | var file = 'inpage.js' 11 | setupInjection (file); 12 | 13 | var port = chrome.runtime.connect({name: "contentscript"}); 14 | port.postMessage({src: "contentScript",dst:"background"}); 15 | 16 | port.onMessage.addListener(function(msg) { 17 | //console.log("port.onMessage: " +JSON.stringify(msg)); 18 | 19 | window.postMessage({ //forward msg from background to webpage 20 | "src": "content", 21 | "dst": "inpage", 22 | "data":msg 23 | }, "*"); 24 | 25 | }); 26 | 27 | //just for debug, listen to port disconnect event 28 | port.onDisconnect.addListener(function(message) { 29 | console.log("Port disconnected: " + JSON.stringify(message)) 30 | }); 31 | 32 | 33 | //message from background 34 | chrome.runtime.onMessage.addListener( 35 | function(request, sender, sendResponse) { 36 | // console.log(sender.tab ? 37 | // "from a content script:" + sender.tab.url : 38 | // "from the extension"); 39 | 40 | if(request.logo === "nebulas"){ 41 | request.src = "content" 42 | window.postMessage(request, "*"); //forward msg from background to webpage 43 | return 44 | } 45 | 46 | window.postMessage({ //forward msg from background to webpage 47 | "src": "content", 48 | "data": request 49 | }, "*"); 50 | 51 | }); 52 | 53 | // Event listener, msg from web-page 54 | window.addEventListener('message', function(e) { 55 | //if (e.source != window) 56 | // return; 57 | 58 | //first version, 59 | if(e.data.target === "contentscript") { 60 | port.postMessage({ //forward msg from webpage to background, [just for compatible] 61 | src: "contentScript", 62 | dst: "background", 63 | data: e.data 64 | }) 65 | } 66 | //add nebpay support 67 | if(e.data.logo === "nebulas" && e.data.src === "nebPay") { //msg from nebPay 68 | e.data.src = "content" 69 | chrome.runtime.sendMessage(e.data, function (response) { 70 | //console.log("response: " + JSON.stringify(response)); 71 | }); 72 | } 73 | 74 | }); 75 | 76 | -------------------------------------------------------------------------------- /example/TestPage_new.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | send transaction 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | 96 | 97 |

Test for ExtensionWallet

98 |

using NebPay API to send transaction and call a smart contract

99 | 100 |
101 | 102 |

1 Send transaction

103 |

Input the receive account and amount of this transaction

104 |
105 | 106 | 107 |
108 |
109 | 110 | 111 |
112 |
113 | 114 |
115 |

116 | 117 |

2 Call a smart contract

118 |

Input your smart contract address and parameters

119 |
120 | 121 | 122 |
123 |
124 | 125 | 126 |
127 |
128 | 129 | 130 |
131 |
132 | 133 | 134 |
135 |
136 | 137 |
138 |

The above button using "sendTransaction" rpc

139 |

140 |
141 | 142 |
143 |

The above button using "call" rpc

144 |
145 |

146 | 147 | 148 | 149 | -------------------------------------------------------------------------------- /example/TestPage_old.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | send transaction 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 |

Test for ExtensionWallet

18 |

19 |
20 |

1 Send transaction

21 |

1.1 Click this button to see which account is using in ExtensionWallet

22 |
23 | 24 |
25 |

26 | 27 |

1.2 Input the receive account and amount of this transaction

28 |
29 | 30 | 31 |
32 |
33 | 34 | 35 |
36 |
37 | 38 |
39 | 40 |

2 Call a smart contract

41 |

Input your smart contract address and parameters

42 |
43 | 44 | 45 |
46 |
47 | 48 | 49 |
50 |
51 | 52 | 53 |
54 |
55 | 56 |
57 |

The above button using "sendTransaction" rpc

58 |
59 | 60 |
61 |

The above button using "call" rpc

62 |
63 |

64 | 65 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /html/check.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 65 | NEBULAS 66 | 67 | 68 | 69 |
70 |
71 |
72 | 73 |
74 |
75 |
76 |

Check TX Status

77 |

78 |
79 |
80 | 81 | 82 | 83 |
84 | Please enter a valid TX hash 85 |
86 |
87 | 88 |
89 |

Transaction Result

90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 128 | 129 | 130 | 131 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 |
TxReceipt Status
Amount 116 |
117 |
Nonce
Gas Price 126 |
127 |
Gas Limit 132 |
133 |
Gas Used 138 |
139 |
149 |
150 | 151 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 |
177 | 178 | 179 | -------------------------------------------------------------------------------- /html/contract.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | NEBULAS 15 | 120 | 121 | 122 | 123 |
124 |
125 |
126 | 127 |
128 |
    129 |
  • 130 | 131 |
  • 132 |
  • 133 | 134 |
  • 135 |
  • 136 | 137 |
  • 138 |
139 |
140 | 141 |
142 |
143 | 144 |
145 | 146 | Please enter a valid TX hash 147 | 148 |
149 |
150 | 151 |
152 |
153 | 154 | 155 | 156 | 157 | 158 | 159 |
160 |
161 | 162 |
163 | 164 | 165 |
166 |
167 | 168 | 169 |
170 | 171 |
172 | 173 | 174 |
175 | 176 | 177 | 178 | 179 |
180 | 181 |
182 |
183 | 184 |
185 |
186 |
187 | 188 |
189 |
190 |
191 | 192 |
193 |
194 | 195 | 196 |
197 |
198 | 199 | 200 |
201 |
202 | 203 |
204 |
205 | 206 |
207 |
208 |
209 | 210 | ( 1 NAS = 1EWei = 10 211 | 18 Wei ) 212 |
213 |
214 |
215 | 216 |
217 | 218 |
219 |
220 | 221 |
222 |
223 | 224 |
225 |
226 | 227 | 242 |
243 | 244 |
245 |
246 | 247 |
248 | 249 |
250 |
251 | 252 | 253 |
254 |
255 | 256 | 257 |
258 |
259 | 260 |
261 | 262 |
263 |
264 | 265 |
266 |
267 |
268 | 269 |
270 |
271 |
272 | 273 |
274 |
275 | 276 | 277 |
278 |
279 | 280 | 281 |
282 |
283 | 284 |
285 |
286 | 287 | 288 |
289 |
290 | 291 | ( 1 NAS = 1EWei = 10 292 | 18 Wei ) 293 | 294 |
295 |
296 | 297 |
298 | 299 |
300 |
301 | 302 |
303 |
304 | 305 |
306 |
307 | 308 | 321 |
322 |
323 |
324 | 325 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 |
354 | 355 | 356 | -------------------------------------------------------------------------------- /html/css/base.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | color: #333; 4 | line-height: 1.8; 5 | letter-spacing: 0.08rem; 6 | font-family: open sans, helvetica neue, helvetica, arial, sans-serif 7 | } 8 | 9 | a { 10 | color: #000 11 | } 12 | 13 | a:focus, 14 | a:visited { 15 | color: #333; 16 | text-decoration: none 17 | } 18 | 19 | a:active, 20 | a:hover { 21 | cursor: pointer; 22 | color: #333; 23 | text-decoration: none 24 | } 25 | 26 | ::selection { 27 | background-color: #333; 28 | color: #fff 29 | } 30 | 31 | ::-moz-selection { 32 | background-color: #333; 33 | color: #fff 34 | } 35 | 36 | ::-webkit-selection { 37 | background-color: #333; 38 | color: #fff 39 | } 40 | 41 | .btn { 42 | background-color: black; 43 | border-radius: 0; 44 | color: white; 45 | font-weight: 500; 46 | letter-spacing: 2px; 47 | margin: 1rem 0 .5rem 0; 48 | padding: 0.75rem 2.1875rem; 49 | } 50 | 51 | .btn.disabled:hover, 52 | .btn.disabled:active { 53 | cursor: default 54 | } 55 | 56 | .btn:disabled { 57 | cursor: default 58 | } 59 | 60 | .btn+.btn { 61 | margin-left: 1rem 62 | } 63 | 64 | @media (max-width: 767px) { 65 | .btn { 66 | white-space: normal 67 | } 68 | .btn+.btn { 69 | margin-left: 0 70 | } 71 | } 72 | 73 | a.btn-link { 74 | font-weight: 200; 75 | padding-bottom: 0.4rem 76 | } 77 | 78 | a.btn-link:focus, 79 | a.btn-link.focus, 80 | a.btn-link:visited, 81 | a.btn-link.visited, 82 | a.btn-link:active, 83 | a.btn-link.active { 84 | text-decoration: none 85 | } 86 | 87 | a.btn-link:hover { 88 | color: #000; 89 | border-bottom-color: #000; 90 | border-bottom: 1px solid; 91 | text-decoration: none; 92 | -webkit-transition: border .3s ease-in-out, color .3s ease-in-out; 93 | -moz-transition: border .3s ease-in-out, color .3s ease-in-out; 94 | -o-transition: border .3s ease-in-out, color .3s ease-in-out; 95 | transition: border 0.3s ease-in-out, color 0.3s ease-in-out 96 | } 97 | 98 | .form-control { 99 | background-color: #f5f5f5; 100 | border-radius: 3px; 101 | box-shadow: none; 102 | color: #565656; 103 | font-size: 0.875rem; 104 | line-height: 1.43; 105 | min-height: 3em; 106 | padding: 0.2em 1.07em 0.2em; 107 | border: 1px solid #e8e8e8 108 | } 109 | 110 | .form-control:focus { 111 | border: 1px solid #e8e8e8 112 | } 113 | 114 | .form-active .form-control:invalid { 115 | border-color: #f28281 116 | } 117 | 118 | .modal-backdrop.in { 119 | opacity: .8; 120 | } 121 | 122 | /* 123 | ============================================================ 124 | added since moved to https://github.com/nebulasio/web-wallet.git 125 | ============================================================ 126 | */ 127 | 128 | input.invalid, 129 | textarea.invalid { 130 | border-color: red; 131 | } 132 | 133 | input.validation-guard { 134 | border-color: #e8e8e8; 135 | } 136 | 137 | label > i { 138 | color: gray; 139 | font-size: small; 140 | } 141 | 142 | .mt14 { 143 | margin-top: 14px; 144 | } 145 | 146 | ::-webkit-scrollbar { 147 | display: none; 148 | } 149 | 150 | [data-i18n] { 151 | white-space: pre-line; 152 | } 153 | 154 | @media (max-width: 991px) { 155 | label > i { 156 | display: none; 157 | } 158 | } 159 | 160 | /* 161 | overrides bootstrap 162 | ============================================================ 163 | */ 164 | 165 | .btn-primary { 166 | border-color: black; 167 | } 168 | 169 | .dropdown-item.active, 170 | .dropdown-item:active { 171 | background-color: black; 172 | } 173 | 174 | /* 175 | overrides bootbox 176 | https://github.com/makeusabrew/bootbox/issues/566 177 | ============================================================ 178 | */ 179 | 180 | .bootbox .modal-header h4 { order: 0; } 181 | .bootbox .modal-header button { order: 1; } 182 | 183 | /* 184 | overrides base.css 185 | ============================================================ 186 | */ 187 | 188 | .bootbox .btn { 189 | line-height: 1; 190 | margin-bottom: 0; 191 | margin-top: 0; 192 | } 193 | -------------------------------------------------------------------------------- /html/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 300px; 7 | color: black; 8 | direction: ltr; 9 | } 10 | 11 | /* PADDING */ 12 | 13 | .CodeMirror-lines { 14 | padding: 4px 0; /* Vertical padding around content */ 15 | } 16 | .CodeMirror pre { 17 | padding: 0 4px; /* Horizontal padding of content */ 18 | } 19 | 20 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 21 | background-color: white; /* The little square between H and V scrollbars */ 22 | } 23 | 24 | /* GUTTER */ 25 | 26 | .CodeMirror-gutters { 27 | border-right: 1px solid #ddd; 28 | background-color: #f7f7f7; 29 | white-space: nowrap; 30 | } 31 | .CodeMirror-linenumbers { } 32 | 33 | .CodeMirror-linenumber { 34 | padding: 0 3px 0 5px; 35 | min-width: 20px; 36 | text-align: right; 37 | color: #999; 38 | white-space: nowrap; 39 | } 40 | 41 | .CodeMirror-guttermarker { color: black; } 42 | .CodeMirror-guttermarker-subtle { color: #999; } 43 | 44 | /* CURSOR */ 45 | 46 | .CodeMirror-cursor { 47 | border-left: 1px solid black; 48 | border-right: none; 49 | width: 0; 50 | } 51 | /* Shown when moving in bi-directional text */ 52 | .CodeMirror div.CodeMirror-secondarycursor { 53 | border-left: 1px solid silver; 54 | } 55 | .cm-fat-cursor .CodeMirror-cursor { 56 | width: auto; 57 | border: 0 !important; 58 | background: #7e7; 59 | } 60 | .cm-fat-cursor div.CodeMirror-cursors { 61 | z-index: 1; 62 | } 63 | .cm-fat-cursor-mark { 64 | background-color: rgba(20, 255, 20, 0.5); 65 | -webkit-animation: blink 1.06s steps(1) infinite; 66 | -moz-animation: blink 1.06s steps(1) infinite; 67 | animation: blink 1.06s steps(1) infinite; 68 | } 69 | .cm-animate-fat-cursor { 70 | width: auto; 71 | border: 0; 72 | -webkit-animation: blink 1.06s steps(1) infinite; 73 | -moz-animation: blink 1.06s steps(1) infinite; 74 | animation: blink 1.06s steps(1) infinite; 75 | background-color: #7e7; 76 | } 77 | @-moz-keyframes blink { 78 | 0% {} 79 | 50% { background-color: transparent; } 80 | 100% {} 81 | } 82 | @-webkit-keyframes blink { 83 | 0% {} 84 | 50% { background-color: transparent; } 85 | 100% {} 86 | } 87 | @keyframes blink { 88 | 0% {} 89 | 50% { background-color: transparent; } 90 | 100% {} 91 | } 92 | 93 | /* Can style cursor different in overwrite (non-insert) mode */ 94 | .CodeMirror-overwrite .CodeMirror-cursor {} 95 | 96 | .cm-tab { display: inline-block; text-decoration: inherit; } 97 | 98 | .CodeMirror-rulers { 99 | position: absolute; 100 | left: 0; right: 0; top: -50px; bottom: -20px; 101 | overflow: hidden; 102 | } 103 | .CodeMirror-ruler { 104 | border-left: 1px solid #ccc; 105 | top: 0; bottom: 0; 106 | position: absolute; 107 | } 108 | 109 | /* DEFAULT THEME */ 110 | 111 | .cm-s-default .cm-header {color: blue;} 112 | .cm-s-default .cm-quote {color: #090;} 113 | .cm-negative {color: #d44;} 114 | .cm-positive {color: #292;} 115 | .cm-header, .cm-strong {font-weight: bold;} 116 | .cm-em {font-style: italic;} 117 | .cm-link {text-decoration: underline;} 118 | .cm-strikethrough {text-decoration: line-through;} 119 | 120 | .cm-s-default .cm-keyword {color: #708;} 121 | .cm-s-default .cm-atom {color: #219;} 122 | .cm-s-default .cm-number {color: #164;} 123 | .cm-s-default .cm-def {color: #00f;} 124 | .cm-s-default .cm-variable, 125 | .cm-s-default .cm-punctuation, 126 | .cm-s-default .cm-property, 127 | .cm-s-default .cm-operator {} 128 | .cm-s-default .cm-variable-2 {color: #05a;} 129 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} 130 | .cm-s-default .cm-comment {color: #a50;} 131 | .cm-s-default .cm-string {color: #a11;} 132 | .cm-s-default .cm-string-2 {color: #f50;} 133 | .cm-s-default .cm-meta {color: #555;} 134 | .cm-s-default .cm-qualifier {color: #555;} 135 | .cm-s-default .cm-builtin {color: #30a;} 136 | .cm-s-default .cm-bracket {color: #997;} 137 | .cm-s-default .cm-tag {color: #170;} 138 | .cm-s-default .cm-attribute {color: #00c;} 139 | .cm-s-default .cm-hr {color: #999;} 140 | .cm-s-default .cm-link {color: #00c;} 141 | 142 | .cm-s-default .cm-error {color: #f00;} 143 | .cm-invalidchar {color: #f00;} 144 | 145 | .CodeMirror-composing { border-bottom: 2px solid; } 146 | 147 | /* Default styles for common addons */ 148 | 149 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} 150 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} 151 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 152 | .CodeMirror-activeline-background {background: #e8f2ff;} 153 | 154 | /* STOP */ 155 | 156 | /* The rest of this file contains styles related to the mechanics of 157 | the editor. You probably shouldn't touch them. */ 158 | 159 | .CodeMirror { 160 | position: relative; 161 | overflow: hidden; 162 | background: white; 163 | } 164 | 165 | .CodeMirror-scroll { 166 | overflow: scroll !important; /* Things will break if this is overridden */ 167 | /* 30px is the magic margin used to hide the element's real scrollbars */ 168 | /* See overflow: hidden in .CodeMirror */ 169 | margin-bottom: -30px; margin-right: -30px; 170 | padding-bottom: 30px; 171 | height: 100%; 172 | outline: none; /* Prevent dragging from highlighting the element */ 173 | position: relative; 174 | } 175 | .CodeMirror-sizer { 176 | position: relative; 177 | border-right: 30px solid transparent; 178 | } 179 | 180 | /* The fake, visible scrollbars. Used to force redraw during scrolling 181 | before actual scrolling happens, thus preventing shaking and 182 | flickering artifacts. */ 183 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 184 | position: absolute; 185 | z-index: 6; 186 | display: none; 187 | } 188 | .CodeMirror-vscrollbar { 189 | right: 0; top: 0; 190 | overflow-x: hidden; 191 | overflow-y: scroll; 192 | } 193 | .CodeMirror-hscrollbar { 194 | bottom: 0; left: 0; 195 | overflow-y: hidden; 196 | overflow-x: scroll; 197 | } 198 | .CodeMirror-scrollbar-filler { 199 | right: 0; bottom: 0; 200 | } 201 | .CodeMirror-gutter-filler { 202 | left: 0; bottom: 0; 203 | } 204 | 205 | .CodeMirror-gutters { 206 | position: absolute; left: 0; top: 0; 207 | min-height: 100%; 208 | z-index: 3; 209 | } 210 | .CodeMirror-gutter { 211 | white-space: normal; 212 | height: 100%; 213 | display: inline-block; 214 | vertical-align: top; 215 | margin-bottom: -30px; 216 | } 217 | .CodeMirror-gutter-wrapper { 218 | position: absolute; 219 | z-index: 4; 220 | background: none !important; 221 | border: none !important; 222 | } 223 | .CodeMirror-gutter-background { 224 | position: absolute; 225 | top: 0; bottom: 0; 226 | z-index: 4; 227 | } 228 | .CodeMirror-gutter-elt { 229 | position: absolute; 230 | cursor: default; 231 | z-index: 4; 232 | } 233 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent } 234 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } 235 | 236 | .CodeMirror-lines { 237 | cursor: text; 238 | min-height: 1px; /* prevents collapsing before first draw */ 239 | } 240 | .CodeMirror pre { 241 | /* Reset some styles that the rest of the page might have set */ 242 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 243 | border-width: 0; 244 | background: transparent; 245 | font-family: inherit; 246 | font-size: inherit; 247 | margin: 0; 248 | white-space: pre; 249 | word-wrap: normal; 250 | line-height: inherit; 251 | color: inherit; 252 | z-index: 2; 253 | position: relative; 254 | overflow: visible; 255 | -webkit-tap-highlight-color: transparent; 256 | -webkit-font-variant-ligatures: contextual; 257 | font-variant-ligatures: contextual; 258 | } 259 | .CodeMirror-wrap pre { 260 | word-wrap: break-word; 261 | white-space: pre-wrap; 262 | word-break: normal; 263 | } 264 | 265 | .CodeMirror-linebackground { 266 | position: absolute; 267 | left: 0; right: 0; top: 0; bottom: 0; 268 | z-index: 0; 269 | } 270 | 271 | .CodeMirror-linewidget { 272 | position: relative; 273 | z-index: 2; 274 | padding: 0.1px; /* Force widget margins to stay inside of the container */ 275 | } 276 | 277 | .CodeMirror-widget {} 278 | 279 | .CodeMirror-rtl pre { direction: rtl; } 280 | 281 | .CodeMirror-code { 282 | outline: none; 283 | } 284 | 285 | /* Force content-box sizing for the elements where we expect it */ 286 | .CodeMirror-scroll, 287 | .CodeMirror-sizer, 288 | .CodeMirror-gutter, 289 | .CodeMirror-gutters, 290 | .CodeMirror-linenumber { 291 | -moz-box-sizing: content-box; 292 | box-sizing: content-box; 293 | } 294 | 295 | .CodeMirror-measure { 296 | position: absolute; 297 | width: 100%; 298 | height: 0; 299 | overflow: hidden; 300 | visibility: hidden; 301 | } 302 | 303 | .CodeMirror-cursor { 304 | position: absolute; 305 | pointer-events: none; 306 | } 307 | .CodeMirror-measure pre { position: static; } 308 | 309 | div.CodeMirror-cursors { 310 | visibility: hidden; 311 | position: relative; 312 | z-index: 3; 313 | } 314 | div.CodeMirror-dragcursors { 315 | visibility: visible; 316 | } 317 | 318 | .CodeMirror-focused div.CodeMirror-cursors { 319 | visibility: visible; 320 | } 321 | 322 | .CodeMirror-selected { background: #d9d9d9; } 323 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 324 | .CodeMirror-crosshair { cursor: crosshair; } 325 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } 326 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } 327 | 328 | .cm-searching { 329 | background-color: #ffa; 330 | background-color: rgba(255, 255, 0, .4); 331 | } 332 | 333 | /* Used to force a border model for a node */ 334 | .cm-force-border { padding-right: .1px; } 335 | 336 | @media print { 337 | /* Hide the cursor when printing */ 338 | .CodeMirror div.CodeMirror-cursors { 339 | visibility: hidden; 340 | } 341 | } 342 | 343 | /* See issue #2901 */ 344 | .cm-tab-wrap-hack:after { content: ''; } 345 | 346 | /* Help users use markselection to safely style text background */ 347 | span.CodeMirror-selectedtext { background: none; } 348 | -------------------------------------------------------------------------------- /html/css/ui-block.css: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | .footer 4 | ============================================================ 5 | */ 6 | 7 | body { 8 | display: flex; 9 | flex-direction: column; 10 | min-height: 100vh; 11 | min-width: 400px; 12 | } 13 | 14 | .footer { 15 | font-size: .8rem; 16 | font-weight: 200; 17 | padding-bottom: 20px; 18 | padding-top: 20px; 19 | margin-top: auto; 20 | display: flex; 21 | flex-direction: column; 22 | align-items: center; 23 | } 24 | 25 | .footer .copyright { 26 | color: #b2b2b2; 27 | } 28 | 29 | .footer nav { 30 | margin: 5px 0; 31 | } 32 | 33 | .footer a { 34 | border-bottom: 1px solid transparent; 35 | margin: 0 7px; 36 | padding-bottom: 3px; 37 | text-decoration: none; 38 | } 39 | 40 | .footer a:hover { 41 | text-decoration: none; 42 | } 43 | 44 | .footer .logo { 45 | display: block; 46 | width: 150px; 47 | height: auto; 48 | margin-bottom: 6px; 49 | } 50 | 51 | /* 52 | .header 53 | ============================================================ 54 | */ 55 | 56 | .header > div { 57 | display: flex; 58 | justify-content: space-between; 59 | } 60 | 61 | .header > div > a { 62 | overflow: hidden; 63 | text-align: center; 64 | white-space: nowrap; 65 | } 66 | 67 | .header .checked { 68 | border-bottom: 2px solid #000; 69 | } 70 | 71 | /* 72 | .icon-address 73 | ============================================================ 74 | */ 75 | 76 | .icon-address { 77 | position: relative; 78 | } 79 | 80 | .icon-address canvas { 81 | font-size: .875rem; 82 | height: 32px; 83 | position: absolute; 84 | right: .35em; 85 | top: .35em; 86 | width: 32px; 87 | } 88 | 89 | .icon-address input { 90 | padding-right: 40px; 91 | } 92 | 93 | /* 94 | .logo-main 95 | ============================================================ 96 | */ 97 | 98 | .logo-main .btn { 99 | font-size: smaller; 100 | font-weight: lighter; 101 | } 102 | 103 | .logo-main .col:first-child { 104 | background: url(../images/logo-b.png) left center no-repeat content-box; 105 | background-size: 134px 30px; 106 | /*height: 70px;*/ 107 | height: 40px; 108 | } 109 | 110 | .logo-main .col:last-child { 111 | align-items: center; 112 | display: flex; 113 | justify-content: flex-end; 114 | } 115 | 116 | /* overrides - base.css */ 117 | .logo-main .col:last-child .btn { 118 | background-color: white; 119 | color: #aaa; 120 | margin: 0 10px 0 0; 121 | padding: 0; 122 | } 123 | 124 | /* 125 | .number-comma 126 | ============================================================ 127 | */ 128 | 129 | .number-comma { 130 | position: relative; 131 | } 132 | 133 | .number-comma > div { 134 | color: #aaa; 135 | font-size: .875rem; 136 | line-height: 3em; 137 | pointer-events: none; 138 | position: absolute; 139 | right: 6px; 140 | top: 0; 141 | } 142 | 143 | .number-comma > span { 144 | line-height: 2.8em; 145 | position: absolute; 146 | right: 6px; 147 | top: 0; 148 | } 149 | 150 | .number-comma .currency { 151 | height: 2.5em; 152 | line-height: 2em; 153 | top: 0; 154 | } 155 | 156 | /* 157 | .select-wallet-file 158 | ============================================================ 159 | */ 160 | 161 | .select-wallet-file label.file { 162 | background-color: #f5f5f5; 163 | border-radius: 3px; 164 | cursor: pointer; 165 | display: block; 166 | font-size: 19px; 167 | font-weight: bold; 168 | height: auto; /* override bootstrap */ 169 | line-height: 50px; 170 | overflow: hidden; 171 | text-align: center; 172 | text-overflow: ellipsis; 173 | } 174 | 175 | .select-wallet-file .empty { 176 | border: 1px solid red; 177 | } 178 | 179 | .select-wallet-file input[type=file] { 180 | display: none; 181 | } 182 | 183 | .select-wallet-file label.pass { 184 | display: block; 185 | } 186 | 187 | .select-wallet-file input[type=password] { 188 | background-color: #f5f5f5; 189 | border: 1px solid #e8e8e8; 190 | border-radius: 3px; 191 | display: block; 192 | height: 3em; 193 | letter-spacing: .3em; 194 | margin-top: 10px; 195 | padding: 0 10px; 196 | width: 100%; 197 | } 198 | 199 | .select-wallet-file label.hide { 200 | display: none; 201 | } 202 | 203 | .select-wallet-file .comment { 204 | font-size: .8rem; 205 | } 206 | .risk-tips{ 207 | background: #ff4d4f; 208 | font-size: 10px; 209 | color: #fff; 210 | padding: 3px 5px; 211 | margin-left: 10px; 212 | display: none; 213 | } 214 | .risk-text{ 215 | background-color: #fff2f0; 216 | border: 1px solid #ffccc7; 217 | font-size: 10px; 218 | padding: 3px 5px; 219 | text-align: center; 220 | margin: -0.5rem 0; 221 | display: none; 222 | } 223 | -------------------------------------------------------------------------------- /html/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/html/images/background.png -------------------------------------------------------------------------------- /html/images/logo-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/html/images/logo-b.png -------------------------------------------------------------------------------- /html/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/html/images/logo.png -------------------------------------------------------------------------------- /html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | NEBULAS 12 | 37 | 38 | 39 |
40 |
41 |
42 | 43 |
44 |
45 |
46 | 47 | 48 |
49 | 50 |
51 |
52 |

53 | Save your 54 | 55 | File. 56 |

57 | 58 |
59 |

60 | This password encrypts your private key. 61 |
This does not act as a seed to generate your keys. 62 |
You will need this password + your private key to unlock your wallet. 63 |

64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
80 | 81 | -------------------------------------------------------------------------------- /html/js/1-localSave.js: -------------------------------------------------------------------------------- 1 | // 2 | // ==================== 3 | // cause: macos safari 4 | // ==================== 5 | // 6 | // macos safari + file: + localStorage = error 7 | 8 | var localSave; 9 | 10 | try { 11 | localStorage.setItem("mod", "mod"); 12 | localStorage.removeItem("mod"); 13 | localSave = localStorage; 14 | } catch (e) { 15 | // https://gist.github.com/juliocesar/926500/85cbf5924c071f23772d73dd51ebd9d5d79ec225 16 | // digital-flowers commented on 8 May 2017 17 | // points to 18 | // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage 19 | 20 | document.cookie = "thetest=b; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/"; 21 | 22 | if (document.cookie) { 23 | document.cookie = "thetest=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"; 24 | 25 | localSave = { 26 | getItem: function (sKey) { 27 | if (!sKey || !this.hasOwnProperty(sKey)) { return null; } 28 | return unescape(document.cookie.replace(new RegExp("(?:^|.*;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*"), "$1")); 29 | }, 30 | key: function (nKeyId) { 31 | return unescape(document.cookie.replace(/\s*\=(?:.(?!;))*$/, "").split(/\s*\=(?:[^;](?!;))*[^;]?;\s*/)[nKeyId]); 32 | }, 33 | setItem: function (sKey, sValue) { 34 | if (!sKey) { return; } 35 | document.cookie = escape(sKey) + "=" + escape(sValue) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/"; 36 | this.length = document.cookie.match(/\=/g).length; 37 | }, 38 | length: 0, 39 | removeItem: function (sKey) { 40 | if (!sKey || !this.hasOwnProperty(sKey)) { return; } 41 | document.cookie = escape(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/"; 42 | this.length--; 43 | }, 44 | hasOwnProperty: function (sKey) { 45 | return (new RegExp("(?:^|;\\s*)" + escape(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); 46 | } 47 | }; 48 | 49 | localSave.length = (document.cookie.match(/\=/g) || localSave).length; 50 | } else { 51 | // 52 | // in chrome, disable cookie 53 | 54 | console.log("warning: can not use localStorage and cookie, using memory, will not persist"); 55 | 56 | localSave = function () { 57 | var bag = {}; 58 | 59 | return { 60 | getItem: function (sKey) { 61 | return bag[sKey]; 62 | }, 63 | key: function (nKeyId) { 64 | var i, j = 0; 65 | 66 | for (i in bag) { 67 | if (j == nKeyId) return i; 68 | 69 | ++j; 70 | } 71 | 72 | return null; 73 | }, 74 | setItem: function (sKey, sValue) { 75 | var i, len = 0; 76 | 77 | bag[sKey] = sValue; 78 | 79 | for (i in bag)++len; 80 | 81 | this.length = len; 82 | }, 83 | length: 0, // in this case length is initially 0 84 | removeItem: function (sKey) { 85 | bag[sKey] = undefined; 86 | 87 | for (i in bag)++len; 88 | 89 | this.length = len; 90 | } 91 | }; 92 | }(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /html/js/check.js: -------------------------------------------------------------------------------- 1 | var nebulas = require("nebulas"), 2 | Account = nebulas.Account, 3 | neb = new nebulas.Neb(), 4 | Unit = nebulas.Unit; 5 | (hash = location.search.slice(1)), (validateAll = uiBlock.validate()); 6 | 7 | uiBlock.insert({ 8 | footer: ".footer", 9 | header: ".header", 10 | logoMain: ".logo-main", 11 | numberComma: ".number-comma", 12 | }); 13 | 14 | $("#btn_done").hide(); 15 | 16 | neb.setRequest( 17 | new nebulas.HttpRequest( 18 | localSave.getItem("apiPrefix") || "https://testnet.nebulas.io/" 19 | ) 20 | ); 21 | $("#btn").on("click", onClickBtn); 22 | $("#btn_done").on("click", function () { 23 | window.close(); 24 | }); 25 | 26 | $(function () { 27 | if (hash) { 28 | //如果hash不为空,说明是从交易页面跳转过来的,直接出发查询过程 29 | $("#input").val(hash); 30 | $("#btn").trigger("click"); 31 | } 32 | }); 33 | 34 | var countDown; 35 | function setAutoCheck() { 36 | //if($(".status").text() !== "success"){ 37 | var interval = 1000; 38 | var second = 15 + 1; 39 | var number = second; 40 | 41 | clearInterval(countDown); 42 | countDown = setInterval(function () { 43 | if ($(".status").text() === "success" || $(".status").text() === "fail") { 44 | clearInterval(countDown); 45 | //$("#counterDown").remove() 46 | $("#btn").hide(); 47 | $("#btn_done").show(); 48 | return; 49 | } 50 | 51 | number--; 52 | //创建或更新倒计时显示,显示number值 53 | if ($("#counterDown").length > 0) { 54 | $("#counterDown").text(" (" + number + ")"); 55 | } else { 56 | var spanTag = document.createElement("span"); 57 | spanTag.id = "counterDown"; 58 | spanTag.innerHTML = "(" + number + ")"; 59 | $("#btn").append(spanTag); 60 | } 61 | //等待倒计时结束 62 | if (number === 0) { 63 | //number = second 64 | onClickBtn(); 65 | } 66 | }, interval); 67 | //} 68 | } 69 | 70 | // function onClickBtn() { 71 | // setAutoCheck() 72 | // onClickBtnRefresh() 73 | // } 74 | 75 | function onClickBtn() { 76 | var addr = $("#input").val(); 77 | 78 | if (validateAll()) { 79 | $(".modal.loading").modal("show"); 80 | 81 | neb.api 82 | .getTransactionReceipt(addr) 83 | .then(doneGetTransactionReceipt) 84 | .catch(function (o) { 85 | $(".modal.loading").modal("hide"); 86 | 87 | bootbox.dialog({ 88 | backdrop: true, 89 | message: i18n.apiErrorToText(o.message), 90 | onEscape: true, 91 | size: "large", 92 | title: "Error", 93 | }); 94 | }); 95 | } else { 96 | $(".errmsg").removeClass("active1"); 97 | setTimeout(function () { 98 | $(".errmsg").addClass("active1"); 99 | }, 2000); 100 | } 101 | setAutoCheck(); 102 | } 103 | 104 | function doneGetTransactionReceipt(o) { 105 | /* 106 | if (o.data) { 107 | data = atob(o.data); 108 | lang = Prism.languages.javascript; 109 | 110 | if (o.type == "binary") 111 | s = data; 112 | else if (o.type == "deploy") 113 | s = Prism.highlight(js_beautify(JSON.parse(data).Source), lang); 114 | else if (o.type == "call") 115 | s = Prism.highlight(js_beautify(data), lang); 116 | else 117 | s = "0x0"; 118 | 119 | $("#code").html(s); 120 | } 121 | */ 122 | $(".modal.loading").modal("hide"); 123 | 124 | $("#info").removeClass("active1"); 125 | $("#code").text( 126 | uiBlock.isNRC20ContractAddr(o.to) ? $.base64.decode(o.data) : o.data 127 | ); 128 | $(".tx_hash").text(o.hash); 129 | $(".contract_addr").text(o.contract_address); 130 | $(".status").text( 131 | o.status == 1 ? "success" : o.status == 0 ? "fail" : "pending" 132 | ); 133 | $(".status").css( 134 | "color", 135 | o.status == 1 ? "green" : o.status == 0 ? "red" : "blue" 136 | ); 137 | $(".from_address").text(o.from); 138 | $(".to_address").text(o.to); 139 | $(".nonce").text(o.nonce); 140 | 141 | var nas = Unit.fromBasic(o.value, "nas").toString(10); 142 | 143 | $(".amount input").val(nas).trigger("input"); 144 | $(".gas-limit input").val(o.gas_limit).trigger("input"); 145 | $(".gas-price input").val(o.gas_price).trigger("input"); 146 | $(".gas-used input").val(o.gas_used).trigger("input"); 147 | } 148 | -------------------------------------------------------------------------------- /html/js/global.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** file: js/global.js 3 | ** description: global javascript library containing code for use across the entire chrome extension, for 4 | ** unique functionality for specific pages, create and use a separate file named "pagename.js" 5 | */ -------------------------------------------------------------------------------- /html/js/home.v1.js: -------------------------------------------------------------------------------- 1 | function checkEmail(email) { 2 | var emailRegex = /[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+/g; 3 | var isEmail = email.match(emailRegex); 4 | isEmail = isEmail && isEmail.length > 0; 5 | if (!isEmail) { 6 | bootbox.dialog({ 7 | title: 'Invalid Email', 8 | message: "Please provide a valid email address", 9 | }); 10 | return isEmail; 11 | } 12 | return isEmail; 13 | } 14 | 15 | function checkWallet(wallet) { 16 | var walletRegex = /(0x)?[\w]{48}/g; 17 | var isWallet = wallet.match(walletRegex); 18 | isWallet = isWallet && isWallet.length > 0; 19 | if (!isWallet) { 20 | bootbox.dialog({ 21 | title: 'Invalid Wallet Address', 22 | message: "[0x] + hex string(40 letters) + checksum(8 letters)", 23 | }); 24 | return isWallet; 25 | } 26 | return isWallet; 27 | } 28 | 29 | $(function () { 30 | $('#frmToken').on("submit", function (e) { 31 | e.preventDefault(); 32 | 33 | var email = $('#tokEmail').val(); 34 | var wallet = $("#tokWallet").val(); 35 | if (checkEmail(email) && checkWallet(wallet)) { 36 | var url = "/claim/api/claim/" + email + "/" + wallet + "/"; 37 | $.get(url, function (resp) { 38 | console.log(resp); 39 | if (resp.hash) { 40 | bootbox.dialog({ 41 | title: 'Send Claim Tx Successfully', 42 | message: "Claim Token Tx Hash is " + resp.hash, 43 | size: 'large' 44 | }); 45 | } else { 46 | bootbox.dialog({ 47 | title: 'Send Claim Tx Failed', 48 | message: resp.error, 49 | }); 50 | } 51 | }).fail(function () { 52 | bootbox.alert({ 53 | message: "Sorry, server is busy!", 54 | }); 55 | }); 56 | } 57 | }); 58 | 59 | $('#frmState').on("submit", function (e) { 60 | e.preventDefault(); 61 | 62 | var wallet = $("#stWallet").val(); 63 | if (checkWallet(wallet)) { 64 | var url = "/claim/api/state/" + wallet + "/"; 65 | $.get(url, function (resp) { 66 | console.log(resp); 67 | if (resp.balance) { 68 | bootbox.dialog({ 69 | title: 'Fetch State Successfully', 70 | message: "Balance: " + resp.balance + "\nNonce: " + resp.nonce, 71 | }); 72 | } else { 73 | bootbox.dialog({ 74 | title: 'Fetch State Failed', 75 | message: resp.error, 76 | }); 77 | } 78 | }).fail(function () { 79 | bootbox.alert({ 80 | message: "Sorry, server is busy!", 81 | }); 82 | }); 83 | } 84 | }); 85 | }); -------------------------------------------------------------------------------- /html/js/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | // replace ="([^ =]+)" with =$1 4 | 5 | var nebulas = require("nebulas"), 6 | account = nebulas.Account.NewAccount(), 7 | validateAll = uiBlock.validate(); 8 | 9 | uiBlock.insert({ 10 | footer: ".footer", 11 | header: ".header", 12 | logoMain: ".logo-main" 13 | }); 14 | 15 | $("#creat").on("click", onClickCreate); 16 | $(".download button").on("click", onClickDownloadButton); 17 | 18 | function onClickCreate() { 19 | validateAll() && $(".download").removeClass("active1"); 20 | } 21 | 22 | function onClickDownloadButton() { 23 | var password = $("#password").val(), address, keyStr, blob; 24 | 25 | if (validateAll()) { 26 | bootbox.alert({ 27 | message: "waiting...", 28 | title: "info" 29 | }); 30 | 31 | // window.open('tokey.html?password=' + password, '_blank'); 32 | 33 | address = account.getAddressString(); 34 | keyStr = account.toKeyString(password); 35 | blob = new Blob([keyStr], { type: "application/json; charset=utf-8" }); 36 | //saveAs(blob, address); 37 | var i = window.document.createElement("a"); 38 | i.target = "_blank", 39 | i.href = window.URL.createObjectURL(blob) 40 | i.download = address 41 | document.body.appendChild(i) 42 | i.click() 43 | document.body.removeChild(i) 44 | 45 | bootbox.hideAll(); 46 | } 47 | } -------------------------------------------------------------------------------- /html/js/main.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** file: js/main.js 3 | ** description: javascript code for "html/main.html" page 4 | */ 5 | 6 | function init_main () { 7 | $('html').hide().fadeIn('slow'); 8 | } 9 | 10 | //bind events to dom elements 11 | document.addEventListener('DOMContentLoaded', init_main); -------------------------------------------------------------------------------- /html/js/options.js: -------------------------------------------------------------------------------- 1 | /* 2 | ** file: js/options.js 3 | ** description: javascript code for "html/options.html" page 4 | */ 5 | 6 | function init_options () { 7 | console.log("function: init_options"); 8 | 9 | //load currently stored options configuration 10 | var favorite_movie = localStorage['favorite_movie']; 11 | 12 | //set the current state of the options form elements to match the stored options values 13 | //favorite_movie 14 | if (favorite_movie) { 15 | var favorite_movie_dropdown = document.getElementById('favorite-movie-dropdown'); 16 | for (var i=0; i < favorite_movie_dropdown.children.length; i++) { 17 | var option = favorite_movie_dropdown.children[i]; 18 | if (option.value == favorite_movie) { 19 | option.selected = 'true'; 20 | break; 21 | } 22 | } 23 | } 24 | } 25 | 26 | function save_options () { 27 | console.log("function: save_options"); 28 | 29 | //favorite-movie-dropdown 30 | var favorite_movie = document.getElementById('favorite-movie-dropdown').children[document.getElementById('favorite-movie-dropdown').selectedIndex].value; 31 | localStorage['favorite_movie'] = favorite_movie; 32 | console.log("favorite_movie = " + favorite_movie); 33 | } 34 | 35 | //bind events to dom elements 36 | document.addEventListener('DOMContentLoaded', init_options); 37 | document.querySelector('#save-options-button').addEventListener('click', save_options); -------------------------------------------------------------------------------- /html/js/sendNas.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var nebulas = require("nebulas"), 4 | Transaction = nebulas.Transaction, 5 | Utils = nebulas.Utils, 6 | Unit = nebulas.Unit, 7 | neb = new nebulas.Neb(), 8 | validateAll = uiBlock.validate(), 9 | gLastGenerateInfo = {}, 10 | gAccount, 11 | gTx; 12 | 13 | var TOKEN_DECIMALS = { 14 | NAX: 9, 15 | nUSDT: 6, 16 | default: 18, 17 | }; 18 | 19 | function getTokenDecimal(token) { 20 | if (token in TOKEN_DECIMALS) { 21 | return TOKEN_DECIMALS[token]; 22 | } else { 23 | return TOKEN_DECIMALS["default"]; 24 | } 25 | } 26 | 27 | neb.setRequest( 28 | new nebulas.HttpRequest( 29 | localSave.getItem("apiPrefix") || "https://testnet.nebulas.io/" 30 | ) 31 | ); 32 | $("#generate").on("click", onClickGenerate); 33 | $("#reject").on("click", onClickReject); 34 | $("#rejectAll").on("click", onClickRejectAll); 35 | $("#modal-confirm .s").on("click", onClickModalConfirmS); 36 | $("#send_transaction").on("click", onClickSendTransaction); 37 | $("#change-wallet").on("click", onClickChangeWallet); 38 | 39 | uiBlock.insert({ 40 | footer: ".footer", 41 | header: ".header", 42 | iconAddress: ".icon-address", 43 | logoMain: ".logo-main", 44 | numberComma: ".number-comma", 45 | selectWalletFile: [".select-wallet-file", onUnlockFile], 46 | }); 47 | 48 | function onCurrencyChanged() { 49 | updateBalance(); 50 | } 51 | uiBlock.addCurrencyChangedListener(onCurrencyChanged); 52 | 53 | function hideKeyFileInput() { 54 | $(".select-wallet-file").hide(); 55 | $(".change_wallet").show(); 56 | } 57 | 58 | function onClickChangeWallet() { 59 | $(".select-wallet-file").show(); 60 | $(".change_wallet").hide(); 61 | } 62 | 63 | function onUnlockFile(swf, fileJson, account, password) { 64 | try { 65 | var value = new Object(); 66 | //value.swf = swf; 67 | value.fileJson = fileJson; 68 | value.password = password; 69 | //console.log("keyInfo to be stored: " + JSON.stringify(JSON.parse(value))) 70 | var valueJson = JSON.stringify(value); 71 | console.log("valueJson: " + valueJson); 72 | chrome.storage.local.set({ keyInfo: valueJson }, function () { 73 | console.log("Value is set to " + valueJson); 74 | }); 75 | messageToBackground("newWallet", "true"); 76 | } catch (e) { 77 | console.log("storage set error" + e); 78 | } 79 | 80 | var address; 81 | try { 82 | account.fromKey(fileJson, password); 83 | address = account.getAddressString(); 84 | gAccount = account; 85 | 86 | $(".icon-address.from input").val(address).trigger("input"); // gen icon from addr, needs trigger 'input' event if via set o.value 87 | $("#unlock").hide(); 88 | $("#send").show(); 89 | 90 | updateBalance(); 91 | } catch (e) { 92 | // this catches e thrown by nebulas.js!account 93 | bootbox.dialog({ 94 | backdrop: true, 95 | onEscape: true, 96 | message: 97 | localSave.getItem("lang") == "en" 98 | ? e 99 | : "keystore 文件错误, 或者密码错误", 100 | size: "large", 101 | title: "Error", 102 | }); 103 | } 104 | } 105 | 106 | function updateBalance() { 107 | if (!gAccount) { 108 | return; 109 | } 110 | var addr = gAccount.getAddressString(); 111 | var currency = uiBlock.currency; 112 | var contractAddr = uiBlock.getContractAddr(uiBlock.currency); 113 | $("#balance").val("").trigger("input"); 114 | if (currency == "NAS") { 115 | neb.api 116 | .getAccountState(addr) 117 | .then(function (resp) { 118 | if (currency != uiBlock.currency) { 119 | return; 120 | } 121 | if (resp.error) { 122 | throw new Error(resp.error); 123 | } 124 | var nas = Unit.fromBasic(resp.balance, "nas").toString(10); 125 | $("#balance").val(nas).trigger("input"); // add comma & unit from value, needs trigger 'input' event if via set o.value 126 | $("#nonce").val(parseInt(resp.nonce || 0) + 1); 127 | }) 128 | .catch(function (e) { 129 | if (currency != uiBlock.currency) { 130 | return; 131 | } 132 | // this catches e thrown by nebulas.js!neb 133 | bootbox.dialog({ 134 | backdrop: true, 135 | onEscape: true, 136 | message: i18n.apiErrorToText(e.message), 137 | size: "large", 138 | title: "Error", 139 | }); 140 | }); 141 | } else { 142 | var contract = { function: "balanceOf", args: '["' + addr + '"]' }; 143 | neb.api 144 | .call({ 145 | from: addr, 146 | to: uiBlock.getContractAddr(uiBlock.currency), 147 | gasLimit: 400000, 148 | gasPrice: 20000000000, 149 | value: 0, 150 | contract: contract, 151 | }) 152 | .then(function (resp) { 153 | if (currency != uiBlock.currency) { 154 | return; 155 | } 156 | if (resp.error) { 157 | throw new Error(resp.error); 158 | } 159 | var b = resp.result.replace(/"/gi, ""); 160 | // let decimals = uiBlock.currency == "NAX" ? "gwei" : "nas"; 161 | // var balance = Unit.fromBasic(b, decimals).toString(10); 162 | 163 | let decimals = getTokenDecimal(uiBlock.currency); 164 | 165 | let decimalsBig = Utils.toBigNumber(10).pow(decimals); 166 | 167 | let balance = Utils.toBigNumber(b).dividedBy(decimalsBig).toString(10); 168 | 169 | $("#balance").val(balance).trigger("input"); // add comma & unit from value, needs trigger 'input' event if via set o.value 170 | }) 171 | .catch(function (e) { 172 | if (currency != uiBlock.currency) { 173 | return; 174 | } 175 | // this catches e thrown by nebulas.js!neb 176 | bootbox.dialog({ 177 | backdrop: true, 178 | onEscape: true, 179 | message: i18n.apiErrorToText(e.message), 180 | size: "large", 181 | title: "Error", 182 | }); 183 | }); 184 | 185 | neb.api 186 | .getAccountState(addr) 187 | .then(function (resp) { 188 | if (!resp.error) { 189 | $("#nonce").val(parseInt(resp.nonce || 0) + 1); 190 | } 191 | }) 192 | .catch(function (e) {}); 193 | } 194 | } 195 | 196 | function onClickReject() { 197 | messageToBackground("reject", "true"); 198 | 199 | messageToBackground("default", "Error: Transaction rejected by user"); 200 | //getNextTx() 201 | window.close(); 202 | } 203 | 204 | function onClickRejectAll() { 205 | messageToBackground("rejectAll", "true"); 206 | getNextTx(); //to refresh data 207 | //window.close() 208 | } 209 | 210 | function onClickGenerate() { 211 | messageToBackground("generate", "true"); 212 | 213 | var fromAddress, 214 | toAddress, 215 | balance, 216 | amount, 217 | gaslimit, 218 | gasprice, 219 | nonce, 220 | bnAmount; 221 | var contract = null; 222 | 223 | if (validateAll()) { 224 | fromAddress = $(".icon-address.from input").val(); 225 | toAddress = $(".icon-address.to input").val(); 226 | balance = $("#balance").val(); 227 | amount = $("#amount").val(); 228 | gaslimit = $("#limit").val(); 229 | gasprice = $("#price").val(); 230 | nonce = $("#nonce").val(); 231 | if ($("#contract").val()) contract = JSON.parse($("#contract").val()); 232 | 233 | if ( 234 | gLastGenerateInfo.fromAddress != fromAddress || 235 | gLastGenerateInfo.toAddress != toAddress || 236 | gLastGenerateInfo.balance != balance || 237 | gLastGenerateInfo.amount != amount || 238 | gLastGenerateInfo.gaslimit != gaslimit || 239 | gLastGenerateInfo.gasprice != gasprice || 240 | gLastGenerateInfo.contract != contract || 241 | gLastGenerateInfo.nonce != nonce 242 | ) 243 | try { 244 | var tmp = Unit.fromBasic( 245 | Utils.toBigNumber(gaslimit).times(Utils.toBigNumber(gasprice)), 246 | "nas" 247 | ); 248 | 249 | if (Utils.toBigNumber(balance).lt(Utils.toBigNumber(amount).plus(tmp))) 250 | if (Utils.toBigNumber(balance).lt(tmp)) 251 | bnAmount = Utils.toBigNumber(0); 252 | else 253 | bnAmount = Utils.toBigNumber(balance).minus(Utils.toBigNumber(tmp)); 254 | 255 | var a = amount.split("."); 256 | var amountValid = a.length == 1 || a[1].length <= 18; 257 | if (uiBlock.currency == "NAS" || contract) { 258 | if (!amountValid) 259 | throw new Error( 260 | "Invalid value! The minimum unit is wei (1^-18nas) " 261 | ); 262 | gTx = new Transaction( 263 | parseInt(localSave.getItem("chainId")), 264 | gAccount, 265 | toAddress, 266 | Unit.nasToBasic(Utils.toBigNumber(amount)), 267 | parseInt(nonce), 268 | gasprice, 269 | gaslimit, 270 | contract 271 | ); 272 | } else { 273 | // let decimals = uiBlock.currency == "NAX" ? 9 : 18; 274 | 275 | let decimals = getTokenDecimal(uiBlock.currency); 276 | if (!amountValid) 277 | throw new Error( 278 | "Invalid value! The minimum unit is wei (1^-" + 279 | decimals + 280 | uiBlock.currency.toLowerCase() + 281 | ") " 282 | ); 283 | let value = Utils.toBigNumber(10) 284 | .pow(decimals) 285 | .times(amount) 286 | .toString(10); 287 | contract = { 288 | function: "transfer", 289 | args: '["' + toAddress + '", "' + value + '"]', 290 | type: "call", 291 | }; 292 | gTx = new Transaction( 293 | parseInt(localSave.getItem("chainId")), 294 | gAccount, 295 | uiBlock.getContractAddr(uiBlock.currency), 296 | Unit.nasToBasic(Utils.toBigNumber("0")), 297 | parseInt(nonce), 298 | gasprice, 299 | gaslimit, 300 | contract 301 | ); 302 | } 303 | gTx.signTransaction(); 304 | 305 | $("#raw").val(gTx.toString()); 306 | $("#signed").val(gTx.toProtoString()); 307 | 308 | // //if the length of gTx is to large, then qrcode() will throw an error 309 | // //then the qrcode will be the error message, 310 | // try { 311 | // $("
") 312 | // .qrcode(gTx.toProtoString()) 313 | // .replaceAll('#addressqr'); 314 | // }catch (e) { 315 | // console.log(e); 316 | // $("
") 317 | // .qrcode(e) 318 | // .replaceAll('#addressqr'); 319 | // } 320 | //$("#transaction").show(); 321 | 322 | gLastGenerateInfo.fromAddress = fromAddress; 323 | gLastGenerateInfo.toAddress = toAddress; 324 | gLastGenerateInfo.balance = balance; 325 | gLastGenerateInfo.amount = amount; 326 | gLastGenerateInfo.gaslimit = gaslimit; 327 | gLastGenerateInfo.gasprice = gasprice; 328 | gLastGenerateInfo.nonce = nonce; 329 | 330 | onClickSendTransaction(); 331 | } catch (e) { 332 | bootbox.dialog({ 333 | backdrop: true, 334 | onEscape: true, 335 | message: e, 336 | size: "large", 337 | title: "Error", 338 | }); 339 | } 340 | } 341 | } 342 | 343 | function onClickSendTransaction() { 344 | $("#for_addr").val($(".icon-address.from input").val()); 345 | $("#to_addr").val($(".icon-address.to input").val()); 346 | $("#value").val($("#amount").val()).trigger("input"); 347 | } 348 | 349 | var request = function (obj) { 350 | return new Promise((resolve, reject) => { 351 | let xhr = new XMLHttpRequest(); 352 | xhr.open(obj.method || "GET", obj.url); 353 | if (obj.headers) { 354 | Object.keys(obj.headers).forEach((key) => { 355 | xhr.setRequestHeader(key, obj.headers[key]); 356 | }); 357 | } 358 | xhr.onload = () => { 359 | if (xhr.status >= 200 && xhr.status < 300) { 360 | resolve(xhr.response); 361 | } else { 362 | reject(xhr.response); 363 | } 364 | }; 365 | xhr.onerror = () => reject(xhr.statusText); 366 | xhr.send(obj.body); 367 | }); 368 | }; 369 | 370 | var postCount = 0; //失败后的尝试次数 371 | var maxPostCount = 5; 372 | function postTxhashToServer(txTobeProcessed, mTxHash, callback) { 373 | if (!txTobeProcessed.callback) { 374 | console.log('this tx has no "callback"'); 375 | callback(); 376 | } 377 | var url = txTobeProcessed.callback; 378 | var payId = txTobeProcessed.serialNumber; 379 | var txHash = mTxHash; 380 | 381 | url = `${url}?payId=${payId}&txHash=${txHash}`; 382 | 383 | var obj = { 384 | url: url, 385 | method: "POST", 386 | body: {}, 387 | }; 388 | 389 | request(obj) 390 | .then(function (resp) { 391 | postCount = 0; 392 | //callback({status : 0, info:'Post serialNumber to server successfully'}) 393 | callback(); 394 | }) 395 | .catch(function (error) { 396 | postCount++; 397 | console.log("post SN failed count: " + postCount); 398 | if (postCount > maxPostCount) { 399 | postCount = 0; 400 | //callback({status: 1, info : error.message || error}) //error 401 | callback(error.message || error); //error 402 | } else { 403 | setTimeout(function () { 404 | postTxhashToServer(txTobeProcessed, mTxHash, callback); 405 | }, 500); 406 | } 407 | }); 408 | } 409 | 410 | function onClickModalConfirmS() { 411 | var mTxHash; 412 | 413 | gTx && 414 | neb.api 415 | .sendRawTransaction(gTx.toProtoString()) 416 | .catch(function (o) { 417 | bootbox.dialog({ 418 | backdrop: true, 419 | onEscape: true, 420 | message: i18n.apiErrorToText(o.message), 421 | size: "large", 422 | title: "Error", 423 | }); 424 | }) 425 | .then(function (resp) { 426 | // console.log("sendRawTransaction resp: " + JSON.stringify(resp)); 427 | mTxHash = resp.txhash; 428 | 429 | console.log("txHash got..."); //send txhash msg to background.js 430 | 431 | //messageToBackground("txhash",resp) 432 | 433 | postTxhashToServer(txTobeProcessed, mTxHash, function (postResult) { 434 | if (postResult) { 435 | resp.error = postResult; 436 | } 437 | messageToBackground("txhash", resp); 438 | window.location.href = "check.html?" + mTxHash; 439 | }); 440 | }); 441 | // .then(function (resp) { 442 | // console.log("postTxhashToServer result:" + JSON.stringify(resp)) 443 | // messageToBackground("default","Post serialNumber to server successfully") 444 | // window.location.href = "check.html?" + mTxHash; 445 | // 446 | // }).catch(function (error) { 447 | // console.log("post txhash To Server error:") 448 | // console.log(JSON.stringify(error)) 449 | // //failed, try again 450 | // return postTxhashToServer(txTobeProcessed, mTxHash) //try for second time 451 | // }).then(function (resp) { 452 | // messageToBackground("default","serialNumber poster to server successfully") 453 | // console.log("postTxhashToServer result:" + JSON.stringify(resp)) 454 | // window.location.href = "check.html?" + mTxHash; 455 | // 456 | // }).catch(function (error) { 457 | // console.log("post txhash to Server error:") 458 | // console.log(JSON.stringify(error)) 459 | // messageToBackground("default",{error:'Post serialNumber to server failed: ' , request_response: (error.message || error)}) 460 | // }) 461 | 462 | // $("#receipt_div").show(); 463 | } 464 | -------------------------------------------------------------------------------- /html/js/sendOffline.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var nebulas = require("nebulas"), 4 | Account = nebulas.Account, 5 | Neb = nebulas.Neb, 6 | Transaction = nebulas.Transaction, 7 | utils = nebulas.Utils, 8 | unit = nebulas.Unit, 9 | neb = new Neb(), 10 | gAccount = new Account(), 11 | gLastGenerateInfo = {}, 12 | validateStep1 = uiBlock.validate("#step1"), 13 | validateStep2 = uiBlock.validate("#step2"), 14 | gFromState; 15 | 16 | neb.setRequest(new nebulas.HttpRequest(localSave.getItem("apiPrefix") || "https://testnet.nebulas.io/")); 17 | $("#exampleModal .send").on("click", onClickExampleModalSend); 18 | $("#generate").on("click", onClickGenerate); 19 | $("#generate-infomation").on("click", onClickGenerateInfomation); 20 | $("#signedoffline").on({ 21 | focus: onFocusSignedOffline, 22 | input: onInputSignedOffline 23 | }); 24 | $("#step3 .send").on("click", onClickStep3Send); 25 | 26 | uiBlock.insert({ 27 | footer: ".footer", 28 | header: ".header", 29 | iconAddress: ".icon-address", 30 | logoMain: ".logo-main", 31 | numberComma: ".number-comma", 32 | selectWalletFile: [".select-wallet-file", onUnlockFile] 33 | }); 34 | 35 | function onUnlockFile(swf, fileJson, account, password) { 36 | var address; 37 | 38 | try { 39 | account.fromKey(fileJson, password); 40 | address = account.getAddressString(); 41 | gAccount = account; 42 | 43 | $("#step2 .icon-address.from input").val(address).trigger("input"); 44 | $(".transaction").show(); 45 | } catch (e) { 46 | bootbox.dialog({ 47 | backdrop: true, 48 | onEscape: true, 49 | message: localSave.getItem("lang") == "en" ? e : "keystore 文件错误, 或者密码错误", 50 | size: "large", 51 | title: "Error" 52 | }); 53 | } 54 | } 55 | 56 | function onClickStep3Send() { 57 | var val = $("#signedoffline").val(), tx; 58 | 59 | if (val) try { 60 | tx = Transaction.prototype.fromProto(val); 61 | $("#for_addr").val(tx.from.getAddressString()); 62 | $("#to_addr").val(tx.to.getAddressString()); 63 | $("#value").val(unit.fromBasic(tx.value, "nas")).trigger("input"); 64 | // $("#value").val(unit.nasToBasic(tx.value).c); 65 | } catch (err) { 66 | bootbox.dialog({ 67 | backdrop: true, 68 | onEscape: true, 69 | message: localSave.getItem("lang") == "en" ? err.message : "无效的签名交易", 70 | size: "large", 71 | title: "Error" 72 | }); 73 | } 74 | } 75 | 76 | function onClickGenerate() { 77 | var fromaddress, toaddress, amount, nonce, gaslimit, gasprice, toaccount, tx; 78 | 79 | if (validateStep2()) { 80 | fromaddress = $(".icon-address.from input").val(); 81 | toaddress = $(".icon-address.to input").val(); 82 | amount = $("#amount").val(); 83 | nonce = $("#nonce").val(); 84 | gaslimit = $("#limit").val(); 85 | gasprice = $("#price").val(); 86 | 87 | if (gLastGenerateInfo.fromaddress != fromaddress || 88 | gLastGenerateInfo.toaddress != toaddress || 89 | gLastGenerateInfo.amount != amount || 90 | gLastGenerateInfo.nonce != nonce || 91 | gLastGenerateInfo.gaslimit != gaslimit || 92 | gLastGenerateInfo.gasprice != gasprice) try { 93 | toaccount = Account.fromAddress(toaddress); 94 | 95 | tx = new Transaction(parseInt(localSave.getItem("chainId")), gAccount, toaccount.getAddressString(), unit.nasToBasic(amount), parseInt(nonce), gasprice, gaslimit); 96 | tx.signTransaction(); 97 | 98 | $("#raw").val(tx.toString()); 99 | $("#signed").val(tx.toProtoString()); 100 | $("#signedoffline").val(tx.toProtoString()); 101 | // $("#qrcode").qrcode(tx.toProtoString()); 102 | 103 | $("
") 104 | .qrcode(tx.toProtoString()) 105 | .replaceAll('#qrcode'); 106 | 107 | $(".transaction").show(); 108 | 109 | gLastGenerateInfo.fromaddress = fromaddress; 110 | gLastGenerateInfo.toaddress = toaddress; 111 | gLastGenerateInfo.amount = amount; 112 | gLastGenerateInfo.nonce = nonce; 113 | gLastGenerateInfo.gaslimit = gaslimit; 114 | gLastGenerateInfo.gasprice = gasprice; 115 | } catch (e) { 116 | bootbox.dialog({ 117 | backdrop: true, 118 | onEscape: true, 119 | message: e, 120 | size: "large", 121 | title: "Error" 122 | }); 123 | } 124 | } 125 | } 126 | 127 | function onClickGenerateInfomation() { 128 | var fromaddress = $(".icon-address.from input").val(); 129 | 130 | if (validateStep1()) 131 | try { 132 | neb.api.gasPrice() 133 | .then(function (resp) { 134 | $("#fa_gasprice").val(resp.gas_price); 135 | $("#price").val(resp.gas_price); 136 | 137 | return neb.api.getAccountState(fromaddress); 138 | }) 139 | .then(function (resp) { 140 | gFromState = { 141 | balance: resp.balance, 142 | nonce: resp.nonce 143 | }; 144 | 145 | $("#fa_nonce").val(parseInt(resp.nonce) + 1); 146 | $("#nonce").val(parseInt(resp.nonce) + 1); 147 | $("#information").show(); 148 | }) 149 | .catch(function (e) { 150 | // https://stackoverflow.com/questions/30715367/why-can-i-not-throw-inside-a-promise-catch-handler 151 | bootbox.dialog({ 152 | backdrop: true, 153 | onEscape: true, 154 | message: e, 155 | size: "large", 156 | title: "Error" 157 | }); 158 | }); 159 | } catch (e) { 160 | bootbox.dialog({ 161 | backdrop: true, 162 | onEscape: true, 163 | message: e, 164 | size: "large", 165 | title: "Error" 166 | }); 167 | } 168 | } 169 | 170 | function onFocusSignedOffline() { 171 | $("[data-validate-order-matters]").removeClass("invalid").popover("hide"); 172 | } 173 | 174 | function onInputSignedOffline() { 175 | $("
") 176 | .qrcode($("#signedoffline").val()) 177 | .replaceAll('#qrcode'); 178 | } 179 | 180 | function onClickExampleModalSend() { 181 | neb.api.sendRawTransaction($("#signedoffline").val()) 182 | .then(function (resp) { 183 | return neb.api.getTransactionReceipt(resp.txhash); 184 | }).then(function (resp) { 185 | $("#receipt_state").val(JSON.stringify(resp)); 186 | $("#receipt").text(resp.hash).prop("href", "check.html?" + resp.hash); 187 | $("#receipt_div").show(); 188 | }).catch(function (o) { 189 | bootbox.dialog({ 190 | backdrop: true, 191 | onEscape: true, 192 | message: i18n.apiErrorToText(o.message), 193 | size: "large", 194 | title: "Error" 195 | }); 196 | }); 197 | } -------------------------------------------------------------------------------- /html/js/viewWalletInfo.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var nebulas = require("nebulas"), 4 | Account = nebulas.Account, 5 | Neb = nebulas.Neb, 6 | Transaction = nebulas.Transaction, 7 | Utils = nebulas.Utils, 8 | neb = new Neb(), 9 | gAccount, gFileJson; 10 | 11 | neb.setRequest(new nebulas.HttpRequest(localSave.getItem("apiPrefix") || "https://testnet.nebulas.io/")); 12 | $("#keystore").on("click", onClickKeystore); 13 | $("#togglePassword").on("change", onChangeTogglePassword); 14 | 15 | uiBlock.insert({ 16 | footer: ".footer", 17 | header: ".header", 18 | logoMain: ".logo-main", 19 | selectWalletFile: [".select-wallet-file", onUnlockFile] 20 | }); 21 | 22 | function onUnlockFile(swf, fileJson, account, password) { 23 | try { 24 | gAccount = account; 25 | gFileJson = fileJson; 26 | account.fromKey(fileJson, password); 27 | 28 | $("#address").val(account.getAddressString()); 29 | $("#sideaddress").text(account.getAddressString()); 30 | $("#password").val(account.getPrivateKeyString()); 31 | $("#addressqr").qrcode(account.getAddressString()); 32 | $("#privateqr").qrcode(account.getPrivateKeyString()); 33 | $("#walletinfo").show(); 34 | 35 | neb.api.getAccountState(account.getAddressString()) 36 | .then(function (resp) { 37 | if (resp.error) { 38 | throw new Error(resp.error); 39 | } else { 40 | $("#amount").val(nebulas.Unit.fromBasic(Utils.toBigNumber(resp.balance), "nas").toNumber() + " NAS"); 41 | } 42 | }) 43 | .catch(function (e) { 44 | // this catches e thrown by nebulas.js!neb 45 | 46 | bootbox.dialog({ 47 | backdrop: true, 48 | onEscape: true, 49 | message: i18n.apiErrorToText(e.message), 50 | size: "large", 51 | title: "Error" 52 | }); 53 | }); 54 | } catch (e) { 55 | // this catches e thrown by nebulas.js!account 56 | 57 | bootbox.dialog({ 58 | backdrop: true, 59 | onEscape: true, 60 | message: localSave.getItem("lang") == "en" ? e : "keystore 文件错误, 或者密码错误", 61 | size: "large", 62 | title: "Error" 63 | }); 64 | } 65 | } 66 | 67 | function onClickKeystore() { 68 | var blob = new Blob([JSON.stringify(gFileJson)], { type: "application/json; charset=utf-8" }); 69 | saveAs(blob, gAccount.getAddressString()); 70 | } 71 | 72 | function onChangeTogglePassword(e) { 73 | if (e.target.checked) { 74 | $("#password").prop("type", "text"); 75 | $(".key_qr").removeClass("display-none"); 76 | } else { 77 | $("#password").prop("type", "password"); 78 | $(".key_qr").addClass("display-none"); 79 | } 80 | } -------------------------------------------------------------------------------- /html/lib/Blob.js: -------------------------------------------------------------------------------- 1 | /* Blob.js 2 | * A Blob implementation. 3 | * 2018-01-12 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * By Devin Samarin, https://github.com/dsamarin 7 | * License: MIT 8 | * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md 9 | */ 10 | 11 | /*global self, unescape */ 12 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 13 | plusplus: true */ 14 | 15 | /*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ 16 | 17 | (function (view) { 18 | "use strict"; 19 | 20 | view.URL = view.URL || view.webkitURL; 21 | 22 | if (view.Blob && view.URL) { 23 | try { 24 | new Blob; 25 | return; 26 | } catch (e) {} 27 | } 28 | 29 | // Internally we use a BlobBuilder implementation to base Blob off of 30 | // in order to support older browsers that only have BlobBuilder 31 | var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { 32 | var 33 | get_class = function(object) { 34 | return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; 35 | } 36 | , FakeBlobBuilder = function BlobBuilder() { 37 | this.data = []; 38 | } 39 | , FakeBlob = function Blob(data, type, encoding) { 40 | this.data = data; 41 | this.size = data.length; 42 | this.type = type; 43 | this.encoding = encoding; 44 | } 45 | , FBB_proto = FakeBlobBuilder.prototype 46 | , FB_proto = FakeBlob.prototype 47 | , FileReaderSync = view.FileReaderSync 48 | , FileException = function(type) { 49 | this.code = this[this.name = type]; 50 | } 51 | , file_ex_codes = ( 52 | "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " 53 | + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" 54 | ).split(" ") 55 | , file_ex_code = file_ex_codes.length 56 | , real_URL = view.URL || view.webkitURL || view 57 | , real_create_object_URL = real_URL.createObjectURL 58 | , real_revoke_object_URL = real_URL.revokeObjectURL 59 | , URL = real_URL 60 | , btoa = view.btoa 61 | , atob = view.atob 62 | 63 | , ArrayBuffer = view.ArrayBuffer 64 | , Uint8Array = view.Uint8Array 65 | 66 | , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ 67 | ; 68 | FakeBlob.fake = FB_proto.fake = true; 69 | while (file_ex_code--) { 70 | FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; 71 | } 72 | // Polyfill URL 73 | if (!real_URL.createObjectURL) { 74 | URL = view.URL = function(uri) { 75 | var 76 | uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") 77 | , uri_origin 78 | ; 79 | uri_info.href = uri; 80 | if (!("origin" in uri_info)) { 81 | if (uri_info.protocol.toLowerCase() === "data:") { 82 | uri_info.origin = null; 83 | } else { 84 | uri_origin = uri.match(origin); 85 | uri_info.origin = uri_origin && uri_origin[1]; 86 | } 87 | } 88 | return uri_info; 89 | }; 90 | } 91 | URL.createObjectURL = function(blob) { 92 | var 93 | type = blob.type 94 | , data_URI_header 95 | ; 96 | if (type === null) { 97 | type = "application/octet-stream"; 98 | } 99 | if (blob instanceof FakeBlob) { 100 | data_URI_header = "data:" + type; 101 | if (blob.encoding === "base64") { 102 | return data_URI_header + ";base64," + blob.data; 103 | } else if (blob.encoding === "URI") { 104 | return data_URI_header + "," + decodeURIComponent(blob.data); 105 | } if (btoa) { 106 | return data_URI_header + ";base64," + btoa(blob.data); 107 | } else { 108 | return data_URI_header + "," + encodeURIComponent(blob.data); 109 | } 110 | } else if (real_create_object_URL) { 111 | return real_create_object_URL.call(real_URL, blob); 112 | } 113 | }; 114 | URL.revokeObjectURL = function(object_URL) { 115 | if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { 116 | real_revoke_object_URL.call(real_URL, object_URL); 117 | } 118 | }; 119 | FBB_proto.append = function(data/*, endings*/) { 120 | var bb = this.data; 121 | // decode data to a binary string 122 | if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { 123 | var 124 | str = "" 125 | , buf = new Uint8Array(data) 126 | , i = 0 127 | , buf_len = buf.length 128 | ; 129 | for (; i < buf_len; i++) { 130 | str += String.fromCharCode(buf[i]); 131 | } 132 | bb.push(str); 133 | } else if (get_class(data) === "Blob" || get_class(data) === "File") { 134 | if (FileReaderSync) { 135 | var fr = new FileReaderSync; 136 | bb.push(fr.readAsBinaryString(data)); 137 | } else { 138 | // async FileReader won't work as BlobBuilder is sync 139 | throw new FileException("NOT_READABLE_ERR"); 140 | } 141 | } else if (data instanceof FakeBlob) { 142 | if (data.encoding === "base64" && atob) { 143 | bb.push(atob(data.data)); 144 | } else if (data.encoding === "URI") { 145 | bb.push(decodeURIComponent(data.data)); 146 | } else if (data.encoding === "raw") { 147 | bb.push(data.data); 148 | } 149 | } else { 150 | if (typeof data !== "string") { 151 | data += ""; // convert unsupported types to strings 152 | } 153 | // decode UTF-16 to binary string 154 | bb.push(unescape(encodeURIComponent(data))); 155 | } 156 | }; 157 | FBB_proto.getBlob = function(type) { 158 | if (!arguments.length) { 159 | type = null; 160 | } 161 | return new FakeBlob(this.data.join(""), type, "raw"); 162 | }; 163 | FBB_proto.toString = function() { 164 | return "[object BlobBuilder]"; 165 | }; 166 | FB_proto.slice = function(start, end, type) { 167 | var args = arguments.length; 168 | if (args < 3) { 169 | type = null; 170 | } 171 | return new FakeBlob( 172 | this.data.slice(start, args > 1 ? end : this.data.length) 173 | , type 174 | , this.encoding 175 | ); 176 | }; 177 | FB_proto.toString = function() { 178 | return "[object Blob]"; 179 | }; 180 | FB_proto.close = function() { 181 | this.size = 0; 182 | delete this.data; 183 | }; 184 | return FakeBlobBuilder; 185 | }(view)); 186 | 187 | view.Blob = function(blobParts, options) { 188 | var type = options ? (options.type || "") : ""; 189 | var builder = new BlobBuilder(); 190 | if (blobParts) { 191 | for (var i = 0, len = blobParts.length; i < len; i++) { 192 | if (Uint8Array && blobParts[i] instanceof Uint8Array) { 193 | builder.append(blobParts[i].buffer); 194 | } 195 | else { 196 | builder.append(blobParts[i]); 197 | } 198 | } 199 | } 200 | var blob = builder.getBlob(type); 201 | if (!blob.slice && blob.webkitSlice) { 202 | blob.slice = blob.webkitSlice; 203 | } 204 | return blob; 205 | }; 206 | 207 | var getPrototypeOf = Object.getPrototypeOf || function(object) { 208 | return object.__proto__; 209 | }; 210 | view.Blob.prototype = getPrototypeOf(new view.Blob()); 211 | }( 212 | typeof self !== "undefined" && self 213 | || typeof window !== "undefined" && window 214 | || this 215 | )); 216 | -------------------------------------------------------------------------------- /html/lib/FileSaver.min.js: -------------------------------------------------------------------------------- 1 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 2 | var saveAs=saveAs||function(e){"use strict";if(!("undefined"==typeof e||"undefined"!=typeof navigator&&/MSIE [1-9]\./.test(navigator.userAgent))){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,d=/CriOS\/[\d]+/.test(navigator.userAgent),f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",u=4e4,c=function(e){var t=function(){"string"==typeof e?n().revokeObjectURL(e):e.remove()};setTimeout(t,u)},l=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(a){f(a)}}},v=function(e){return/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)?new Blob([String.fromCharCode(65279),e],{type:e.type}):e},p=function(t,f,u){u||(t=v(t));var p,w=this,m=t.type,y=m===s,S=function(){l(w,"writestart progress write writeend".split(" "))},h=function(){if((d||y&&i)&&e.FileReader){var o=new FileReader;return o.onloadend=function(){var t=d?o.result:o.result.replace(/^data:[^;]*;/,"data:attachment/file;"),n=e.open(t,"_blank");n||(e.location.href=t),t=void 0,w.readyState=w.DONE,S()},o.readAsDataURL(t),void(w.readyState=w.INIT)}if(p||(p=n().createObjectURL(t)),y)e.location.href=p;else{var r=e.open(p,"_blank");r||(e.location.href=p)}w.readyState=w.DONE,S(),c(p)};return w.readyState=w.INIT,r?(p=n().createObjectURL(t),void setTimeout(function(){o.href=p,o.download=f,a(o),S(),c(p),w.readyState=w.DONE})):void h()},w=p.prototype,m=function(e,t,n){return new p(e,t||e.name||"download",n)};return"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob?function(e,t,n){return t=t||e.name||"download",n||(e=v(e)),navigator.msSaveOrOpenBlob(e,t)}:(w.abort=function(){},w.readyState=w.INIT=0,w.WRITING=1,w.DONE=2,w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null,m)}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!==define.amd&&define("FileSaver.js",function(){return saveAs}); -------------------------------------------------------------------------------- /html/lib/blockies.min.js: -------------------------------------------------------------------------------- 1 | !function(){function e(e){for(var o=0;o>19^e^e>>8,(c[3]>>>0)/(1<<31>>>0)}function r(){var e=Math.floor(360*o()),r=60*o()+40+"%",t=25*(o()+o()+o()+o())+"%",l="hsl("+e+","+r+","+t+")";return l}function t(e){for(var r=e,t=e,l=Math.ceil(r/2),n=r-l,a=[],c=0;t>c;c++){for(var i=[],f=0;l>f;f++)i[f]=Math.floor(2.3*o());var s=i.slice(0,n);s.reverse(),i=i.concat(s);for(var h=0;h=d&&f===d-1?"btn-primary":"btn-default")}),a}function i(a,b){var c=a.length,d={};if(1>c||c>2)throw new Error("Invalid argument length");return 2===c||"string"==typeof a[0]?(d[b[0]]=a[0],d[b[1]]=a[1]):d=a[0],d}function j(a,c,d){return b.extend(!0,{},a,i(c,d))}function k(a,b,c,d){var e={className:"bootbox-"+a,buttons:l.apply(null,b)};return m(j(e,d,c),b)}function l(){for(var a={},b=0,c=arguments.length;c>b;b++){var e=arguments[b],f=e.toLowerCase(),g=e.toUpperCase();a[f]={label:d(g)}}return a}function m(a,b){var d={};return g(b,function(a,b){d[b]=!0}),g(a.buttons,function(a){if(d[a]===c)throw new Error("button key "+a+" is not allowed (options are "+b.join("\n")+")")}),a}var n={dialog:"",header:"",footer:"",closeButton:"",form:"
",inputs:{text:"",textarea:"",email:"",select:"",checkbox:"
",date:"",time:"",number:"",password:""}},o={locale:"en",backdrop:"static",animate:!0,className:null,closeButton:!0,show:!0,container:"body"},p={};p.alert=function(){var a;if(a=k("alert",["ok"],["message","callback"],arguments),a.callback&&!b.isFunction(a.callback))throw new Error("alert requires callback property to be a function when provided");return a.buttons.ok.callback=a.onEscape=function(){return b.isFunction(a.callback)?a.callback.call(this):!0},p.dialog(a)},p.confirm=function(){var a;if(a=k("confirm",["cancel","confirm"],["message","callback"],arguments),a.buttons.cancel.callback=a.onEscape=function(){return a.callback.call(this,!1)},a.buttons.confirm.callback=function(){return a.callback.call(this,!0)},!b.isFunction(a.callback))throw new Error("confirm requires a callback");return p.dialog(a)},p.prompt=function(){var a,d,e,f,h,i,k;if(f=b(n.form),d={className:"bootbox-prompt",buttons:l("cancel","confirm"),value:"",inputType:"text"},a=m(j(d,arguments,["title","callback"]),["cancel","confirm"]),i=a.show===c?!0:a.show,a.message=f,a.buttons.cancel.callback=a.onEscape=function(){return a.callback.call(this,null)},a.buttons.confirm.callback=function(){var c;switch(a.inputType){case"text":case"textarea":case"email":case"select":case"date":case"time":case"number":case"password":c=h.val();break;case"checkbox":var d=h.find("input:checked");c=[],g(d,function(a,d){c.push(b(d).val())})}return a.callback.call(this,c)},a.show=!1,!a.title)throw new Error("prompt requires a title");if(!b.isFunction(a.callback))throw new Error("prompt requires a callback");if(!n.inputs[a.inputType])throw new Error("invalid prompt type");switch(h=b(n.inputs[a.inputType]),a.inputType){case"text":case"textarea":case"email":case"date":case"time":case"number":case"password":h.val(a.value);break;case"select":var o={};if(k=a.inputOptions||[],!b.isArray(k))throw new Error("Please pass an array of input options");if(!k.length)throw new Error("prompt with select requires options");g(k,function(a,d){var e=h;if(d.value===c||d.text===c)throw new Error("given options in wrong format");d.group&&(o[d.group]||(o[d.group]=b("").attr("label",d.group)),e=o[d.group]),e.append("")}),g(o,function(a,b){h.append(b)}),h.val(a.value);break;case"checkbox":var q=b.isArray(a.value)?a.value:[a.value];if(k=a.inputOptions||[],!k.length)throw new Error("prompt with checkbox requires options");if(!k[0].value||!k[0].text)throw new Error("given options in wrong format");h=b("
"),g(k,function(c,d){var e=b(n.inputs[a.inputType]);e.find("input").attr("value",d.value),e.find("label").append(d.text),g(q,function(a,b){b===d.value&&e.find("input").prop("checked",!0)}),h.append(e)})}return a.placeholder&&h.attr("placeholder",a.placeholder),a.pattern&&h.attr("pattern",a.pattern),a.maxlength&&h.attr("maxlength",a.maxlength),f.append(h),f.on("submit",function(a){a.preventDefault(),a.stopPropagation(),e.find(".btn-primary").click()}),e=p.dialog(a),e.off("shown.bs.modal"),e.on("shown.bs.modal",function(){h.focus()}),i===!0&&e.modal("show"),e},p.dialog=function(a){a=h(a);var d=b(n.dialog),f=d.find(".modal-dialog"),i=d.find(".modal-body"),j=a.buttons,k="",l={onEscape:a.onEscape};if(b.fn.modal===c)throw new Error("$.fn.modal is not defined; please double check you have included the Bootstrap JavaScript library. See http://getbootstrap.com/javascript/ for more details.");if(g(j,function(a,b){k+="",l[a]=b.callback}),i.find(".bootbox-body").html(a.message),a.animate===!0&&d.addClass("fade"),a.className&&d.addClass(a.className),"large"===a.size?f.addClass("modal-lg"):"small"===a.size&&f.addClass("modal-sm"),a.title&&i.before(n.header),a.closeButton){var m=b(n.closeButton);a.title?d.find(".modal-header").prepend(m):m.css("margin-top","-10px").prependTo(i)}return a.title&&d.find(".modal-title").html(a.title),k.length&&(i.after(n.footer),d.find(".modal-footer").html(k)),d.on("hidden.bs.modal",function(a){a.target===this&&d.remove()}),d.on("shown.bs.modal",function(){d.find(".btn-primary:first").focus()}),"static"!==a.backdrop&&d.on("click.dismiss.bs.modal",function(a){d.children(".modal-backdrop").length&&(a.currentTarget=d.children(".modal-backdrop").get(0)),a.target===a.currentTarget&&d.trigger("escape.close.bb")}),d.on("escape.close.bb",function(a){l.onEscape&&e(a,d,l.onEscape)}),d.on("click",".modal-footer button",function(a){var c=b(this).data("bb-handler");e(a,d,l[c])}),d.on("click",".bootbox-close-button",function(a){e(a,d,l.onEscape)}),d.on("keyup",function(a){27===a.which&&d.trigger("escape.close.bb")}),b(a.container).append(d),d.modal({backdrop:a.backdrop?"static":!1,keyboard:!1,show:!1}),a.show&&d.modal("show"),d},p.setDefaults=function(){var a={};2===arguments.length?a[arguments[0]]=arguments[1]:a=arguments[0],b.extend(o,a)},p.hideAll=function(){return b(".bootbox").modal("hide"),p};var q={bg_BG:{OK:"Ок",CANCEL:"Отказ",CONFIRM:"Потвърждавам"},br:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Sim"},cs:{OK:"OK",CANCEL:"Zrušit",CONFIRM:"Potvrdit"},da:{OK:"OK",CANCEL:"Annuller",CONFIRM:"Accepter"},de:{OK:"OK",CANCEL:"Abbrechen",CONFIRM:"Akzeptieren"},el:{OK:"Εντάξει",CANCEL:"Ακύρωση",CONFIRM:"Επιβεβαίωση"},en:{OK:"OK",CANCEL:"Cancel",CONFIRM:"OK"},es:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Aceptar"},et:{OK:"OK",CANCEL:"Katkesta",CONFIRM:"OK"},fa:{OK:"قبول",CANCEL:"لغو",CONFIRM:"تایید"},fi:{OK:"OK",CANCEL:"Peruuta",CONFIRM:"OK"},fr:{OK:"OK",CANCEL:"Annuler",CONFIRM:"D'accord"},he:{OK:"אישור",CANCEL:"ביטול",CONFIRM:"אישור"},hu:{OK:"OK",CANCEL:"Mégsem",CONFIRM:"Megerősít"},hr:{OK:"OK",CANCEL:"Odustani",CONFIRM:"Potvrdi"},id:{OK:"OK",CANCEL:"Batal",CONFIRM:"OK"},it:{OK:"OK",CANCEL:"Annulla",CONFIRM:"Conferma"},ja:{OK:"OK",CANCEL:"キャンセル",CONFIRM:"確認"},lt:{OK:"Gerai",CANCEL:"Atšaukti",CONFIRM:"Patvirtinti"},lv:{OK:"Labi",CANCEL:"Atcelt",CONFIRM:"Apstiprināt"},nl:{OK:"OK",CANCEL:"Annuleren",CONFIRM:"Accepteren"},no:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},pl:{OK:"OK",CANCEL:"Anuluj",CONFIRM:"Potwierdź"},pt:{OK:"OK",CANCEL:"Cancelar",CONFIRM:"Confirmar"},ru:{OK:"OK",CANCEL:"Отмена",CONFIRM:"Применить"},sq:{OK:"OK",CANCEL:"Anulo",CONFIRM:"Prano"},sv:{OK:"OK",CANCEL:"Avbryt",CONFIRM:"OK"},th:{OK:"ตกลง",CANCEL:"ยกเลิก",CONFIRM:"ยืนยัน"},tr:{OK:"Tamam",CANCEL:"İptal",CONFIRM:"Onayla"},zh_CN:{OK:"OK",CANCEL:"取消",CONFIRM:"确认"},zh_TW:{OK:"OK",CANCEL:"取消",CONFIRM:"確認"}};return p.addLocale=function(a,c){return b.each(["OK","CANCEL","CONFIRM"],function(a,b){if(!c[b])throw new Error("Please supply a translation for '"+b+"'")}),q[a]={OK:c.OK,CANCEL:c.CANCEL,CONFIRM:c.CONFIRM},p},p.removeLocale=function(a){return delete q[a],p},p.setLocale=function(a){return p.setDefaults("locale",a)},p.init=function(c){return a(c||b)},p}); -------------------------------------------------------------------------------- /html/lib/bootstrap-4.0.0-dist/css/bootstrap-reboot.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0 (https://getbootstrap.com) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */ 8 | *, 9 | *::before, 10 | *::after { 11 | box-sizing: border-box; 12 | } 13 | 14 | html { 15 | font-family: sans-serif; 16 | line-height: 1.15; 17 | -webkit-text-size-adjust: 100%; 18 | -ms-text-size-adjust: 100%; 19 | -ms-overflow-style: scrollbar; 20 | -webkit-tap-highlight-color: transparent; 21 | } 22 | 23 | @-ms-viewport { 24 | width: device-width; 25 | } 26 | 27 | article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section { 28 | display: block; 29 | } 30 | 31 | body { 32 | margin: 0; 33 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 34 | font-size: 1rem; 35 | font-weight: 400; 36 | line-height: 1.5; 37 | color: #212529; 38 | text-align: left; 39 | background-color: #fff; 40 | } 41 | 42 | [tabindex="-1"]:focus { 43 | outline: 0 !important; 44 | } 45 | 46 | hr { 47 | box-sizing: content-box; 48 | height: 0; 49 | overflow: visible; 50 | } 51 | 52 | h1, h2, h3, h4, h5, h6 { 53 | margin-top: 0; 54 | margin-bottom: 0.5rem; 55 | } 56 | 57 | p { 58 | margin-top: 0; 59 | margin-bottom: 1rem; 60 | } 61 | 62 | abbr[title], 63 | abbr[data-original-title] { 64 | text-decoration: underline; 65 | -webkit-text-decoration: underline dotted; 66 | text-decoration: underline dotted; 67 | cursor: help; 68 | border-bottom: 0; 69 | } 70 | 71 | address { 72 | margin-bottom: 1rem; 73 | font-style: normal; 74 | line-height: inherit; 75 | } 76 | 77 | ol, 78 | ul, 79 | dl { 80 | margin-top: 0; 81 | margin-bottom: 1rem; 82 | } 83 | 84 | ol ol, 85 | ul ul, 86 | ol ul, 87 | ul ol { 88 | margin-bottom: 0; 89 | } 90 | 91 | dt { 92 | font-weight: 700; 93 | } 94 | 95 | dd { 96 | margin-bottom: .5rem; 97 | margin-left: 0; 98 | } 99 | 100 | blockquote { 101 | margin: 0 0 1rem; 102 | } 103 | 104 | dfn { 105 | font-style: italic; 106 | } 107 | 108 | b, 109 | strong { 110 | font-weight: bolder; 111 | } 112 | 113 | small { 114 | font-size: 80%; 115 | } 116 | 117 | sub, 118 | sup { 119 | position: relative; 120 | font-size: 75%; 121 | line-height: 0; 122 | vertical-align: baseline; 123 | } 124 | 125 | sub { 126 | bottom: -.25em; 127 | } 128 | 129 | sup { 130 | top: -.5em; 131 | } 132 | 133 | a { 134 | color: #007bff; 135 | text-decoration: none; 136 | background-color: transparent; 137 | -webkit-text-decoration-skip: objects; 138 | } 139 | 140 | a:hover { 141 | color: #0056b3; 142 | text-decoration: underline; 143 | } 144 | 145 | a:not([href]):not([tabindex]) { 146 | color: inherit; 147 | text-decoration: none; 148 | } 149 | 150 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus { 151 | color: inherit; 152 | text-decoration: none; 153 | } 154 | 155 | a:not([href]):not([tabindex]):focus { 156 | outline: 0; 157 | } 158 | 159 | pre, 160 | code, 161 | kbd, 162 | samp { 163 | font-family: monospace, monospace; 164 | font-size: 1em; 165 | } 166 | 167 | pre { 168 | margin-top: 0; 169 | margin-bottom: 1rem; 170 | overflow: auto; 171 | -ms-overflow-style: scrollbar; 172 | } 173 | 174 | figure { 175 | margin: 0 0 1rem; 176 | } 177 | 178 | img { 179 | vertical-align: middle; 180 | border-style: none; 181 | } 182 | 183 | svg:not(:root) { 184 | overflow: hidden; 185 | } 186 | 187 | table { 188 | border-collapse: collapse; 189 | } 190 | 191 | caption { 192 | padding-top: 0.75rem; 193 | padding-bottom: 0.75rem; 194 | color: #6c757d; 195 | text-align: left; 196 | caption-side: bottom; 197 | } 198 | 199 | th { 200 | text-align: inherit; 201 | } 202 | 203 | label { 204 | display: inline-block; 205 | margin-bottom: .5rem; 206 | } 207 | 208 | button { 209 | border-radius: 0; 210 | } 211 | 212 | button:focus { 213 | outline: 1px dotted; 214 | outline: 5px auto -webkit-focus-ring-color; 215 | } 216 | 217 | input, 218 | button, 219 | select, 220 | optgroup, 221 | textarea { 222 | margin: 0; 223 | font-family: inherit; 224 | font-size: inherit; 225 | line-height: inherit; 226 | } 227 | 228 | button, 229 | input { 230 | overflow: visible; 231 | } 232 | 233 | button, 234 | select { 235 | text-transform: none; 236 | } 237 | 238 | button, 239 | html [type="button"], 240 | [type="reset"], 241 | [type="submit"] { 242 | -webkit-appearance: button; 243 | } 244 | 245 | button::-moz-focus-inner, 246 | [type="button"]::-moz-focus-inner, 247 | [type="reset"]::-moz-focus-inner, 248 | [type="submit"]::-moz-focus-inner { 249 | padding: 0; 250 | border-style: none; 251 | } 252 | 253 | input[type="radio"], 254 | input[type="checkbox"] { 255 | box-sizing: border-box; 256 | padding: 0; 257 | } 258 | 259 | input[type="date"], 260 | input[type="time"], 261 | input[type="datetime-local"], 262 | input[type="month"] { 263 | -webkit-appearance: listbox; 264 | } 265 | 266 | textarea { 267 | overflow: auto; 268 | resize: vertical; 269 | } 270 | 271 | fieldset { 272 | min-width: 0; 273 | padding: 0; 274 | margin: 0; 275 | border: 0; 276 | } 277 | 278 | legend { 279 | display: block; 280 | width: 100%; 281 | max-width: 100%; 282 | padding: 0; 283 | margin-bottom: .5rem; 284 | font-size: 1.5rem; 285 | line-height: inherit; 286 | color: inherit; 287 | white-space: normal; 288 | } 289 | 290 | progress { 291 | vertical-align: baseline; 292 | } 293 | 294 | [type="number"]::-webkit-inner-spin-button, 295 | [type="number"]::-webkit-outer-spin-button { 296 | height: auto; 297 | } 298 | 299 | [type="search"] { 300 | outline-offset: -2px; 301 | -webkit-appearance: none; 302 | } 303 | 304 | [type="search"]::-webkit-search-cancel-button, 305 | [type="search"]::-webkit-search-decoration { 306 | -webkit-appearance: none; 307 | } 308 | 309 | ::-webkit-file-upload-button { 310 | font: inherit; 311 | -webkit-appearance: button; 312 | } 313 | 314 | output { 315 | display: inline-block; 316 | } 317 | 318 | summary { 319 | display: list-item; 320 | cursor: pointer; 321 | } 322 | 323 | template { 324 | display: none; 325 | } 326 | 327 | [hidden] { 328 | display: none !important; 329 | } 330 | /*# sourceMappingURL=bootstrap-reboot.css.map */ -------------------------------------------------------------------------------- /html/lib/bootstrap-4.0.0-dist/css/bootstrap-reboot.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Reboot v4.0.0 (https://getbootstrap.com) 3 | * Copyright 2011-2018 The Bootstrap Authors 4 | * Copyright 2011-2018 Twitter, Inc. 5 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 6 | * Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md) 7 | */*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important} 8 | /*# sourceMappingURL=bootstrap-reboot.min.css.map */ -------------------------------------------------------------------------------- /html/lib/jquery.base64.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jquery.base64.js 0.1 - https://github.com/yckart/jquery.base64.js 3 | * Makes Base64 en & -decoding simpler as it is. 4 | * 5 | * Based upon: https://gist.github.com/Yaffle/1284012 6 | * 7 | * Copyright (c) 2012 Yannick Albert (http://yckart.com) 8 | * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php). 9 | * 2013/02/10 10 | **/ 11 | ;(function($) { 12 | 13 | var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", 14 | a256 = '', 15 | r64 = [256], 16 | r256 = [256], 17 | i = 0; 18 | 19 | var UTF8 = { 20 | 21 | /** 22 | * Encode multi-byte Unicode string into utf-8 multiple single-byte characters 23 | * (BMP / basic multilingual plane only) 24 | * 25 | * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars 26 | * 27 | * @param {String} strUni Unicode string to be encoded as UTF-8 28 | * @returns {String} encoded string 29 | */ 30 | encode: function(strUni) { 31 | // use regular expressions & String.replace callback function for better efficiency 32 | // than procedural approaches 33 | var strUtf = strUni.replace(/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz 34 | function(c) { 35 | var cc = c.charCodeAt(0); 36 | return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f); 37 | }) 38 | .replace(/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz 39 | function(c) { 40 | var cc = c.charCodeAt(0); 41 | return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f); 42 | }); 43 | return strUtf; 44 | }, 45 | 46 | /** 47 | * Decode utf-8 encoded string back into multi-byte Unicode characters 48 | * 49 | * @param {String} strUtf UTF-8 string to be decoded back to Unicode 50 | * @returns {String} decoded string 51 | */ 52 | decode: function(strUtf) { 53 | // note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char! 54 | var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars 55 | function(c) { // (note parentheses for precence) 56 | var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f); 57 | return String.fromCharCode(cc); 58 | }) 59 | .replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars 60 | function(c) { // (note parentheses for precence) 61 | var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f; 62 | return String.fromCharCode(cc); 63 | }); 64 | return strUni; 65 | } 66 | }; 67 | 68 | while(i < 256) { 69 | var c = String.fromCharCode(i); 70 | a256 += c; 71 | r256[i] = i; 72 | r64[i] = b64.indexOf(c); 73 | ++i; 74 | } 75 | 76 | function code(s, discard, alpha, beta, w1, w2) { 77 | s = String(s); 78 | var buffer = 0, 79 | i = 0, 80 | length = s.length, 81 | result = '', 82 | bitsInBuffer = 0; 83 | 84 | while(i < length) { 85 | var c = s.charCodeAt(i); 86 | c = c < 256 ? alpha[c] : -1; 87 | 88 | buffer = (buffer << w1) + c; 89 | bitsInBuffer += w1; 90 | 91 | while(bitsInBuffer >= w2) { 92 | bitsInBuffer -= w2; 93 | var tmp = buffer >> bitsInBuffer; 94 | result += beta.charAt(tmp); 95 | buffer ^= tmp << bitsInBuffer; 96 | } 97 | ++i; 98 | } 99 | if(!discard && bitsInBuffer > 0) result += beta.charAt(buffer << (w2 - bitsInBuffer)); 100 | return result; 101 | } 102 | 103 | var Plugin = $.base64 = function(dir, input, encode) { 104 | return input ? Plugin[dir](input, encode) : dir ? null : this; 105 | }; 106 | 107 | Plugin.btoa = Plugin.encode = function(plain, utf8encode) { 108 | plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain; 109 | plain = code(plain, false, r256, b64, 8, 6); 110 | return plain + '===='.slice((plain.length % 4) || 4); 111 | }; 112 | 113 | Plugin.atob = Plugin.decode = function(coded, utf8decode) { 114 | coded = String(coded).split('='); 115 | var i = coded.length; 116 | do {--i; 117 | coded[i] = code(coded[i], true, r64, a256, 6, 8); 118 | } while (i > 0); 119 | coded = coded.join(''); 120 | return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded; 121 | }; 122 | }(jQuery)); -------------------------------------------------------------------------------- /html/lib/jquery.qrcode.min.js: -------------------------------------------------------------------------------- 1 | (function(r){r.fn.qrcode=function(h){var s;function u(a){this.mode=s;this.data=a}function o(a,c){this.typeNumber=a;this.errorCorrectLevel=c;this.modules=null;this.moduleCount=0;this.dataCache=null;this.dataList=[]}function q(a,c){if(void 0==a.length)throw Error(a.length+"/"+c);for(var d=0;da||this.moduleCount<=a||0>c||this.moduleCount<=c)throw Error(a+","+c);return this.modules[a][c]},getModuleCount:function(){return this.moduleCount},make:function(){if(1>this.typeNumber){for(var a=1,a=1;40>a;a++){for(var c=p.getRSBlocks(a,this.errorCorrectLevel),d=new t,b=0,e=0;e=d;d++)if(!(-1>=a+d||this.moduleCount<=a+d))for(var b=-1;7>=b;b++)-1>=c+b||this.moduleCount<=c+b||(this.modules[a+d][c+b]= 5 | 0<=d&&6>=d&&(0==b||6==b)||0<=b&&6>=b&&(0==d||6==d)||2<=d&&4>=d&&2<=b&&4>=b?!0:!1)},getBestMaskPattern:function(){for(var a=0,c=0,d=0;8>d;d++){this.makeImpl(!0,d);var b=j.getLostPoint(this);if(0==d||a>b)a=b,c=d}return c},createMovieClip:function(a,c,d){a=a.createEmptyMovieClip(c,d);this.make();for(c=0;c=f;f++)for(var i=-2;2>=i;i++)this.modules[b+f][e+i]=-2==f||2==f||-2==i||2==i||0==f&&0==i?!0:!1}},setupTypeNumber:function(a){for(var c= 7 | j.getBCHTypeNumber(this.typeNumber),d=0;18>d;d++){var b=!a&&1==(c>>d&1);this.modules[Math.floor(d/3)][d%3+this.moduleCount-8-3]=b}for(d=0;18>d;d++)b=!a&&1==(c>>d&1),this.modules[d%3+this.moduleCount-8-3][Math.floor(d/3)]=b},setupTypeInfo:function(a,c){for(var d=j.getBCHTypeInfo(this.errorCorrectLevel<<3|c),b=0;15>b;b++){var e=!a&&1==(d>>b&1);6>b?this.modules[b][8]=e:8>b?this.modules[b+1][8]=e:this.modules[this.moduleCount-15+b][8]=e}for(b=0;15>b;b++)e=!a&&1==(d>>b&1),8>b?this.modules[8][this.moduleCount- 8 | b-1]=e:9>b?this.modules[8][15-b-1+1]=e:this.modules[8][15-b-1]=e;this.modules[this.moduleCount-8][8]=!a},mapData:function(a,c){for(var d=-1,b=this.moduleCount-1,e=7,f=0,i=this.moduleCount-1;0g;g++)if(null==this.modules[b][i-g]){var n=!1;f>>e&1));j.getMask(c,b,i-g)&&(n=!n);this.modules[b][i-g]=n;e--; -1==e&&(f++,e=7)}b+=d;if(0>b||this.moduleCount<=b){b-=d;d=-d;break}}}};o.PAD0=236;o.PAD1=17;o.createData=function(a,c,d){for(var c=p.getRSBlocks(a, 9 | c),b=new t,e=0;e8*a)throw Error("code length overflow. ("+b.getLengthInBits()+">"+8*a+")");for(b.getLengthInBits()+4<=8*a&&b.put(0,4);0!=b.getLengthInBits()%8;)b.putBit(!1);for(;!(b.getLengthInBits()>=8*a);){b.put(o.PAD0,8);if(b.getLengthInBits()>=8*a)break;b.put(o.PAD1,8)}return o.createBytes(b,c)};o.createBytes=function(a,c){for(var d= 10 | 0,b=0,e=0,f=Array(c.length),i=Array(c.length),g=0;g>>=1;return c},getPatternPosition:function(a){return j.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,c,d){switch(a){case 0:return 0==(c+d)%2;case 1:return 0==c%2;case 2:return 0==d%3;case 3:return 0==(c+d)%3;case 4:return 0==(Math.floor(c/2)+Math.floor(d/3))%2;case 5:return 0==c*d%2+c*d%3;case 6:return 0==(c*d%2+c*d%3)%2;case 7:return 0==(c*d%3+(c+d)%2)%2;default:throw Error("bad maskPattern:"+ 14 | a);}},getErrorCorrectPolynomial:function(a){for(var c=new q([1],0),d=0;dc)switch(a){case 1:return 10;case 2:return 9;case s:return 8;case 8:return 8;default:throw Error("mode:"+a);}else if(27>c)switch(a){case 1:return 12;case 2:return 11;case s:return 16;case 8:return 10;default:throw Error("mode:"+a);}else if(41>c)switch(a){case 1:return 14;case 2:return 13;case s:return 16;case 8:return 12;default:throw Error("mode:"+ 15 | a);}else throw Error("type:"+c);},getLostPoint:function(a){for(var c=a.getModuleCount(),d=0,b=0;b=g;g++)if(!(0>b+g||c<=b+g))for(var h=-1;1>=h;h++)0>e+h||c<=e+h||0==g&&0==h||i==a.isDark(b+g,e+h)&&f++;5a)throw Error("glog("+a+")");return l.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;256<=a;)a-=255;return l.EXP_TABLE[a]},EXP_TABLE:Array(256), 17 | LOG_TABLE:Array(256)},m=0;8>m;m++)l.EXP_TABLE[m]=1<m;m++)l.EXP_TABLE[m]=l.EXP_TABLE[m-4]^l.EXP_TABLE[m-5]^l.EXP_TABLE[m-6]^l.EXP_TABLE[m-8];for(m=0;255>m;m++)l.LOG_TABLE[l.EXP_TABLE[m]]=m;q.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var c=Array(this.getLength()+a.getLength()-1),d=0;d 18 | this.getLength()-a.getLength())return this;for(var c=l.glog(this.get(0))-l.glog(a.get(0)),d=Array(this.getLength()),b=0;b>>7-a%8&1)},put:function(a,c){for(var d=0;d>>c-d-1&1))},getLengthInBits:function(){return this.length},putBit:function(a){var c=Math.floor(this.length/8);this.buffer.length<=c&&this.buffer.push(0);a&&(this.buffer[c]|=128>>>this.length%8);this.length++}};"string"===typeof h&&(h={text:h});h=r.extend({},{render:"canvas",width:256,height:256,typeNumber:-1, 26 | correctLevel:2,background:"#ffffff",foreground:"#000000"},h);return this.each(function(){var a;if("canvas"==h.render){a=new o(h.typeNumber,h.correctLevel);a.addData(h.text);a.make();var c=document.createElement("canvas");c.width=h.width;c.height=h.height;for(var d=c.getContext("2d"),b=h.width/a.getModuleCount(),e=h.height/a.getModuleCount(),f=0;f").css("width",h.width+"px").css("height",h.height+"px").css("border","0px").css("border-collapse","collapse").css("background-color",h.background);d=h.width/a.getModuleCount();b=h.height/a.getModuleCount();for(e=0;e").css("height",b+"px").appendTo(c);for(i=0;i").css("width", 28 | d+"px").css("background-color",a.isDark(e,i)?h.foreground:h.background).appendTo(f)}}a=c;jQuery(a).appendTo(this)})}})(jQuery); 29 | -------------------------------------------------------------------------------- /html/lib/prismjs-1.13.0/prism.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.13.0 2 | http://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 3 | /** 4 | * prism.js default theme for JavaScript, CSS and HTML 5 | * Based on dabblet (http://dabblet.com) 6 | * @author Lea Verou 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: black; 12 | background: none; 13 | text-shadow: 0 1px white; 14 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | } 31 | 32 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 33 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 34 | text-shadow: none; 35 | background: #b3d4fc; 36 | } 37 | 38 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 39 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 40 | text-shadow: none; 41 | background: #b3d4fc; 42 | } 43 | 44 | @media print { 45 | code[class*="language-"], 46 | pre[class*="language-"] { 47 | text-shadow: none; 48 | } 49 | } 50 | 51 | /* Code blocks */ 52 | pre[class*="language-"] { 53 | padding: 1em; 54 | margin: .5em 0; 55 | overflow: auto; 56 | } 57 | 58 | :not(pre) > code[class*="language-"], 59 | pre[class*="language-"] { 60 | background: #f5f2f0; 61 | } 62 | 63 | /* Inline code */ 64 | :not(pre) > code[class*="language-"] { 65 | padding: .1em; 66 | border-radius: .3em; 67 | white-space: normal; 68 | } 69 | 70 | .token.comment, 71 | .token.prolog, 72 | .token.doctype, 73 | .token.cdata { 74 | color: slategray; 75 | } 76 | 77 | .token.punctuation { 78 | color: #999; 79 | } 80 | 81 | .namespace { 82 | opacity: .7; 83 | } 84 | 85 | .token.property, 86 | .token.tag, 87 | .token.boolean, 88 | .token.number, 89 | .token.constant, 90 | .token.symbol, 91 | .token.deleted { 92 | color: #905; 93 | } 94 | 95 | .token.selector, 96 | .token.attr-name, 97 | .token.string, 98 | .token.char, 99 | .token.builtin, 100 | .token.inserted { 101 | color: #690; 102 | } 103 | 104 | .token.operator, 105 | .token.entity, 106 | .token.url, 107 | .language-css .token.string, 108 | .style .token.string { 109 | color: #9a6e3a; 110 | background: hsla(0, 0%, 100%, .5); 111 | } 112 | 113 | .token.atrule, 114 | .token.attr-value, 115 | .token.keyword { 116 | color: #07a; 117 | } 118 | 119 | .token.function, 120 | .token.class-name { 121 | color: #DD4A68; 122 | } 123 | 124 | .token.regex, 125 | .token.important, 126 | .token.variable { 127 | color: #e90; 128 | } 129 | 130 | .token.important, 131 | .token.bold { 132 | font-weight: bold; 133 | } 134 | .token.italic { 135 | font-style: italic; 136 | } 137 | 138 | .token.entity { 139 | cursor: help; 140 | } 141 | 142 | -------------------------------------------------------------------------------- /html/lib/prismjs-1.13.0/prism.js: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.13.0 2 | http://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 3 | var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(){var e=/\blang(?:uage)?-(\w+)\b/i,t=0,n=_self.Prism={manual:_self.Prism&&_self.Prism.manual,disableWorkerMessageHandler:_self.Prism&&_self.Prism.disableWorkerMessageHandler,util:{encode:function(e){return e instanceof r?new r(e.type,n.util.encode(e.content),e.alias):"Array"===n.util.type(e)?e.map(n.util.encode):e.replace(/&/g,"&").replace(/e.length)return;if(!(w instanceof s)){if(m&&b!=t.length-1){h.lastIndex=k;var _=h.exec(e);if(!_)break;for(var j=_.index+(d?_[1].length:0),P=_.index+_[0].length,A=b,x=k,O=t.length;O>A&&(P>x||!t[A].type&&!t[A-1].greedy);++A)x+=t[A].length,j>=x&&(++b,k=x);if(t[b]instanceof s)continue;I=A-b,w=e.slice(k,x),_.index-=k}else{h.lastIndex=0;var _=h.exec(w),I=1}if(_){d&&(p=_[1]?_[1].length:0);var j=_.index+p,_=_[0].slice(p),P=j+_.length,N=w.slice(0,j),S=w.slice(P),C=[b,I];N&&(++b,k+=N.length,C.push(N));var E=new s(u,f?n.tokenize(_,f):_,y,_,m);if(C.push(E),S&&C.push(S),Array.prototype.splice.apply(t,C),1!=I&&n.matchGrammar(e,t,r,b,k,!0,u),i)break}else if(i)break}}}}},tokenize:function(e,t){var r=[e],a=t.rest;if(a){for(var l in a)t[l]=a[l];delete t.rest}return n.matchGrammar(e,r,t,0,0,!1),r},hooks:{all:{},add:function(e,t){var r=n.hooks.all;r[e]=r[e]||[],r[e].push(t)},run:function(e,t){var r=n.hooks.all[e];if(r&&r.length)for(var a,l=0;a=r[l++];)a(t)}}},r=n.Token=function(e,t,n,r,a){this.type=e,this.content=t,this.alias=n,this.length=0|(r||"").length,this.greedy=!!a};if(r.stringify=function(e,t,a){if("string"==typeof e)return e;if("Array"===n.util.type(e))return e.map(function(n){return r.stringify(n,t,e)}).join("");var l={type:e.type,content:r.stringify(e.content,t,a),tag:"span",classes:["token",e.type],attributes:{},language:t,parent:a};if(e.alias){var i="Array"===n.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(l.classes,i)}n.hooks.run("wrap",l);var o=Object.keys(l.attributes).map(function(e){return e+'="'+(l.attributes[e]||"").replace(/"/g,""")+'"'}).join(" ");return"<"+l.tag+' class="'+l.classes.join(" ")+'"'+(o?" "+o:"")+">"+l.content+""},!_self.document)return _self.addEventListener?(n.disableWorkerMessageHandler||_self.addEventListener("message",function(e){var t=JSON.parse(e.data),r=t.language,a=t.code,l=t.immediateClose;_self.postMessage(n.highlight(a,n.languages[r],r)),l&&_self.close()},!1),_self.Prism):_self.Prism;var a=document.currentScript||[].slice.call(document.getElementsByTagName("script")).pop();return a&&(n.filename=a.src,n.manual||a.hasAttribute("data-manual")||("loading"!==document.readyState?window.requestAnimationFrame?window.requestAnimationFrame(n.highlightAll):window.setTimeout(n.highlightAll,16):document.addEventListener("DOMContentLoaded",n.highlightAll))),_self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); 4 | Prism.languages.markup={comment://,prolog:/<\?[\s\S]+?\?>/,doctype://i,cdata://i,tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/i,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"attr-value":{pattern:/=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+)/i,inside:{punctuation:[/^=/,{pattern:/(^|[^\\])["']/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.hooks.add("wrap",function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))}),Prism.languages.xml=Prism.languages.markup,Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup; 5 | Prism.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(?:;|(?=\s*\{))/i,inside:{rule:/@[\w-]+/}},url:/url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,selector:/[^{}\s][^{};]*?(?=\s*\{)/,string:{pattern:/("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},property:/[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,important:/\B!important\b/i,"function":/[-a-z0-9]+(?=\()/i,punctuation:/[(){};:]/},Prism.languages.css.atrule.inside.rest=Prism.languages.css,Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/()[\s\S]*?(?=<\/style>)/i,lookbehind:!0,inside:Prism.languages.css,alias:"language-css",greedy:!0}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag)); 6 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/[a-z0-9_]+(?=\()/i,number:/\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,punctuation:/[{}[\];(),.:]/}; 7 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,number:/\b(?:0[xX][\dA-Fa-f]+|0[bB][01]+|0[oO][0-7]+|NaN|Infinity)\b|(?:\b\d+\.?\d*|\B\.\d+)(?:[Ee][+-]?\d+)?/,"function":/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*\()/i,operator:/-[-=]?|\+[+=]?|!=?=?|<>?>?=?|=(?:==?|>)?|&[&=]?|\|[|=]?|\*\*?=?|\/=?|~|\^=?|%=?|\?|\.{3}/}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s])\s*)\/(\[[^\]\r\n]+]|\\.|[^\/\\\[\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=\s*(?:function\b|(?:\([^()]*\)|[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/i,alias:"function"},constant:/\b[A-Z][A-Z\d_]*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|[^\\`])*`/,greedy:!0,inside:{interpolation:{pattern:/\$\{[^}]+\}/,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/()[\s\S]*?(?=<\/script>)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript",greedy:!0}}),Prism.languages.js=Prism.languages.javascript; 8 | -------------------------------------------------------------------------------- /html/main.html.ori: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
Chrome Extension Template v1.0
20 | 21 |
A sample project for kickstarting your next Chrome browser extension.
22 |
23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /html/options.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
Chrome Extension Template v1.0
20 |
Configuration and Settings
21 |
22 |
23 | 24 |
25 | 31 |
32 |
33 |
34 | 35 |
36 |
37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /html/sendNas.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | NEBULAS 13 | 61 | 62 | 63 | 64 |
65 |
66 |
67 |
68 | 69 |
70 |
Your wallet file is imported.
71 | 72 |
73 | 74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 | 82 |
83 |
84 |
85 |
86 |
87 | 88 |
89 |
90 |
91 | 92 |
93 |
94 |
95 |
96 |
97 | 100 |
101 |
102 |
103 | 108 |
109 |
110 |
111 |
112 | 113 | 114 |
115 |
116 | High Risk 117 | 118 |
119 |
120 | 121 | 122 | 123 |
124 | 125 | 126 |
127 |
128 |
129 |
130 | 131 | 132 |
133 |
134 | 135 | 136 |
137 |
138 |
139 | 140 |
141 |
142 |
143 | 144 | 145 |
146 | 147 | 148 |
149 | 150 | ↓ 151 | 152 |
153 | 154 | 155 |
156 |
157 | 158 | 159 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 |
209 | 210 | 211 | -------------------------------------------------------------------------------- /html/sendOffline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 28 | NEBULAS 29 | 30 | 31 | 32 |
33 |
34 |
35 | 36 |
37 |
38 |

Step 1: Generate Information (Online Computer)

39 |
40 |
From Address
41 |
42 |
43 | 44 | 54 |
55 |
56 | 57 |
58 |
59 |

Step 2: Generate Transaction (Offline Computer)

60 |
61 |
62 | 63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 |
71 |
72 | 73 |
74 |
75 |
76 | 77 | 78 |
79 |
80 |
81 |
82 | 85 |
86 |
87 |
88 | 93 |
94 |
95 |
96 |
97 |
98 | 99 |
100 | 101 |
102 | 103 |
104 |
105 |
106 | 107 | 108 |
109 |
110 |
111 |
112 | 113 | 114 |
115 |
116 |
117 |
118 | 119 |
120 |

Step 3: Send / Publish Transaction (Online Computer)

121 |
122 |
123 | 124 | 125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 | 133 |
134 |
135 | 136 |
137 | 138 | ↓ 139 | 140 |
141 | 142 | 143 |
144 |
145 | 146 | 180 | 181 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 |
211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /html/server.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict'; 3 | 4 | var fs = require('fs'); 5 | var url = require('url'); 6 | var path = require('path'); 7 | var http = require('http'); 8 | var root = path.resolve(process.argv[2] || '.'); 9 | 10 | console.log('Static root dir: ' + root); 11 | 12 | var server = http.createServer(function (request, response) { 13 | var pathname = url.parse(request.url).pathname; 14 | 15 | if (pathname === '/') { 16 | pathname += 'index.html'; 17 | } 18 | 19 | var filepath = path.join(root, pathname); 20 | 21 | fs.stat(filepath, function (err, stats) { 22 | if (!err && stats.isFile()) { 23 | console.log('200 ' + request.url); 24 | response.writeHead(200); 25 | fs.createReadStream(filepath).pipe(response); 26 | } else { 27 | console.log('404 ' + request.url); 28 | response.writeHead(404); 29 | response.end('404 Not Found'); 30 | } 31 | }); 32 | }); 33 | 34 | server.listen(8080); 35 | console.log('nasWallet is running at http://127.0.0.1:8080/'); 36 | -------------------------------------------------------------------------------- /html/viewWalletInfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | NEBULAS 12 | 13 | 33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 | 44 | 45 |
46 |
47 | 48 | 49 |
50 |
51 | 55 | 56 |
57 |
58 | 59 | 60 |
61 | 62 | 63 |
64 |
65 |
66 |
67 |
68 | 69 |
70 |
71 | 75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 |
94 | 95 | -------------------------------------------------------------------------------- /html/welcome.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Notice 6 | 7 | 8 | 79 | 80 | 81 | 82 |
83 |
84 |
85 |

Release Notes of NasExtWallet

86 |
87 |

0.2.8

88 |

89 | Update mainnet nUSDT, NAS-NAX LP, NAS-nUSDT LP, NAX-nUSDT LP addresses. 90 |

91 |

0.2.7

92 |

93 | Fix token select display bug; update copyright; 94 |

95 | 96 |

0.2.6

97 |

98 | Add mainnet nUSDT, NAS-NAX LP, NAS-nUSDT LP, NAX-nUSDT LP addresses. 99 |

100 | 101 |

0.2.5

102 |

103 | Add testnet NAS-NAX LP, NAS-nUSDT LP, NAX-nUSDT LP addresses. 104 |

105 | 106 |

0.2.4

107 |

Fix transcation result NAS amount display.

108 | 109 |

0.2.3

110 |

Add new NAX, nUSDT(testnet) address.

111 | 112 |

0.2.2

113 |

Add NRC20 'approve' risk warning.

114 | 115 |

0.2.1

116 |

Modify the default gas price. Support NAX.

117 | 118 |

0.1.9

119 |

Modify the default gas price

120 | 121 |

0.1.8

122 |

123 | Fix the problem of large amount of NRC 20 transfer failure, 124 | optimize UI display of big number 125 |

126 | 127 |

0.1.7

128 |

Bug fixes.

129 | 130 |

0.1.6

131 |

132 | Support ATP: the wallet would show the balance of ATP, meanwhile, 133 | it can also support ATP transaction. 134 |

135 | 136 |

0.1.5

137 |

138 | Bug fixes: txhash page doesn't show-up after sending binary 139 | transaction with this extension. 140 |

141 | 142 |

0.1.4

143 |

144 | Add feedback message for posting serialNumber to server. 145 | If serialNumber is failed to be posted to server, you 146 | should not use queryPayInfo(serialNumber) to query 147 | transaction results, please use 148 | neb.api.getTransactionReceipt instead. 149 |

150 | 151 |

152 | After a transaction is send, there should be an feedback that if 153 | the serialNumber is posted to server successfully. Hence 154 | an attribute error is added to the return value for 155 | listener(serialNumber, result). the result is: 156 |

157 |
158 |             
159 |     {
160 |         "txhash": "ae41d5459fc8db5ffaee5416585e0874d2324d258258b8c59cda789a04934e1a",
161 |         "contract_address": "",
162 |         "error": "{\"timestamp\":1531231627789,\"status\":400,\"error\":\"Bad Request\",\"exception\":\"org.springframework.web.bind.MissingServletRequestParameterException\",\"message\":\"Required String parameter 'payId' is not present\",\"path\":\"/api/pay\"}"
163 |     }
164 |             
165 |             
166 |

167 | If the error is not empty, it means that the 168 | serialNumber is not posted to the server, then you should 169 | not use nebpay.queryPayInfo. 170 |

171 | 172 |

0.1.3

173 |

174 | Update get account address api: 175 | NasExtWallet.getUserAddress. Now you can easily get the 176 | user address. 177 |

178 |
179 |             
180 |         var userAddress;
181 |         NasExtWallet.getUserAddress(function(addr){
182 |             userAddress = addr;
183 |             console.log("user address is : " + addr)
184 |         })
185 |             
186 |             
187 |
188 | 189 |
190 | 191 |
192 |

Notice: How to debug with local html file

193 |
194 |

195 | Please note that chrome extension installed from Google Web Store 196 | cannot interact with local page files by default. 197 |

198 | 199 |

200 | If you need to test your local page files with this extension, 201 | please check the options "Allow access to file URLs" at extension 202 | setting, just copy this link to chrome address bar: 203 | chrome://extensions/?id=gehjkhmhclgnkkhpfamakecfgakkfkco 206 |

207 |
208 | 209 |
210 |
211 |
212 |
213 | 214 | 215 | -------------------------------------------------------------------------------- /images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/background.png -------------------------------------------------------------------------------- /images/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /images/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/glyphicons-halflings.png -------------------------------------------------------------------------------- /images/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/icon_128.png -------------------------------------------------------------------------------- /images/icon_19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/icon_19.png -------------------------------------------------------------------------------- /images/icon_38.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/icon_38.png -------------------------------------------------------------------------------- /images/logo-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/logo-b.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/nebulas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/images/nebulas.png -------------------------------------------------------------------------------- /inpage.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var webExtensionWallet = "for nebulas"; 4 | 5 | console.log("webExtensionWallet is defined:" + webExtensionWallet); 6 | 7 | var _NasExtWallet = function () { 8 | this.getUserAddressCallback ; 9 | 10 | this.getUserAddress = function(callback) { 11 | //console.log("********* get account ************") 12 | getUserAddressCallback = callback 13 | window.postMessage({ 14 | "target": "contentscript", 15 | "data":{}, 16 | "method": "getAccount", 17 | }, "*"); 18 | } 19 | 20 | // listen message from contentscript 21 | window.addEventListener('message', function(e) { 22 | // e.detail contains the transferred data (can 23 | if (e.data.src ==="content" && e.data.dst === "inpage" && !!e.data.data && !!e.data.data.account) { 24 | userAddrerss = e.data.data.account; 25 | if(typeof getUserAddressCallback === 'function'){ 26 | getUserAddressCallback(userAddrerss) 27 | } 28 | } 29 | }) 30 | } 31 | 32 | var NasExtWallet = new _NasExtWallet() 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NasExtWallet", 3 | "default_locale": "en", 4 | "description": "The extension for Nebulas Dapp", 5 | "version": "0.2.8.2", 6 | "manifest_version": 2, 7 | 8 | "icons": { 9 | "19": "images/icon_19.png", 10 | "38": "images/icon_38.png", 11 | "128": "images/icon_128.png" 12 | }, 13 | 14 | "permissions": [ 15 | "https://*.nebulas.io/", 16 | "activeTab", 17 | "*://*/", 18 | "storage" 19 | ], 20 | "background": { 21 | "scripts": [ 22 | "html/lib/nebulas.js", 23 | "html/js/1-localSave.js", 24 | "background.js" 25 | ], 26 | "persistent": false 27 | }, 28 | 29 | "browser_action": { 30 | "default_title": "Nebulas", 31 | "default_icon": { 32 | "19": "images/icon_19.png", 33 | "38": "images/icon_38.png" 34 | }, 35 | 36 | "default_popup": "html/sendNas.html" 37 | }, 38 | 39 | "content_scripts": [ 40 | { 41 | "all_frames": true, 42 | "js": ["contentscript.js"], 43 | "matches": ["file://*/*", "http://*/*", "https://*/*"], 44 | "run_at": "document_start" 45 | } 46 | ], 47 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", 48 | 49 | "web_accessible_resources": ["inpage.js"], 50 | 51 | "options_page": "html/options.html", 52 | "homepage_url": "https://github.com/nebulasio/WebExtensionWallet" 53 | } 54 | -------------------------------------------------------------------------------- /popup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | //this port communicate with background 4 | var port = chrome.runtime.connect({name: "popup"}); 5 | port.postMessage({src: "popup",dst:"background"}); 6 | port.onMessage.addListener(function(msg) { 7 | console.log("msg listened: " +JSON.stringify(msg)); 8 | if (!! msg.unapprovedTxs) { 9 | processTx(msg.unapprovedTxs); 10 | // var length = msg.unapprovedTxs.length 11 | // if(msg.unapprovedTxs.length > 0) { 12 | // var tx = msg.unapprovedTxs[length - 1].data 13 | // processTx(tx); 14 | // }else{ 15 | // console.log("no more unapprovedTxs") 16 | // $(".icon-address.to input").val(''); 17 | // $("#amount").val(''); 18 | // } 19 | 20 | } 21 | }); 22 | 23 | //just for debug, listen to port disconnect event 24 | port.onDisconnect.addListener(function(message) { 25 | console.log("Port disconnected: " + JSON.stringify(message)) 26 | }); 27 | 28 | //post message to background 29 | function messageToBackground(name,msg) { 30 | var data = {} 31 | data[name] = msg 32 | port.postMessage({ 33 | src: "popup",dst:"background", 34 | serialNumber: txTobeProcessed.serialNumber || "", 35 | data : data 36 | // data: { 37 | // name : msg 38 | // } 39 | }); 40 | } 41 | 42 | var txTobeProcessed = "" 43 | //var serialNumber 44 | 45 | function processTx(unapprovedTxs) { 46 | var length = unapprovedTxs.length; 47 | if(length > 0) { 48 | var tx = unapprovedTxs[length - 1].data; 49 | txTobeProcessed = tx 50 | 51 | console.log("to address: " + tx.to + ", mount: " + tx.value) 52 | $(".icon-address.to input").val(tx.to).trigger("input"); 53 | $("#amount").val(tx.value).trigger("input"); 54 | 55 | if(tx.gasLimit) $("#limit").val(tx.gasLimit).trigger("input"); 56 | if(tx.gasPrice) $("#price").val(tx.gasPrice).trigger("input"); 57 | 58 | if (length > 1) 59 | $("#rejectAll").show(); 60 | 61 | if (tx.serialNumber) //value send by nebPay is using unit of Wei 62 | $("#amount").val(Unit.fromBasic(tx.value, "nas")).trigger("input"); 63 | 64 | //serialNumber = tx.serialNumber || ""; 65 | if (!!tx.contract) { 66 | //$("#contract_div").css("display", "unset"); 67 | $("#contract_div").show(); 68 | $("#contract").val(JSON.stringify(tx.contract)); 69 | $(".icon-address.to input").attr("disabled","disabled") 70 | $("#amount").attr("disabled","disabled") 71 | if(tx.contract.function && tx.contract.function.toLowerCase() == 'approve'){ 72 | $(".risk-tips").css('display','initial'); 73 | $(".risk-text").show(); 74 | $("#generate").css('background','#ff4d4f'); 75 | } 76 | } 77 | else { 78 | //$("#contract_div").css("display", "none"); 79 | $("#contract_div").hide(); 80 | $("#contract").val("") 81 | } 82 | } else { 83 | console.log("no more unapprovedTxs") 84 | $(".icon-address.to input").val('').trigger("input"); 85 | $("#amount").val('').trigger("input"); 86 | $("#contract_div").hide(); 87 | $("#rejectAll").hide(); 88 | 89 | } 90 | 91 | } 92 | 93 | //load stored keyfle info from chrome.storage.local 94 | document.addEventListener("DOMContentLoaded", function() { 95 | console.log("popout page loaded...") 96 | changeNetwork() 97 | restoreAccount() 98 | $("#contract_div").css("display","none"); 99 | }); 100 | 101 | var AccAddress ; 102 | 103 | function getNextTx() { 104 | console.log("to get next unapprovedTxs") 105 | 106 | messageToBackground("getNextTx","true") 107 | 108 | } 109 | 110 | //tell background to check if the network is changed 111 | function changeNetwork() { 112 | var url = localSave.getItem("apiPrefix") 113 | //var chainId = localSave.getItem("chainId") 114 | console.log("to change network") 115 | 116 | messageToBackground("changeNetwork",url) 117 | } 118 | 119 | // 120 | function restoreAccount() { 121 | 122 | chrome.storage.local.get(['keyInfo'], function(result) { 123 | try { 124 | console.log('keyInfo Value is :' + JSON.stringify(result.keyInfo)); 125 | result = JSON.parse(result.keyInfo) 126 | } catch(e) { 127 | console.log(e); 128 | result = null; 129 | } 130 | if(!!result){ 131 | $(".container select-wallet-file").addClass("active1") 132 | console.log("unlockFile:") 133 | UnlockFile(result.fileJson, result.password) 134 | if(typeof(hideKeyFileInput) === "function") hideKeyFileInput() 135 | getNextTx() 136 | } 137 | 138 | }); 139 | } 140 | 141 | function UnlockFile( fileJson, password) { 142 | console.log("\tfileJson: " + JSON.stringify(fileJson) ) 143 | 144 | try { 145 | var address; 146 | var Account = require("nebulas").Account 147 | var account = Account.fromAddress(fileJson.address) 148 | 149 | account.fromKey(fileJson, password); 150 | address = account.getAddressString(); 151 | gAccount = account; 152 | AccAddress = address; 153 | 154 | console.log("AccAddress got...") 155 | port.postMessage({ 156 | src: "popup", 157 | dst:"background", 158 | data: { 159 | AccAddress : AccAddress 160 | } 161 | }); 162 | 163 | console.log("\tfileJson: " + JSON.stringify(gAccount) ) 164 | 165 | 166 | $(".icon-address.from input").val(address).trigger("input"); // gen icon from addr, needs trigger 'input' event if via set o.value 167 | $("#unlock").hide(); 168 | $("#send").show(); 169 | 170 | neb.api.getAccountState(address) 171 | .then(function (resp) { 172 | var nas = require("nebulas").Unit.fromBasic(resp.balance, "nas").toNumber(); 173 | console.log("\tbalance: " + nas +", nonce: " + resp.nonce) 174 | $("#balance").val(nas).trigger("input"); // add comma & unit from value, needs trigger 'input' event if via set o.value 175 | $("#nonce").val(parseInt(resp.nonce || 0) + 1); 176 | }) 177 | .catch(function (e) { 178 | // this catches e thrown by nebulas.js!neb 179 | 180 | bootbox.dialog({ 181 | backdrop: true, 182 | onEscape: true, 183 | message: i18n.apiErrorToText(e.message), 184 | size: "large", 185 | title: "Error" 186 | }); 187 | }); 188 | } catch (e) { 189 | // this catches e thrown by nebulas.js!account 190 | console.log("unlockFile error:" + JSON.stringify(e)) 191 | 192 | } 193 | } 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /resources/add-chrome-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/resources/add-chrome-extension.png -------------------------------------------------------------------------------- /resources/download-from-fithub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/resources/download-from-fithub.png -------------------------------------------------------------------------------- /resources/extension_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nebulasio/WebExtensionWallet/HEAD/resources/extension_options.png --------------------------------------------------------------------------------