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