| 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> |
|---|
| 2 | <html> |
|---|
| 3 | <head> |
|---|
| 4 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
|---|
| 5 | <meta name="copyright" content="© 2008-2009 NeoCat"> |
|---|
| 6 | <meta name="description" content="JavaScript-based Twitter Client"> |
|---|
| 7 | <meta name="viewport" content="width=280,user-scalable=no"> |
|---|
| 8 | <link rel="apple-touch-icon" href="icon.png"> |
|---|
| 9 | <link rel="shortcut icon" href="favicon.ico"> |
|---|
| 10 | <title>twicli</title> |
|---|
| 11 | <style type="text/css"><!-- |
|---|
| 12 | body { background-image: url(block_bg.png); background-attachment: fixed; margin: 1px; min-height: 500px; } |
|---|
| 13 | img { border: 0 none; } |
|---|
| 14 | hr { margin: 0; padding: 0; } |
|---|
| 15 | iframe { display: none; } |
|---|
| 16 | |
|---|
| 17 | #control { position: fixed; top: 0; left: 0; width: 100%; height: 53px; border-bottom: 1px solid black; background-color: white; z-index: 3; background-color: #eee; } |
|---|
| 18 | #loading { opacity: 0.5; filter: alpha(opacity=50); position: absolute; top: 6px; width: 100%; height: 20px; z-index: 4; text-align: center; } |
|---|
| 19 | #fst { position: absolute; left: 1px; top: 1px; width: 94%; height: 30px; font-size: small; overflow: hidden; } |
|---|
| 20 | #go { text-decoration: none; position: absolute; left: 95%; top: 1px; } |
|---|
| 21 | #rst { text-decoration: none; position: absolute; left: 95%; top: 16px; } |
|---|
| 22 | #menu { position: absolute; left: 0px; top: 33px; height: 20px; } |
|---|
| 23 | #menu a { display: inline-block; font-size: 13px; height: 18px; line-height: 18px; border: 1px solid black; border-bottom: 0 none; background-color: #aaa; color: #242; padding: 0 4px; margin: 0; text-decoration: none; font-family: sans-serif; -moz-border-radius: 5px 5px 0 0; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; margin-right: 2px; } |
|---|
| 24 | #menu a.sel { height: 20px; background-color: #ffe; color: #002; border-bottom-color: #fff; } |
|---|
| 25 | #menu a.new { background-color: #fcc; } |
|---|
| 26 | |
|---|
| 27 | #tw, #tw2 { position: absolute; left: 0px; top: 54px; width: 100%; font-size: small; } |
|---|
| 28 | #tw2 { background-color: #fec; display: none; min-height: 448px; } |
|---|
| 29 | #tw > div { border-bottom: 1px solid #777; } |
|---|
| 30 | #tw > div > div, #tw2c > div > div { padding: 1px; border-bottom: 1px solid #999; } |
|---|
| 31 | .dummy { border-bottom: 0; padding: 0; height: 0; clear: both; } |
|---|
| 32 | .uicon { float: left; width: 32px; height: 32px; } |
|---|
| 33 | .fav { float: right; } |
|---|
| 34 | .dir { color: #679; } |
|---|
| 35 | .status { text-decoration: none; color: black; } |
|---|
| 36 | .utils { white-space: nowrap; text-align: right } |
|---|
| 37 | .prop, .prop a { color: #999; font-size: x-small; } |
|---|
| 38 | .fromme { background-color: #cfc; } |
|---|
| 39 | .tome { background-color: #ccf; } |
|---|
| 40 | .emp { background-color: #fcc; } |
|---|
| 41 | .button { color: #f29; border: 1px solid #ddd; text-decoration: none; font-size: medium; -webkit-text-size-adjust:140%; } |
|---|
| 42 | .green { color: #195; } |
|---|
| 43 | .popup { padding: 0 4px; color: #888; } |
|---|
| 44 | .lock { position: relative; top: 2px; left: 0; } |
|---|
| 45 | .close { color: red; } |
|---|
| 46 | #get_old, #next { text-align: center; background-color: #999; color: #fec; cursor: pointer; } |
|---|
| 47 | #rep { display: none; background-color: #fee; position: absolute; width: 90%; left: 4%; top: 200px; border: 4px solid #666; z-index: 2; padding: 2px; font-size: small; } |
|---|
| 48 | #reps { margin-top: 5px; } |
|---|
| 49 | #popup { display: none; background-color: #eee; position: absolute; left: 0; top: 200px; border: 2px solid #666; z-index: 6; width: 180px; font-size: small; } |
|---|
| 50 | #popup a { display: block; background-color: #fff; color: black; text-decoration: none; padding: 3px; border-bottom: 1px solid #888; } |
|---|
| 51 | #popup a:hover { background-color: #33f; color: #fff; text-decoration: none; } |
|---|
| 52 | #popup a.row2 { background-color: #eee; } |
|---|
| 53 | #popup_hide { display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.2; filter: alpha(opacity=20); background-color: black; z-index: 5; } |
|---|
| 54 | #user_info { margin: 1px; border: 1px solid #888; } |
|---|
| 55 | #user_info td { font-size: small; } |
|---|
| 56 | |
|---|
| 57 | #counter-div { display: none; width: 3em; position: fixed; top: 33px; right: 6%; z-index: 9; opacity: 0.80; filter: alpha(opacity=80); } |
|---|
| 58 | #counter-p1 { border-top: solid 9px transparent; width: 0; height: 0; border-right: solid 5px #99f; float: left; margin-left: 8px; } |
|---|
| 59 | #counter-p2 { border-top: solid 9px transparent; width: 0; height: 0; border-left: solid 5px #99f; float: left; } |
|---|
| 60 | #counter { font-family: Georgia; font-size: 11pt; font-weight: bold; font-style: italic; background-color: #99f; color: white; height: 1.1em; text-align: center; padding: 3px 0; clear: left; } |
|---|
| 61 | |
|---|
| 62 | @media screen and (max-device-width: 480px) { |
|---|
| 63 | #control { padding-bottom: 5px; } |
|---|
| 64 | #menu { height: 24px; } |
|---|
| 65 | #menu a { padding: 1px 5px; height: 22px; line-height: 22px; } |
|---|
| 66 | #menu a.sel { height: 24px; } |
|---|
| 67 | #tw, #tw2 { margin-top: 5px; } |
|---|
| 68 | } |
|---|
| 69 | --></style> |
|---|
| 70 | <style id="fst_css"></style> |
|---|
| 71 | <script type="text/javascript"> |
|---|
| 72 | if (navigator.userAgent.indexOf("Opera") >= 0) |
|---|
| 73 | document.write("<style>#control { height: 58px; } #menu { top: 38px; } #tw, #tw2 { top: 58px; }</style>"); |
|---|
| 74 | function $(id) { return document.getElementById(id); } |
|---|
| 75 | function setFstHeight(h) { |
|---|
| 76 | if (no_resize_fst) return; |
|---|
| 77 | var exh = (navigator.userAgent.indexOf("Opera") >= 0) ? 1 : 0; |
|---|
| 78 | $("fst").style.height = h; |
|---|
| 79 | $("menu").style.top = $("counter-div").style.top = h+3+exh*5; |
|---|
| 80 | $("control").style.height = h+23+exh*5; |
|---|
| 81 | $("tw").style.top = $("tw2").style.top = h+24+exh*4; |
|---|
| 82 | } |
|---|
| 83 | // クロスドメインJavaScript呼び出し |
|---|
| 84 | function loadXDomainScript(url, ele) { |
|---|
| 85 | if (ele && ele.parentNode) |
|---|
| 86 | ele.parentNode.removeChild(ele); |
|---|
| 87 | ele = document.createElement("script"); |
|---|
| 88 | ele.src = url; |
|---|
| 89 | ele.type = "text/javascript"; |
|---|
| 90 | document.body.appendChild(ele); |
|---|
| 91 | return ele; |
|---|
| 92 | } |
|---|
| 93 | // クロスドメインJavaScript呼び出し(クラスバージョン) |
|---|
| 94 | function XDomainScript() { |
|---|
| 95 | this.cb_cnt = (new Date).getTime(); |
|---|
| 96 | } |
|---|
| 97 | XDomainScript.prototype = { |
|---|
| 98 | load: function(url, callback) { |
|---|
| 99 | var id = this.cb_cnt++; |
|---|
| 100 | var ele = document.createElement("script"); |
|---|
| 101 | ele.src = url + (url.indexOf('?') < 0 ? '?' : '&') + 'callback=xds.cb' + id; |
|---|
| 102 | ele.type = "text/javascript"; |
|---|
| 103 | this['cbe' + id] = ele; |
|---|
| 104 | this['cb' + id] = function(){ this.abort(id); callback.apply(this, arguments); }; |
|---|
| 105 | document.body.appendChild(ele); |
|---|
| 106 | return id; |
|---|
| 107 | }, |
|---|
| 108 | abort: function(id) { |
|---|
| 109 | var ele = this['cbe' + id]; |
|---|
| 110 | if (ele && ele.parentNode) ele.parentNode.removeChild(ele); |
|---|
| 111 | if (this['cb' + id]) delete this['cb' + id]; |
|---|
| 112 | if (this['cbe' + id]) delete this['cbe' + id]; |
|---|
| 113 | } |
|---|
| 114 | }; |
|---|
| 115 | var xds = new XDomainScript; |
|---|
| 116 | // 動的にフレームを生成してPOSTを投げる |
|---|
| 117 | var postQueue = []; |
|---|
| 118 | function enqueuePost(url, done, err) { |
|---|
| 119 | postQueue.push([url, done, err]); |
|---|
| 120 | if (postQueue.length > 1) // 複数リクエストを同時に投げないようキューイング |
|---|
| 121 | return; |
|---|
| 122 | postNext(); |
|---|
| 123 | } |
|---|
| 124 | function postNext() { |
|---|
| 125 | if (postQueue.length) { |
|---|
| 126 | postInIFrame(postQueue[0][0], postQueue[0][1], postQueue[0][2]); |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | var postSeq = 0; |
|---|
| 130 | function postInIFrame(url, done, err) { |
|---|
| 131 | var frm = document.createElement("form"); // POST用のフォームを生成 |
|---|
| 132 | frm.action = url; |
|---|
| 133 | frm.method = "POST"; |
|---|
| 134 | frm.target = "pfr" + seq; |
|---|
| 135 | document.body.appendChild(frm); |
|---|
| 136 | var pfr = document.createElement("iframe"); // formのtargetとなるiframeを生成 |
|---|
| 137 | pfr.name = "pfr" + seq; |
|---|
| 138 | pfr.src = "about:blank"; |
|---|
| 139 | pfr.style.display = "none"; |
|---|
| 140 | var errTimer = false; |
|---|
| 141 | if (err) { // 10秒で正常終了しなければエラーとみなす |
|---|
| 142 | errTimer = setTimeout(function(){ |
|---|
| 143 | err(); |
|---|
| 144 | frm.parentNode.removeChild(frm); |
|---|
| 145 | pfr.parentNode.removeChild(pfr); |
|---|
| 146 | postQueue.shift(); |
|---|
| 147 | postNext(); |
|---|
| 148 | }, 100000); |
|---|
| 149 | } |
|---|
| 150 | var cnt = 0; |
|---|
| 151 | var onload = pfr.onload = function(){ |
|---|
| 152 | if (cnt++ == 0) { |
|---|
| 153 | setTimeout(function(){frm.submit();}, 0); |
|---|
| 154 | } else { |
|---|
| 155 | clearTimeout(errTimer); |
|---|
| 156 | done(); |
|---|
| 157 | setTimeout(function(){ |
|---|
| 158 | frm.parentNode.removeChild(frm); |
|---|
| 159 | pfr.parentNode.removeChild(pfr); |
|---|
| 160 | postQueue.shift(); |
|---|
| 161 | postNext(); |
|---|
| 162 | }, 0); |
|---|
| 163 | } |
|---|
| 164 | }; |
|---|
| 165 | if ('v'=='\v') pfr.onreadystatechange = function(){ /* for IE */ |
|---|
| 166 | if (this.readyState == "complete") { |
|---|
| 167 | pfr.contentWindow.name = pfr.name; |
|---|
| 168 | onload(); |
|---|
| 169 | } |
|---|
| 170 | }; |
|---|
| 171 | document.body.appendChild(pfr); |
|---|
| 172 | } |
|---|
| 173 | // 要素の位置を取得 |
|---|
| 174 | function cumulativeOffset(ele) { |
|---|
| 175 | var top = 0, left = 0; |
|---|
| 176 | do { |
|---|
| 177 | top += ele.offsetTop || 0; |
|---|
| 178 | left += ele.offsetLeft || 0; |
|---|
| 179 | ele = ele.offsetParent; |
|---|
| 180 | } while (ele); |
|---|
| 181 | return [left, top]; |
|---|
| 182 | } |
|---|
| 183 | // スクロール |
|---|
| 184 | function getScrollY() { return window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; } |
|---|
| 185 | function scrollToY(y,y0,start) { |
|---|
| 186 | var t = (new Date).getTime(); |
|---|
| 187 | start = start || t; |
|---|
| 188 | y0 = y0 || getScrollY(); |
|---|
| 189 | if (start+500 <= t) |
|---|
| 190 | return scrollTo(0,y); |
|---|
| 191 | scrollTo(0, Math.ceil(y0 + (y-y0)*(1-Math.cos((t-start)/500*Math.PI))/2)); |
|---|
| 192 | setTimeout(function(){scrollToY(y, y0, start)}, 20); |
|---|
| 193 | } |
|---|
| 194 | // DOM Storage (or Cookie) |
|---|
| 195 | if (!window.localStorage) window.localStorage = window.globalStorage && window.globalStorage[location.hostname]; |
|---|
| 196 | function readCookie(key) { |
|---|
| 197 | if (window.localStorage && window.localStorage["twicli_"+key]) |
|---|
| 198 | return String(window.localStorage["twicli_"+key]); |
|---|
| 199 | key += "="; |
|---|
| 200 | var scookie = document.cookie + ";"; |
|---|
| 201 | start = scookie.indexOf(key); |
|---|
| 202 | if (start >= 0) { |
|---|
| 203 | var end = scookie.indexOf(";", start); |
|---|
| 204 | return unescape(scookie.substring(start + key.length, end)); |
|---|
| 205 | } |
|---|
| 206 | return null; |
|---|
| 207 | } |
|---|
| 208 | function writeCookie(key, val, days) { |
|---|
| 209 | if (window.localStorage) |
|---|
| 210 | window.localStorage["twicli_"+key] = val; |
|---|
| 211 | else { |
|---|
| 212 | var sday = new Date(); |
|---|
| 213 | sday.setTime(sday.getTime() + (days * 1000 * 60 * 60 * 24)); |
|---|
| 214 | document.cookie = key + "=" + escape(val) + ";expires=" + sday.toGMTString(); |
|---|
| 215 | } |
|---|
| 216 | } |
|---|
| 217 | // Array.mapの再実装(Opera用) |
|---|
| 218 | if (!Array.prototype.map) { |
|---|
| 219 | Array.prototype.map = function(fun) { |
|---|
| 220 | var len = this.length; |
|---|
| 221 | var res = new Array(len); |
|---|
| 222 | var thisp = arguments[1]; |
|---|
| 223 | for (var i = 0; i < len; i++) |
|---|
| 224 | if (i in this) |
|---|
| 225 | res[i] = fun.call(thisp, this[i], i, this); |
|---|
| 226 | return res; |
|---|
| 227 | }; |
|---|
| 228 | } |
|---|
| 229 | // user-defined CSS |
|---|
| 230 | var user_style = readCookie('user_style') || ""; |
|---|
| 231 | document.write('<style>' + user_style + '</style>'); |
|---|
| 232 | </script> |
|---|
| 233 | </head> |
|---|
| 234 | <body onLoad="init()"> |
|---|
| 235 | <div id="control"> |
|---|
| 236 | <script type="text/javascript">resetFrm = function(){}; update = function(){};</script> |
|---|
| 237 | <iframe name="tx" onload="resetFrm();update()"></iframe> |
|---|
| 238 | <!--発言フォーム--> |
|---|
| 239 | <form name="frm" action="http://twitter.com/statuses/update.xml" method="POST" target="tx"> |
|---|
| 240 | <textarea id="fst" name="status" onkeyup="updateCount(); if (!key_press_detected && this.value.indexOf('\n') >= 0) return press(1)" onkeypress="updateCount(); return press(event)" onfocus="updateCount();" onblur="$('counter-div').style.display='none';"></textarea> |
|---|
| 241 | <input type="hidden" name="source" value="twicli"> |
|---|
| 242 | <a id="go" href="javascript:void press(1)"><img src="go.png"></a> |
|---|
| 243 | <a id="rst" href="javascript:void resetFrm()"><img src="clr.png"></a> |
|---|
| 244 | <div id="loading"><img src="loading.gif"></div></form> |
|---|
| 245 | <!--メニュー--> |
|---|
| 246 | <div id="menu"><nobr id='menu2'><a id="TL" class="sel" href="javascript:void switchTL()">TL</a><a id="reply" href="javascript:void switchReply()">Re</a><a id="user" href="javascript:void switchUser()">user</a><a id="direct" href="javascript:void switchDirect()">D</a><a id="misc" href="javascript:void switchMisc()">+</a></nobr></div> |
|---|
| 247 | </div> |
|---|
| 248 | <!--メインタイムライン--> |
|---|
| 249 | <div id="tw"></div> |
|---|
| 250 | <!--TL以外のタブ--> |
|---|
| 251 | <div id="tw2"><div id="tw2h"></div><div id="tw2c"></div></div> |
|---|
| 252 | <!--返信--> |
|---|
| 253 | <div id="rep"><a href="javascript:closeRep()" class="close">[x]</a> |
|---|
| 254 | <a href="javascript:pickup2()" class="close">[⇔]</a><div id="reps"></div></div> |
|---|
| 255 | <!--ポップアップメニュー--> |
|---|
| 256 | <div id="popup" onClick="popup_hide()"> |
|---|
| 257 | <a id="popup_link_user" href="" target="twitter">Twitter / User</a> |
|---|
| 258 | <a id="popup_link_status" href="" target="twitter">Twitter / Status</a> |
|---|
| 259 | <a id="popup_status_delete" href="#" onClick="return deleteStatus()">Delete Status</a> |
|---|
| 260 | <a id="popup_status_retweet" href="#" onClick="return retweetStatus()" target="twitter">ReTweet</a> |
|---|
| 261 | </div> |
|---|
| 262 | <!--ポップアップメニュー非表示用--> |
|---|
| 263 | <div id="popup_hide" onClick="popup_hide();"></div> |
|---|
| 264 | <!--文字数カウンタ--> |
|---|
| 265 | <div id="counter-div"><div id="counter-p1"></div><div id="counter-p2"></div><div id="counter"></div></div> |
|---|
| 266 | <!-- --> |
|---|
| 267 | |
|---|
| 268 | <script type="text/javascript"> |
|---|
| 269 | var twitterURL = 'http://twitter.com/'; |
|---|
| 270 | var myname = null; // 自ユーザ名 |
|---|
| 271 | var myid = null; // 自ユーザID |
|---|
| 272 | var last_user = null; // user TLに表示するユーザ名 |
|---|
| 273 | // 設定値 |
|---|
| 274 | var cookieVer = parseInt(readCookie('ver')) || 0; |
|---|
| 275 | var updateInterval = (cookieVer>3) && parseInt(readCookie('update_interval')) || 60; |
|---|
| 276 | var pluginstr = (cookieVer>5) && readCookie('tw_plugins') || ' regexp.js\noutputz.js\nsearch.js\nsearch2.js\nfavotter.js\nfollowers.js'; |
|---|
| 277 | pluginstr = pluginstr.substr(1); |
|---|
| 278 | var plugins = new Array; |
|---|
| 279 | var nr_limit = parseInt(readCookie('limit')) || 500; // 表示する発言数の上限 |
|---|
| 280 | var max_count = (cookieVer>3) && parseInt(readCookie('max_count')) || 50; |
|---|
| 281 | var max_count_u = parseInt(readCookie('max_count_u')) || 50; |
|---|
| 282 | var no_since_id = parseInt(readCookie('no_since_id') || "0"); // since_idを使用しない |
|---|
| 283 | var no_counter = parseInt(readCookie('no_counter') || "0"); // 発言文字数カウンタを無効化 |
|---|
| 284 | var no_resize_fst = parseInt(readCookie('no_resize_fst') || "0"); // フィールドの自動リサイズを無効化 |
|---|
| 285 | var replies_in_tl = parseInt(readCookie('replies_in_tl') || "1"); // フォロー外からのReplyをTLに表示 |
|---|
| 286 | var footer = readCookie('footer') || ""; // フッタ文字列 |
|---|
| 287 | // TL管理用 |
|---|
| 288 | var nr_tw = 0; // 現在のTLの発言数 |
|---|
| 289 | var cur_page = 1; // 現在表示中のページ |
|---|
| 290 | var nr_page = 0; // 次に取得するページ |
|---|
| 291 | var get_next_func = getOldTL; // 次ページ取得関数 |
|---|
| 292 | var since_id = null; // TLの最終since_id |
|---|
| 293 | var since_id_reply = null; // Replyの最終since_id |
|---|
| 294 | var in_reply_to_user = null; // 発言の返信先 |
|---|
| 295 | // クロスドメイン通信関連 |
|---|
| 296 | var seq = (new Date).getTime(); |
|---|
| 297 | var users_log = []; |
|---|
| 298 | var users_xds = []; |
|---|
| 299 | var auth_ele = null; |
|---|
| 300 | var update_ele = null; |
|---|
| 301 | var update_ele2 = null; |
|---|
| 302 | var reply_ele = null; |
|---|
| 303 | var direct_ele1 = null; |
|---|
| 304 | var direct_ele2 = null; |
|---|
| 305 | var direct1 = null; |
|---|
| 306 | var direct2 = null; |
|---|
| 307 | var delayed_tw = null; |
|---|
| 308 | // UI関連 |
|---|
| 309 | var user_pick1 = null; // [⇔]で表示するユーザ名1 |
|---|
| 310 | var user_pick2 = null; // [⇔]で表示するユーザ名2 |
|---|
| 311 | var popup_user = null; // ポップアップメニューが選択されたユーザ名 |
|---|
| 312 | var popup_id = null; // ポップアップメニューが選択された発言ID |
|---|
| 313 | var fav_mode = 0; // fav表示中か |
|---|
| 314 | var rep_top = 0; // replyのオーバーレイ位置 |
|---|
| 315 | var popup_top = 0; // ポップアップメニューの表示位置 |
|---|
| 316 | var selected_menu = $("TL"); // 選択中のタブ |
|---|
| 317 | var update_timer = null; |
|---|
| 318 | var update_reply_counter = 0; |
|---|
| 319 | var key_press_detected = false; |
|---|
| 320 | |
|---|
| 321 | //ログイン・自ユーザ名受信 |
|---|
| 322 | function twAuth(a) { |
|---|
| 323 | if (a.error) return alert(a.error); |
|---|
| 324 | myname = last_user = a.screen_name; |
|---|
| 325 | myid = a.id; |
|---|
| 326 | $("user").innerHTML = last_user; |
|---|
| 327 | if (delayed_tw) |
|---|
| 328 | twShow(delayed_tw); // ログイン前に受信したTLを遅延評価 |
|---|
| 329 | } |
|---|
| 330 | function auth() { |
|---|
| 331 | auth_ele = loadXDomainScript(twitterURL + "account/verify_credentials.json?callback=twAuth", auth_ele); |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | // enterキーで発言 |
|---|
| 335 | function press(e) { |
|---|
| 336 | if (e != 1) key_press_detected = true; |
|---|
| 337 | if (e != 1 && e.keyCode != 13 && e.keyCode != 10 || e.ctrlKey || e.shiftKey) return true; |
|---|
| 338 | if (!key_press_detected) document.frm.status.value = document.frm.status.value.replace(/\n/g, ""); |
|---|
| 339 | if (document.frm.status.value == '') { // 空欄であればTimeline更新のみ |
|---|
| 340 | $("loading").style.display = "block"; |
|---|
| 341 | update(); |
|---|
| 342 | return false; |
|---|
| 343 | } |
|---|
| 344 | if (document.frm.status.value.indexOf("@"+in_reply_to_user) < 0) // @ユーザが含まれているときのみ返信先を指定 |
|---|
| 345 | setReplyId(false); |
|---|
| 346 | in_reply_to_user = ""; |
|---|
| 347 | callPlugins("post", document.frm.status.value); |
|---|
| 348 | document.frm.status.value += footer; |
|---|
| 349 | document.frm.status.select(); |
|---|
| 350 | document.frm.submit(); |
|---|
| 351 | return false; |
|---|
| 352 | } |
|---|
| 353 | // 発言文字数カウンタ表示・更新 |
|---|
| 354 | function updateCount() { |
|---|
| 355 | setFstHeight($("fst").value.length ? Math.max($("fst").scrollHeight+2,30) : 30); |
|---|
| 356 | if (no_counter) return; |
|---|
| 357 | $("counter-div").style.display = "block"; |
|---|
| 358 | $("counter").innerHTML = 140 - footer.length - $("fst").value.length; |
|---|
| 359 | } |
|---|
| 360 | // フォームの初期化 |
|---|
| 361 | resetFrm = function() { |
|---|
| 362 | document.frm.reset(); |
|---|
| 363 | setReplyId(false); |
|---|
| 364 | if ($("counter-div").style.display == "block") updateCount(); |
|---|
| 365 | setFstHeight(30); |
|---|
| 366 | } |
|---|
| 367 | // reply先の設定/解除 |
|---|
| 368 | function setReplyId(id) { |
|---|
| 369 | var repid = $('in_reply_to_status_id'); |
|---|
| 370 | if (repid && repid.parentNode) |
|---|
| 371 | repid.parentNode.removeChild(repid); |
|---|
| 372 | if (id) { |
|---|
| 373 | repid = document.createElement('input'); |
|---|
| 374 | repid.type = 'hidden'; |
|---|
| 375 | repid.id = repid.name = 'in_reply_to_status_id'; |
|---|
| 376 | repid.value = id; |
|---|
| 377 | document.frm.appendChild(repid); |
|---|
| 378 | } |
|---|
| 379 | } |
|---|
| 380 | // reply先を設定 |
|---|
| 381 | function replyTo(user, id) { |
|---|
| 382 | in_reply_to_user = user; |
|---|
| 383 | document.frm.status.value = (selected_menu.id == "direct" ? "d " : "@") + user + " " + document.frm.status.value; |
|---|
| 384 | setReplyId(id); |
|---|
| 385 | document.frm.status.select(); |
|---|
| 386 | } |
|---|
| 387 | // reply先を表示 |
|---|
| 388 | function dispReply(user, id, ele) { |
|---|
| 389 | user_pick1 = user; |
|---|
| 390 | var d = $((selected_menu.id == "TL" ? "tw" : "tw2c") + "-" + id); |
|---|
| 391 | if (!d || d.style.display == "none") { |
|---|
| 392 | rep_top = cumulativeOffset(ele)[1] + 20; |
|---|
| 393 | d = selected_menu.id != "TL" && $("tw" + "-" + id); |
|---|
| 394 | if (d) { |
|---|
| 395 | $('reps').innerHTML = d.innerHTML; |
|---|
| 396 | $('rep').style.display = "block"; |
|---|
| 397 | $('rep').style.top = rep_top; |
|---|
| 398 | user_pick2 = d.screen_name; |
|---|
| 399 | return; |
|---|
| 400 | } |
|---|
| 401 | $("loading").style.display = "block"; |
|---|
| 402 | reply_ele = loadXDomainScript(twitterURL + 'statuses/show/'+id+'.json?callback=dispReply2', reply_ele); |
|---|
| 403 | return; |
|---|
| 404 | } |
|---|
| 405 | closeRep(); |
|---|
| 406 | var top = cumulativeOffset(d)[1]; |
|---|
| 407 | var h = d.offsetHeight; |
|---|
| 408 | var sc_top = document.body.scrollTop || document.documentElement.scrollTop; |
|---|
| 409 | var win_h = window.innerHeight || document.documentElement.clientHeight; |
|---|
| 410 | if (top < sc_top) scrollToY(top); |
|---|
| 411 | if (sc_top+win_h < top+h) scrollToY(top+h-win_h); |
|---|
| 412 | d.className += ' emp'; |
|---|
| 413 | setTimeout(function(){d.className = d.className.replace(' emp','')}, 2000); |
|---|
| 414 | } |
|---|
| 415 | // reply先をoverlay表示 (Timelineに無い場合) |
|---|
| 416 | function dispReply2(tw) { |
|---|
| 417 | $("loading").style.display = "none"; |
|---|
| 418 | if (tw.error) return alert(tw.error); |
|---|
| 419 | $('reps').innerHTML = makeHTML(tw); |
|---|
| 420 | callPlugins("newMessageElement", $('reps'), tw); |
|---|
| 421 | $('rep').style.display = "block"; |
|---|
| 422 | $('rep').style.top = rep_top; |
|---|
| 423 | user_pick2 = tw.user.screen_name; |
|---|
| 424 | } |
|---|
| 425 | // replyのoverlay表示を閉じる |
|---|
| 426 | function closeRep() { |
|---|
| 427 | $('rep').style.display = 'none'; |
|---|
| 428 | } |
|---|
| 429 | // replyからユーザ間のタイムラインを取得 |
|---|
| 430 | function pickup2() { |
|---|
| 431 | switchUser(user_pick1 + "," + user_pick2); |
|---|
| 432 | } |
|---|
| 433 | // ポップアップメニューを表示 |
|---|
| 434 | function popup_menu(user, id, ele) { |
|---|
| 435 | popup_user = user; |
|---|
| 436 | popup_id = id; |
|---|
| 437 | callPlugins("popup", $('popup'), user, id, ele); |
|---|
| 438 | $('popup_link_user').href = twitterURL + user; |
|---|
| 439 | $('popup_link_status').href = twitterURL + user + '/statuses/' + id; |
|---|
| 440 | $('popup_status_delete').style.display = (user == myname ? "block" : "none"); |
|---|
| 441 | $('popup').style.display = "block"; |
|---|
| 442 | var pos = cumulativeOffset(ele); |
|---|
| 443 | $('popup').style.left = pos[0] < $('popup').offsetWidth - ele.offsetWidth ? 0 : pos[0] - $('popup').offsetWidth + ele.offsetWidth; |
|---|
| 444 | $('popup').style.top = popup_top = pos[1] + 20; |
|---|
| 445 | $('popup_hide').style.height = Math.max(document.body.scrollHeight, $("tw").offsetHeight+$("control").offsetHeight); |
|---|
| 446 | $('popup_hide').style.display = "block"; |
|---|
| 447 | } |
|---|
| 448 | // ポップアップメニューを非表示 |
|---|
| 449 | function popup_hide() { |
|---|
| 450 | $('popup').style.display = 'none'; |
|---|
| 451 | $('popup_hide').style.display = 'none'; |
|---|
| 452 | popup_user = popup_id = null; |
|---|
| 453 | } |
|---|
| 454 | // 発言のReTweet |
|---|
| 455 | function retweetStatus() { |
|---|
| 456 | if (!popup_id) return false; |
|---|
| 457 | if ($('lock-' + popup_id) && !confirm("This post is protected; Are you sure to RT?")) return false; |
|---|
| 458 | $('fst').value = "RT @"+popup_user+": " + $('text'+popup_id).innerHTML.replace(/<.*?>/g,''); |
|---|
| 459 | $('fst').focus(); $('fst').select(); |
|---|
| 460 | return false; |
|---|
| 461 | } |
|---|
| 462 | // 発言の削除 |
|---|
| 463 | function deleteStatus() { |
|---|
| 464 | if (!popup_id) return false; |
|---|
| 465 | if (!confirm("Are you sure to delete this message (@"+popup_user+" / "+popup_id+")?")) return false; |
|---|
| 466 | $("loading").style.display = "block"; |
|---|
| 467 | if ($("text" + popup_id)) $("text" + popup_id).style.textDecoration = "line-through"; |
|---|
| 468 | enqueuePost(twitterURL + 'status/destroy/' + popup_id + '.xml', |
|---|
| 469 | function(){$("loading").style.display = "none";}, function(){$("loading").style.display = "none";}); |
|---|
| 470 | return false; |
|---|
| 471 | } |
|---|
| 472 | // 最新タイムラインを取得 |
|---|
| 473 | update_inited = function() { |
|---|
| 474 | if (!myname) auth(); |
|---|
| 475 | if (delayed_tw) return; |
|---|
| 476 | callPlugins("update"); |
|---|
| 477 | update_ele = loadXDomainScript(twitterURL + 'statuses/friends_timeline.json?seq=' + (seq++) + |
|---|
| 478 | '&count=' + (since_id ? 200 : max_count) + |
|---|
| 479 | '&callback=twShow' + (!no_since_id && since_id ? '&since_id='+since_id : ''), update_ele); |
|---|
| 480 | resetUpdateTimer(); |
|---|
| 481 | } |
|---|
| 482 | function resetUpdateTimer() { |
|---|
| 483 | if (update_timer) clearInterval(update_timer); |
|---|
| 484 | update_timer = setInterval(update, updateInterval*1000); |
|---|
| 485 | } |
|---|
| 486 | // twitのHTML表現を生成 |
|---|
| 487 | function dateFmt(d) { |
|---|
| 488 | d = new Date(typeof(d)=='string' ? d.replace('+','GMT+') : d); |
|---|
| 489 | function d2(dig) { return (dig>9?"":"0") + dig } |
|---|
| 490 | return (d.getMonth()+1) + "/" + d.getDate() + " " + d.getHours() + ":" + d2(d.getMinutes()) + ":" + d2(d.getSeconds()); |
|---|
| 491 | } |
|---|
| 492 | function makeHTML(tw, no_name, pid) { |
|---|
| 493 | var un = tw.user.screen_name; |
|---|
| 494 | return /*fav*/ '<img class="fav" src="http://assets3.twitter.com/images/icon_star_'+(tw.favorited?'full':'empty')+'.gif" ' + |
|---|
| 495 | 'onClick="fav(this,' + tw.id + ')"' + (pid ? ' id="fav-'+pid+'-'+tw.id+'"' : '') + '>' + |
|---|
| 496 | (!no_name ? |
|---|
| 497 | //ユーザアイコン |
|---|
| 498 | (tw.user.url ? '<a target="twitter" href="'+tw.user.url+'">' : '') + |
|---|
| 499 | '<img class="uicon" src="' + tw.user.profile_image_url + '">' + (tw.user.url ? '</a>' : '') + |
|---|
| 500 | //名前 |
|---|
| 501 | '<a href="http://twitter.com/' + un + '" onClick="switchUser(\'' + un + '\');return false"><span class="uid">' + un + '</span>' + |
|---|
| 502 | /*プロフィールの名前*/ (tw.user.name!=un ? '<span class="uname">('+tw.user.name+'‬)</span>' : '') + '</a>' |
|---|
| 503 | : '') + |
|---|
| 504 | /* protected? */ (tw.user.protected ? '<img id="lock-' + tw.id + '" class="lock" src="http://assets0.twitter.com/images/icon_lock.gif">' : '') + |
|---|
| 505 | /*ダイレクトメッセージの方向*/ (tw.d_dir == 1 ? '<span class="dir">→</span> ' : tw.d_dir == 2 ? '<span class="dir">←</span> ' : '') + |
|---|
| 506 | //本文 (https〜をリンクに置換 + @を本家リンク+JavaScriptに置換) |
|---|
| 507 | " <span id=\"text" + tw.id + "\" class=\"status\">" + |
|---|
| 508 | tw.text.replace(/https?:\/\/[\w!#$%&'()*+,.\/:;=?@~-]+|@([\w-]+)/g, function(_,id){ |
|---|
| 509 | if(!id) return "<a target=\"twitter\" href=\""+_+"\">"+_+"</a>"; |
|---|
| 510 | return "<a href=\"http://twitter.com/"+id+"\" onClick=\"switchUser('"+id+"'); return false;\" >"+_+"</a>"; |
|---|
| 511 | }).replace(/\r?\n|\r/g, "<br>") + '</span>' + |
|---|
| 512 | //日付 |
|---|
| 513 | ' <span class="utils"><span class="prop"><a class="date" target="twitter" href="http://twitter.com/'+un+'/statuses/'+tw.id+'">' + dateFmt(tw.created_at) + '</a>' + |
|---|
| 514 | //クライアント |
|---|
| 515 | (tw.source ? '<span class="separator"> / </span><span class="source">' + tw.source.replace(/<a /,'<a target="twitter"') + '</span>' : '') + '</span>' + |
|---|
| 516 | //返信先を設定 |
|---|
| 517 | ' <a class="button green" href="javascript:replyTo(\'' + un + "'," + tw.id + ')">↩</a>' + |
|---|
| 518 | //返信元へのリンク |
|---|
| 519 | (tw.in_reply_to_status_id ? ' <a class="button" href="#" onClick="dispReply(\'' + un + '\',' + tw.in_reply_to_status_id + ',this); return false;">☞</a>' : '') + |
|---|
| 520 | //popupメニュー表示 |
|---|
| 521 | ' <a class="button popup" href="#" onClick="popup_menu(\'' + un + "'," + tw.id + ', this); return false;"><small><small>▼</small></small></a>' + |
|---|
| 522 | '</span><div class="dummy"></div>'; |
|---|
| 523 | } |
|---|
| 524 | // ユーザ情報のHTML表現を生成 |
|---|
| 525 | function makeUserInfoHTML(user) { |
|---|
| 526 | return '<table><tr><td><a target="twitter" href="http://twitter.com/account/profile_image/'+ |
|---|
| 527 | user.screen_name+'"><img align="left" src="' + user.profile_image_url + '"></a></td><td id="profile">' + |
|---|
| 528 | (user.protected ? '<img src="http://assets0.twitter.com/images/icon_lock.gif">' : '') + |
|---|
| 529 | '<b>' + user.screen_name + '</b> / <b>' + user.name + '</b><br>' + |
|---|
| 530 | (user.location ? '<b>Location</b>: ' + user.location + '<br>' : '') + |
|---|
| 531 | (user.url ? '<b>URL</b>: <a target="twitter" href="' + user.url + '">' + user.url + '</a><br>' : '') + |
|---|
| 532 | (user.description ? user.description : '') + |
|---|
| 533 | '<br><b>' + user.friends_count + '<small>following</small> / ' + |
|---|
| 534 | user.followers_count + '<small>followers</small>' + |
|---|
| 535 | '<br>' + user.statuses_count + '<small>updates</small> / ' + |
|---|
| 536 | user.favourites_count + '<small>favs</small></b>' + |
|---|
| 537 | '</td></tr></table><a target="twitter" href="http://twitter.com/' + user.screen_name + '">[Twitter]</a> '+ |
|---|
| 538 | '<a href="javascript:switchFav()">[fav]</a> '; |
|---|
| 539 | } |
|---|
| 540 | // 過去の発言取得ボタン(DOM)生成 |
|---|
| 541 | function nextButton(id, p) { |
|---|
| 542 | var ret = document.createElement('div'); |
|---|
| 543 | ret.id = id; |
|---|
| 544 | ret.onclick = function() { getNext(this); }; |
|---|
| 545 | ret.innerHTML = '▽' + (p ? '(' + p + ')' : ''); |
|---|
| 546 | return ret; |
|---|
| 547 | } |
|---|
| 548 | // favoriteの追加/削除 |
|---|
| 549 | function fav(img, id) { |
|---|
| 550 | if (img.src.indexOf('throbber') >= 0) return; |
|---|
| 551 | var f = img.src.indexOf('empty') >= 0; |
|---|
| 552 | setFavIcon(img, id, -1); |
|---|
| 553 | enqueuePost(twitterURL + 'favourings/' + (f ? 'create' : 'destroy') + '/' + id + '.xml', |
|---|
| 554 | function(){ setFavIcon(img, id, f) }, function(){ setFavIcon(img, id, !f) }); |
|---|
| 555 | } |
|---|
| 556 | // favアイコンの設定(f=0: 未fav, f=1:fav済, f=-1:通信中) |
|---|
| 557 | function setFavIcon(img, id, f) { |
|---|
| 558 | var img_tl = $('fav-tw-' + id); |
|---|
| 559 | var img_url = (f==-1) ? twitterURL + 'images/icon_throbber.gif' : |
|---|
| 560 | 'http://assets3.twitter.com/images/icon_star_' + (f ? 'full' : 'empty') + '.gif'; |
|---|
| 561 | img.src = img_url; |
|---|
| 562 | if (img_tl) img_tl.src = img_url; |
|---|
| 563 | callPlugins("fav", id, f, img, img_tl); |
|---|
| 564 | } |
|---|
| 565 | // followとremove |
|---|
| 566 | function follow(f) { |
|---|
| 567 | enqueuePost(twitterURL + 'friendships/' + (f ? 'create' : 'destroy') + '/' + last_user + '.xml', switchUser); |
|---|
| 568 | $("loading").style.display = "block"; |
|---|
| 569 | } |
|---|
| 570 | // ユーザ情報を表示 |
|---|
| 571 | function twUserInfo(user) { |
|---|
| 572 | if (user.error) return alert(user.error); |
|---|
| 573 | var elem = $('user_info'); |
|---|
| 574 | elem.innerHTML = makeUserInfoHTML(user); |
|---|
| 575 | callPlugins("newUserInfoElement", elem, user); |
|---|
| 576 | if (myname != user.screen_name) { |
|---|
| 577 | update_ele2 = loadXDomainScript(twitterURL + 'friendships/show.json?seq=' + (seq++) + |
|---|
| 578 | '&source_screen_name=' + myname + '&target_id=' + user.id + |
|---|
| 579 | '&callback=twRelation', update_ele2); |
|---|
| 580 | } |
|---|
| 581 | } |
|---|
| 582 | // ユーザ情報にフォロー関係を表示 |
|---|
| 583 | function twRelation(rel) { |
|---|
| 584 | var source = rel.relationship.source; |
|---|
| 585 | var elem = $("user_info"); |
|---|
| 586 | elem.innerHTML += '<input type="button" value="' + (source.following ? 'Remove ' : 'Follow ') + last_user + |
|---|
| 587 | '" onClick="follow('+!source.following+')">'; |
|---|
| 588 | if (source.followed_by) |
|---|
| 589 | $("profile").innerHTML += "<br><b>" + rel.relationship.target.screen_name + ' is following you!</b>'; |
|---|
| 590 | callPlugins("newUserRelationship", elem, rel); |
|---|
| 591 | } |
|---|
| 592 | // ダイレクトメッセージ一覧の受信 |
|---|
| 593 | function twDirect1(tw) { |
|---|
| 594 | if (tw.error) return alert(tw.error); |
|---|
| 595 | direct1 = tw; |
|---|
| 596 | if (direct2) |
|---|
| 597 | twDirectShow(); |
|---|
| 598 | } |
|---|
| 599 | function twDirect2(tw) { |
|---|
| 600 | if (tw.error) return alert(tw.error); |
|---|
| 601 | direct2 = tw; |
|---|
| 602 | if (direct1) |
|---|
| 603 | twDirectShow(); |
|---|
| 604 | } |
|---|
| 605 | function twDirectShow() { |
|---|
| 606 | var direct = direct1.concat(direct2).sort(function(a,b){return b.id - a.id}); |
|---|
| 607 | direct = direct.map(function(d){ |
|---|
| 608 | if (d.recipient_screen_name == myname) { |
|---|
| 609 | d.user = d.sender; |
|---|
| 610 | d.d_dir = 1; |
|---|
| 611 | } else { |
|---|
| 612 | d.user = d.recipient; |
|---|
| 613 | d.d_dir = 2; |
|---|
| 614 | } |
|---|
| 615 | return d; |
|---|
| 616 | }); |
|---|
| 617 | twShow2(direct); |
|---|
| 618 | direct1 = direct2 = false; |
|---|
| 619 | } |
|---|
| 620 | // API制限情報の受信 |
|---|
| 621 | function twLimit(lim) { |
|---|
| 622 | $("loading").style.display = "none"; |
|---|
| 623 | $("tw2c").innerHTML = "<b>Twitter API status:</b><br>" + |
|---|
| 624 | "hourly limit : " + lim.remaining_hits + " / " + lim.hourly_limit + "<br>" + |
|---|
| 625 | "reset at : " + dateFmt(lim.reset_time); |
|---|
| 626 | } |
|---|
| 627 | // 新着reply受信通知 |
|---|
| 628 | function noticeNewReply() { |
|---|
| 629 | if ($("reply").className.indexOf("new") < 0) |
|---|
| 630 | $("reply").className += " new"; |
|---|
| 631 | callPlugins("noticeNewReply"); |
|---|
| 632 | } |
|---|
| 633 | // 受信repliesを表示 |
|---|
| 634 | function twReplies(tw) { |
|---|
| 635 | if (tw.error) return alert(tw.error); |
|---|
| 636 | tw.reverse(); |
|---|
| 637 | for (var j in tw) callPlugins("gotNewReply", tw[j]); |
|---|
| 638 | tw.reverse(); |
|---|
| 639 | var nr = tw.length; |
|---|
| 640 | if (replies_in_tl) |
|---|
| 641 | nr = twShowToNode(tw, $("tw"), false, false, true); |
|---|
| 642 | if (nr > 0) noticeNewReply(); |
|---|
| 643 | if (tw.length > 0) since_id_reply = tw[0].id; |
|---|
| 644 | } |
|---|
| 645 | // 受信twitを表示 |
|---|
| 646 | function twShow(tw) { |
|---|
| 647 | if (tw.error) return alert(tw.error); |
|---|
| 648 | if (!myname) { |
|---|
| 649 | delayed_tw = tw; // 認証完了後まで評価を遅延 |
|---|
| 650 | return; |
|---|
| 651 | } |
|---|
| 652 | tw.reverse(); |
|---|
| 653 | for (var j in tw) callPlugins("gotNewMessage", tw[j]); |
|---|
| 654 | if(!since_id_reply) since_id_reply = tw[0].id; |
|---|
| 655 | tw.reverse(); |
|---|
| 656 | if (nr_page == 0) { |
|---|
| 657 | $("tw").appendChild(nextButton('get_old', 1)); |
|---|
| 658 | nr_page = 1; |
|---|
| 659 | } |
|---|
| 660 | twShowToNode(tw, $("tw"), false, false, true, true); |
|---|
| 661 | if (since_id_reply && update_reply_counter-- <= 0) { |
|---|
| 662 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/replies.json?seq=' + (seq++) + |
|---|
| 663 | '&count=' + (since_id ? 200 : max_count) + |
|---|
| 664 | '&callback=twReplies&since_id='+since_id_reply, |
|---|
| 665 | update_ele2); |
|---|
| 666 | update_reply_counter = 4; |
|---|
| 667 | } |
|---|
| 668 | callPlugins("noticeUpdate", tw); |
|---|
| 669 | } |
|---|
| 670 | function twOld(tw) { |
|---|
| 671 | if (tw.error) return alert(tw.error); |
|---|
| 672 | var tmp = $("tmp"); |
|---|
| 673 | if (tmp && tmp.parentNode) tmp.parentNode.removeChild(tmp); |
|---|
| 674 | twShowToNode(tw, $("tw"), false, true); |
|---|
| 675 | $("tw").appendChild(nextButton('get_old', nr_page)); |
|---|
| 676 | } |
|---|
| 677 | function twShow2(tw) { |
|---|
| 678 | if (tw.error) return alert(tw.error); |
|---|
| 679 | var tmp = $("tmp"); |
|---|
| 680 | if (tmp && tmp.parentNode) tmp.parentNode.removeChild(tmp); |
|---|
| 681 | var user_info = $("user_info"); |
|---|
| 682 | twShowToNode(tw, $("tw2c"), !!user_info && !fav_mode, cur_page > 1); |
|---|
| 683 | if (selected_menu.id == "reply" || selected_menu.id == "user" && last_user.indexOf(',') < 0) { |
|---|
| 684 | $("tw2c").appendChild(nextButton('next')); |
|---|
| 685 | get_next_func = getNextFuncCommon; |
|---|
| 686 | } |
|---|
| 687 | if (tw[0] && selected_menu.id == "user" && last_user.indexOf(',') < 0 && !fav_mode) |
|---|
| 688 | twUserInfo(tw[0].user); |
|---|
| 689 | } |
|---|
| 690 | function twShow3(tw) { |
|---|
| 691 | if (tw.error) return alert(tw.error); |
|---|
| 692 | users_log.push(tw); |
|---|
| 693 | if (users_log.length == last_user.split(',').length) { |
|---|
| 694 | var tws = []; |
|---|
| 695 | for (var i = 0; i < users_log.length; i++) |
|---|
| 696 | tws = tws.concat(users_log[i]); |
|---|
| 697 | tws = tws.sort(function(a,b){return b.id - a.id}); |
|---|
| 698 | twShow2(tws); |
|---|
| 699 | } |
|---|
| 700 | } |
|---|
| 701 | function twShowToNode(tw, twNode, no_name, after, animation, check_since) { |
|---|
| 702 | $('loading').style.display = 'none'; |
|---|
| 703 | var len = tw.length; |
|---|
| 704 | if (len == 0) return 0; |
|---|
| 705 | var pNode = document.createElement('div'); |
|---|
| 706 | var dummy = pNode.appendChild(document.createElement('div')); |
|---|
| 707 | var myname_r = new RegExp("@"+myname+"\\b","i"); |
|---|
| 708 | var nr_show = 0; |
|---|
| 709 | for (var i = len-1; i >= 0; i--) { |
|---|
| 710 | if ($(twNode.id + "-" + tw[i].id)) |
|---|
| 711 | continue; |
|---|
| 712 | if (tw[i].user) { |
|---|
| 713 | var s = document.createElement('div'); |
|---|
| 714 | s.id = twNode.id + "-" + tw[i].id; |
|---|
| 715 | s.innerHTML = makeHTML(tw[i], no_name, twNode.id); |
|---|
| 716 | s.screen_name = tw[i].user.screen_name; |
|---|
| 717 | if (tw[i].d_dir == 1 || tw[i].text.match(myname_r)) { |
|---|
| 718 | s.className = "tome"; |
|---|
| 719 | if (twNode.id == "tw") |
|---|
| 720 | noticeNewReply(); |
|---|
| 721 | } |
|---|
| 722 | if (tw[i].d_dir == 2 || tw[i].user.screen_name == myname) |
|---|
| 723 | s.className = "fromme"; |
|---|
| 724 | callPlugins("newMessageElement", s, tw[i], twNode.id); |
|---|
| 725 | pNode.insertBefore(s, pNode.childNodes[0]); |
|---|
| 726 | nr_show++; |
|---|
| 727 | } |
|---|
| 728 | } |
|---|
| 729 | pNode.removeChild(dummy); |
|---|
| 730 | if (pNode.childNodes.length == 0) return 0; |
|---|
| 731 | pNode.style.overflow = "hidden"; |
|---|
| 732 | var animation2 = animation && getScrollY() < 10; |
|---|
| 733 | var maxH; |
|---|
| 734 | var curY = getScrollY(); |
|---|
| 735 | if (animation2) { // get maxH |
|---|
| 736 | twNode.appendChild(pNode); |
|---|
| 737 | maxH = pNode.clientHeight; |
|---|
| 738 | twNode.removeChild(pNode); |
|---|
| 739 | pNode.style.minHeight = 0; |
|---|
| 740 | } |
|---|
| 741 | if (after || !twNode.childNodes[0]) |
|---|
| 742 | twNode.appendChild(pNode); |
|---|
| 743 | else |
|---|
| 744 | twNode.insertBefore(pNode, twNode.childNodes[0]); |
|---|
| 745 | if (animation2) |
|---|
| 746 | animate(pNode, maxH, (new Date).getTime()); |
|---|
| 747 | else if (animation) { |
|---|
| 748 | $('rep').style.top = (rep_top += pNode.clientHeight+1); |
|---|
| 749 | $('popup').style.top = (popup_top += pNode.clientHeight+1); |
|---|
| 750 | scrollTo(0, curY + pNode.clientHeight+1); |
|---|
| 751 | } |
|---|
| 752 | if (animation) { |
|---|
| 753 | nr_tw += nr_show; |
|---|
| 754 | while (nr_tw > nr_limit) { |
|---|
| 755 | var last_node = twNode.childNodes[twNode.childNodes.length-1]; |
|---|
| 756 | nr_tw -= last_node.childNodes.length; |
|---|
| 757 | twNode.removeChild(last_node); |
|---|
| 758 | } |
|---|
| 759 | } |
|---|
| 760 | for (var i = 0; check_since && i < len; i++) { |
|---|
| 761 | if (tw[i].user.screen_name != myname) { |
|---|
| 762 | since_id = tw[i].id; |
|---|
| 763 | break; |
|---|
| 764 | } |
|---|
| 765 | } |
|---|
| 766 | return nr_show; |
|---|
| 767 | } |
|---|
| 768 | // 新規twitの出現アニメーション処理 |
|---|
| 769 | function animate(elem, max, start) { |
|---|
| 770 | var t = (new Date).getTime(); |
|---|
| 771 | if (start+1000 <= t) |
|---|
| 772 | return elem.style.maxHeight = 'none'; |
|---|
| 773 | elem.style.maxHeight = Math.ceil(max*(1-Math.cos((t-start)/1000*Math.PI))/2); |
|---|
| 774 | setTimeout(function(){animate(elem, max, start)}, 20); |
|---|
| 775 | } |
|---|
| 776 | // 次ページ取得 |
|---|
| 777 | function getNext(ele) { |
|---|
| 778 | var tmp = document.createElement("div"); |
|---|
| 779 | tmp.id = "tmp"; |
|---|
| 780 | tmp.innerHTML = "<p></p>"; |
|---|
| 781 | ele.parentNode.appendChild(tmp); |
|---|
| 782 | ele.parentNode.removeChild(ele); |
|---|
| 783 | $("loading").style.display = "block"; |
|---|
| 784 | get_next_func(); |
|---|
| 785 | } |
|---|
| 786 | function getOldTL() { |
|---|
| 787 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/friends_timeline.json?seq=' + (seq++) + |
|---|
| 788 | '&count=' + max_count + '&page=' + (nr_page++) + '&id=' + last_user + |
|---|
| 789 | '&callback=twOld', update_ele2); |
|---|
| 790 | } |
|---|
| 791 | function getNextFuncCommon() { |
|---|
| 792 | if (selected_menu.id == "user" && !fav_mode) |
|---|
| 793 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/user_timeline.json?seq=' + (seq++) + |
|---|
| 794 | '&count=' + max_count_u + '&page=' + (++cur_page) + '&id=' + last_user + |
|---|
| 795 | '&suppress_response_codes=true&callback=twShow2', update_ele2); |
|---|
| 796 | else if (selected_menu.id == "user" && fav_mode) |
|---|
| 797 | update_ele2 = loadXDomainScript(twitterURL + 'favorites/' + last_user + '.json?seq=' + (seq++) + |
|---|
| 798 | '&page=' + (++cur_page) + '&callback=twShow2', update_ele2); |
|---|
| 799 | else if (selected_menu.id == "reply") |
|---|
| 800 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/replies.json?seq=' + (seq++) + |
|---|
| 801 | '&count=' + max_count_u + '&page=' + (++cur_page) + |
|---|
| 802 | '&callback=twShow2', update_ele2); |
|---|
| 803 | } |
|---|
| 804 | // タイムライン切り替え |
|---|
| 805 | function switchTo(id) { |
|---|
| 806 | selected_menu.className = ""; |
|---|
| 807 | selected_menu = $(id); |
|---|
| 808 | selected_menu.className = "sel"; |
|---|
| 809 | $("tw").style.display = id=="TL"?"block":"none"; |
|---|
| 810 | $("tw2h").innerHTML = ""; |
|---|
| 811 | $("tw2c").innerHTML = ""; |
|---|
| 812 | $("tw2").style.display = id!="TL"?"block":"none"; |
|---|
| 813 | $("rep").style.display = "none"; |
|---|
| 814 | scrollTo(0, 1); scrollTo(0, 0); |
|---|
| 815 | cur_page = 1; |
|---|
| 816 | fav_mode = 0; |
|---|
| 817 | } |
|---|
| 818 | function switchTL() { |
|---|
| 819 | get_next_func = getOldTL; |
|---|
| 820 | switchTo("TL"); |
|---|
| 821 | } |
|---|
| 822 | function switchReply() { |
|---|
| 823 | switchTo("reply"); |
|---|
| 824 | $("loading").style.display = "block"; |
|---|
| 825 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/replies.json?seq=' + (seq++) + |
|---|
| 826 | '&count=' + max_count_u + '&callback=twShow2', update_ele2); |
|---|
| 827 | } |
|---|
| 828 | function switchUser(user) { |
|---|
| 829 | if (!user) user = last_user; |
|---|
| 830 | last_user = user; |
|---|
| 831 | $("user").innerHTML = user; |
|---|
| 832 | switchTo("user"); |
|---|
| 833 | $("loading").style.display = "block"; |
|---|
| 834 | var users = user.split(','); |
|---|
| 835 | if (users.length == 1) { |
|---|
| 836 | $("tw2h").innerHTML = "<div id=\"user_info\"></div>"; |
|---|
| 837 | update_ele2 = loadXDomainScript(twitterURL + 'statuses/user_timeline.json?seq=' + (seq++) + |
|---|
| 838 | '&count=' + max_count_u + '&id=' + user + '&callback=twShow2', update_ele2); |
|---|
| 839 | } else { |
|---|
| 840 | users_log = []; |
|---|
| 841 | for (var i = 0; i < users_xds.length; i++) |
|---|
| 842 | xds.abort(users_xds[i]); |
|---|
| 843 | users_xds = users.map(function(u) { |
|---|
| 844 | xds.load(twitterURL + 'statuses/user_timeline.json?id=' + u + |
|---|
| 845 | '&suppress_response_codes=true&count=' + max_count_u, twShow3); |
|---|
| 846 | }); |
|---|
| 847 | } |
|---|
| 848 | } |
|---|
| 849 | function switchFav() { |
|---|
| 850 | $("loading").style.display = "block"; |
|---|
| 851 | cur_page = 1; |
|---|
| 852 | fav_mode = 1; |
|---|
| 853 | $("tw2c").innerHTML = ""; |
|---|
| 854 | update_ele2 = loadXDomainScript(twitterURL + 'favorites/' + last_user + '.json?seq=' + (seq++) + |
|---|
| 855 | '&callback=twShow2', update_ele2); |
|---|
| 856 | } |
|---|
| 857 | function switchDirect() { |
|---|
| 858 | switchTo("direct"); |
|---|
| 859 | $("loading").style.display = "block"; |
|---|
| 860 | direct_ele1 = loadXDomainScript(twitterURL + 'direct_messages.json?seq=' + (seq++) + |
|---|
| 861 | '&callback=twDirect1', direct_ele1); |
|---|
| 862 | direct_ele2 = loadXDomainScript(twitterURL + 'direct_messages/sent.json?seq=' + (seq++) + |
|---|
| 863 | '&callback=twDirect2', direct_ele2); |
|---|
| 864 | } |
|---|
| 865 | function switchMisc() { |
|---|
| 866 | switchTo("misc"); |
|---|
| 867 | $("tw2h").innerHTML = '<p><a target="twitter" href="index.html"><b>twicli</b></a> : browser-base Twitter client<br><small>Copyright © 2008-2009 NeoCat</small></p><hr>' + |
|---|
| 868 | '<p><form onSubmit="switchUser($(\'user_id\').value); return false;">'+ |
|---|
| 869 | 'show user info : @<input type="text" size="15" id="user_id" value="' + myname + '"><input type="image" src="go.png"></form></p><hr>' + |
|---|
| 870 | '<p><a href="javascript:togglePreps()">▼<b>Preferences</b></a>' + |
|---|
| 871 | '<form id="preps" onSubmit="setPreps(this); return false;" style="display: none;">' + |
|---|
| 872 | 'max #msgs in TL: <input name="limit" size="5" value="' + nr_limit + '"><br>' + |
|---|
| 873 | '#msgs in TL on update (max=200): <input name="maxc" size="3" value="' + max_count + '"><br>' + |
|---|
| 874 | '#msgs in user on update (max=200): <input name="maxu" size="3" value="' + max_count_u + '"><br>' + |
|---|
| 875 | 'update interval: <input name="interval" size="3" value="' + updateInterval + '"> sec<br>' + |
|---|
| 876 | '<input type="checkbox" name="since_check"' + (no_since_id?"":" checked") + '>since_id check<br>' + |
|---|
| 877 | '<input type="checkbox" name="replies_in_tl"' + (replies_in_tl?" checked":"") + '>show not-following replies in TL<br>' + |
|---|
| 878 | '<input type="checkbox" name="counter"' + (no_counter?"":" checked") + '>POST length counter<br>' + |
|---|
| 879 | '<input type="checkbox" name="resize_fst"' + (no_resize_fst?"":" checked") + '>Auto-resize field<br>' + |
|---|
| 880 | 'Footer: <input name="footer" size="10" value="' + footer + '"><br>' + |
|---|
| 881 | 'Plugins:<br><textarea cols="30" rows="4" name="list">' + pluginstr + '</textarea><br>' + |
|---|
| 882 | 'user stylesheet:<br><textarea cols="30" rows="4" name="user_style">' + user_style + '</textarea><br>' + |
|---|
| 883 | '<input type="submit" value="Save"></form></p><hr>'; |
|---|
| 884 | callPlugins("miscTab", $("tw2h")); |
|---|
| 885 | $("loading").style.display = "block"; |
|---|
| 886 | update_ele2 = loadXDomainScript(twitterURL + 'account/rate_limit_status.json?seq=' + (seq++) + |
|---|
| 887 | '&id=' + myname + '&callback=twLimit', update_ele2); |
|---|
| 888 | } |
|---|
| 889 | function togglePreps() { |
|---|
| 890 | $('preps').style.display = $('preps').style.display == 'block' ? 'none' : 'block'; |
|---|
| 891 | } |
|---|
| 892 | function setPreps(frm) { |
|---|
| 893 | nr_limit = frm.limit.value; |
|---|
| 894 | max_count = frm.maxc.value; |
|---|
| 895 | max_count_u = frm.maxu.value; |
|---|
| 896 | updateInterval = frm.interval.value; |
|---|
| 897 | no_since_id = !frm.since_check.checked; |
|---|
| 898 | no_counter = !frm.counter.checked; |
|---|
| 899 | no_resize_fst = !frm.resize_fst.checked; |
|---|
| 900 | replies_in_tl = frm.replies_in_tl.checked; |
|---|
| 901 | footer = new String(frm.footer.value); |
|---|
| 902 | resetUpdateTimer(); |
|---|
| 903 | writeCookie('ver', 6, 3652); |
|---|
| 904 | writeCookie('limit', nr_limit, 3652); |
|---|
| 905 | writeCookie('max_count', max_count, 3652); |
|---|
| 906 | writeCookie('max_count_u', max_count_u, 3652); |
|---|
| 907 | writeCookie('update_interval', updateInterval, 3652); |
|---|
| 908 | writeCookie('no_since_id', no_since_id?1:0, 3652); |
|---|
| 909 | writeCookie('no_counter', no_counter?1:0, 3652); |
|---|
| 910 | writeCookie('no_resize_fst', no_resize_fst?1:0, 3652); |
|---|
| 911 | writeCookie('replies_in_tl', replies_in_tl?1:0, 3652); |
|---|
| 912 | writeCookie('footer', footer, 3652); |
|---|
| 913 | writeCookie('tw_plugins', new String(" " + frm.list.value), 3652); |
|---|
| 914 | writeCookie('user_style', new String(frm.user_style.value), 3652); |
|---|
| 915 | callPlugins('savePrefs', frm); |
|---|
| 916 | alert("Your settings are saved. Please reload to apply plugins and CSS."); |
|---|
| 917 | } |
|---|
| 918 | // 初期化 |
|---|
| 919 | function init() { |
|---|
| 920 | setTimeout(function(){scrollTo(0, 1)}, 0); |
|---|
| 921 | // 初回アップデート |
|---|
| 922 | update = update_inited; // 初期化前にupdateが発生するのを防止 |
|---|
| 923 | setTimeout(function(){update()}, 0); |
|---|
| 924 | } |
|---|
| 925 | // プラグイン |
|---|
| 926 | function registerPlugin(obj) { |
|---|
| 927 | plugins.push(obj); |
|---|
| 928 | } |
|---|
| 929 | function callPlugins(name) { |
|---|
| 930 | var args = [].slice.apply(arguments); |
|---|
| 931 | args.shift(); |
|---|
| 932 | for (var i in plugins) |
|---|
| 933 | if (typeof plugins[i][name] == "function") |
|---|
| 934 | plugins[i][name].apply(plugins[i], args); |
|---|
| 935 | } |
|---|
| 936 | if (pluginstr) { |
|---|
| 937 | var st = '<scr'+'ipt type="text/javascript" src="'; |
|---|
| 938 | var ed = '"></scr'+'ipt>'; |
|---|
| 939 | document.write(st + pluginstr.split("\n").join(ed+st) + ed); |
|---|
| 940 | } |
|---|
| 941 | // ホイールの回転でスクロール (スクロール不可のウィンドウ・フレーム内で有効) |
|---|
| 942 | function wheel(event) { |
|---|
| 943 | var delta = 0; |
|---|
| 944 | if (!event) event = window.event; |
|---|
| 945 | if (event.wheelDelta) { |
|---|
| 946 | delta = event.wheelDelta; |
|---|
| 947 | } else if (event.detail) |
|---|
| 948 | delta = -event.detail; |
|---|
| 949 | if (navigator.userAgent.indexOf("Gecko/") >= 0) |
|---|
| 950 | delta *= 10; |
|---|
| 951 | if (navigator.userAgent.indexOf("AppleWebKit/") >= 0) |
|---|
| 952 | delta /= 10; |
|---|
| 953 | if (delta) |
|---|
| 954 | scrollBy(0, -delta); |
|---|
| 955 | if (event.preventDefault) |
|---|
| 956 | event.preventDefault(); |
|---|
| 957 | event.returnValue = false; |
|---|
| 958 | } |
|---|
| 959 | if (window.addEventListener) window.addEventListener('DOMMouseScroll', wheel, false); |
|---|
| 960 | window.onmousewheel = document.onmousewheel = wheel; |
|---|
| 961 | </script> |
|---|
| 962 | </body> |
|---|
| 963 | </html> |
|---|