cryptochat
https://yuzunoha.github.io/cryptochat/
(CryptoChat.sol)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
pragma solidity ^0.4.23; contract CryptoChat { struct Post { uint time; address addr; string text; } Post[] public posts; event Write(uint _time, address _address, string _text); function getPostsLength() public view returns(uint) { return posts.length; } function getTime(uint _id) public view returns(uint) { if(posts.length <= _id){ return 0; } return posts[_id].time; } function getAddr(uint _id) public view returns(address) { if(posts.length <= _id){ return address(0); } return posts[_id].addr; } function getText(uint _id) public view returns(string) { if(posts.length <= _id){ return ""; } return posts[_id].text; } function set(string _text) public { posts.push(Post( now, // uint time msg.sender, // address addr _text // string text )); emit Write(now, msg.sender, _text); } } |
(index.html)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>CryptoChat</title> <link rel="stylesheet" type="text/css" href="css.css"> </head> <body> <h2>CryptoChat(ropsten)</h2> <a href="https://github.com/Yuzunoha/cryptochat">https://github.com/Yuzunoha/cryptochat</a> <p id="message"></p> <input id="value_set" type="text"> <a href="#" class="square_btn" onclick="set();return false;">書き込み</a> <a href="#" class="square_btn" onclick="update();return false;">更新</a> <br> <br> <p id="wallet_data"></p> <table class="bordered"> <thead> <tr> <th>#</th> <th>text</th> <th>address</th> <th>date(local)</th> <th>timestamp(blockchain)</th> </tr> </thead> <tbody id="tbody"> </tbody> </table> <script src="./const.js"></script> <script type="text/javascript"> // global start var message = document.getElementById('message'); if (typeof web3 === 'undefined') { // メタマスクがない message.innerHTML += '<font color="red">Please install metamask</font><br>'; } else { // メタマスクがある web3.eth.getAccounts((err, accs) => { if (0 === accs.length) { message.innerHTML += '<font color="red">Please login to your MetaMask!</font><br>'; } if ('3' !== web3.currentProvider.publicConfigStore._state.networkVersion) { message.innerHTML += '<font color="red">Please connect the Ropsten Test Network.</font><br>'; } }); } // コントラクト var contract = web3.eth.contract(JSON.parse(ABI)).at(CONTRACT_ADDR); //イベント監視 contract.Write().watch(function (error, result) { // イベントキャッチのタイミングで自動更新 update(); }); // global end // 更新(F5) new Promise((resolve) => { window.web3.eth.getAccounts((err, accounts) => { resolve(accounts); }); }).then((accounts) => { update(); }); function update() { var s = ""; var promises = []; var len; new Promise((resolve) => { contract.getPostsLength((e, r) => { len = r.toNumber(); resolve(len); }); }).then((len) => { const getPromise = (i, attr) => { return new Promise((resolve) => { switch (attr) { case "text": contract.getText(i, (e, r) => { var key = 'text' + i; var value = r; resolve({ [key]: value }); }); break; case "addr": contract.getAddr(i, (e, r) => { var key = 'addr' + i; var value = r; resolve({ [key]: value }); }); break; case "time": contract.getTime(i, (e, r) => { var key = 'time' + i; var value = r.toString(); resolve({ [key]: value }); }); break; } }); }; for (var i = 0; i < len; i++) { promises.push(getPromise(i, "text")); promises.push(getPromise(i, "addr")); promises.push(getPromise(i, "time")); } Promise.all(promises).then((results) => { var posts = []; for (var result of results) { for (var key of Object.keys(result)) { var value = result[key]; posts[key] = value; } } for (var i = 0; i < len; i++) { s += "<tr>"; s += "<td>"; s += i; s += "</td>"; s += "<td>"; s += posts["text" + i]; s += "</td>"; s += "<td>"; s += posts["addr" + i]; s += "</td>"; s += "<td>"; s += unixTime2ymd(posts["time" + i]); s += "</td>"; s += "<td>"; s += posts["time" + i]; s += "</td>"; s += "</tr>"; } var tbody = document.getElementById("tbody"); tbody.innerHTML = s; }); }); } function set() { var value_set = document.getElementById("value_set").value; // ガード if (value_set === "") { alert("何か書いて"); return; } // 書き込み contract.set(value_set, function (err, value) { // console.log(); }); } function unixTime2ymd(intTime) { // var d = new Date( intTime ); var d = new Date(intTime * 1000); var year = d.getFullYear(); var month = d.getMonth() + 1; var day = d.getDate(); var hour = ('0' + d.getHours()).slice(-2); var min = ('0' + d.getMinutes()).slice(-2); var sec = ('0' + d.getSeconds()).slice(-2); return (year + '-' + month + '-' + day + ' ' + hour + ':' + min + ':' + sec); } </script> </body> </html> |
(css.css)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
@charset "UTF-8"; .square_btn{ display: inline-block; padding: 0.5em 1em; text-decoration: none; color: #FFF; background-image: -webkit-linear-gradient(#6795fd 0%, #67ceff 100%); background-image: linear-gradient(#6795fd 0%, #67ceff 100%); transition: .4s; } .square_btn:hover{ background-image: -webkit-linear-gradient(#6795fd 0%, #67ceff 70%); background-image: linear-gradient(#6795fd 0%, #67ceff 70%); } /* =================================================================== CSS information File Name : default.css Author : MIYA Style Info : ブラウザスタイルのリセットと基本設定 =================================================================== */ /* ----------------------- Browser Default Initialization */ html { overflow-y: scroll; } body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, textarea, p, blockquote, th, td { margin: 0; padding: 0; } address, caption, cite, code, dfn, em, strong, th, var { font-style: normal; } table { border-collapse: collapse; border-spacing: 0; } caption, th { text-align: left; } q:before ,q:after { content: ''; } object, embed { vertical-align: top; } hr, legend { display: none; } h1, h2, h3, h4, h5, h6 { font-size: 100%; } img, abbr, acronym, fieldset { border: 0; } li { list-style-type: none; } p, dd, blockquote { text-align: justify; text-justify: inter-ideograph; } /* ----------------------- Basic Style */ /* ------------ Font Style */ body { font-family: verdana,"ヒラギノ角ゴ Pro W3","Hiragino Kaku Gothic Pro",Osaka,"MS Pゴシック","MS PGothic",Sans-Serif; color: #333; font-size: 75%; line-height: 150%; } html>/**/body { font-size: 12px; } * + html body { font-family: "メイリオ","Meiryo"; } /* =================================================================== CSS information File Name : contents.css Author : MIYA Style Info : コンテンツ内のスタイル =================================================================== */ div.main { width: 580px; } h3 { font-size: 133.3%; margin-bottom: 5px; } /* サンプルtableの共通設定 ----------------------------------------------------------- */ table { border-collapse: collapse; border-spacing: 0; width: 100%; margin-bottom: 30px; } th, td { padding: 10px 20px; color: #1D5C79; } /* サンプル4 ----------------------------------------------------------- */ .sample4 .odd { background: #E5F2F8; } |
(const.js)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
var CONTRACT_ADDR = "0x83ac400371a0d0e258ee4cb6217b84f4a05cfe37"; var ABI = `[ { "constant": false, "inputs": [ { "name": "_text", "type": "string" } ], "name": "set", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "_time", "type": "uint256" }, { "indexed": false, "name": "_address", "type": "address" }, { "indexed": false, "name": "_text", "type": "string" } ], "name": "Write", "type": "event" }, { "constant": true, "inputs": [ { "name": "_id", "type": "uint256" } ], "name": "getAddr", "outputs": [ { "name": "", "type": "address" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [], "name": "getPostsLength", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "_id", "type": "uint256" } ], "name": "getText", "outputs": [ { "name": "", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "_id", "type": "uint256" } ], "name": "getTime", "outputs": [ { "name": "", "type": "uint256" } ], "payable": false, "stateMutability": "view", "type": "function" }, { "constant": true, "inputs": [ { "name": "", "type": "uint256" } ], "name": "posts", "outputs": [ { "name": "time", "type": "uint256" }, { "name": "addr", "type": "address" }, { "name": "text", "type": "string" } ], "payable": false, "stateMutability": "view", "type": "function" } ]`; |