root/websites/twicli/twicli.html @ 36024

Revision 36024, 44.1 kB (checked in by NeoCat, 3 years ago)

fix get_old on #msg=200

  • Property svn:mime-type set to text/html; charset=UTF-8
Line 
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="&copy; 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"><!--
12body { background-image: url(block_bg.png); background-attachment: fixed; margin: 1px; min-height: 500px; color: black; }
13img { border: 0 none; }
14hr { margin: 0; padding: 0; }
15hr.spacer { margin: 6px 0 }
16iframe { display: none; }
17form { 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">
78function $(id) { return document.getElementById(id); }
79function 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// 文字参照をデコード
88function charRef(s) {
89        var ele = document.createElement("div");
90        ele.innerHTML = s;
91        return ele.firstChild.nodeValue;
92}
93// クロスドメインJavaScript呼び出し
94function 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呼び出し(クラスバージョン)
104function XDomainScript() {
105        this.cb_cnt = (new Date).getTime();
106}
107XDomainScript.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};
125var xds = new XDomainScript;
126// 動的にフレームを生成してPOSTを投げる
127var postQueue = [];
128function enqueuePost(url, done, err) {
129        postQueue.push([url, done, err]);
130        if (postQueue.length > 1) // 複数リクエストを同時に投げないようキューイング
131                return;
132        postNext();
133}
134function postNext() {
135        if (postQueue.length) {
136                postInIFrame(postQueue[0][0], postQueue[0][1], postQueue[0][2]);
137        }
138}
139var postSeq = 0;
140function 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// 要素の位置を取得
184function 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// スクロール
194if (navigator.userAgent.indexOf('iPhone') >= 0)
195        window.scrollBy = function(x,y) { scrollTo(x+window.pageXOffset,y+window.pageYOffset) };
196function getScrollY() { return window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; }
197function 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)
209if (!window.localStorage) window.localStorage = window.globalStorage && window.globalStorage[location.hostname];
210function 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}
222function 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用)
232if (!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の再実装
244Array.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
252var user_style = readCookie('user_style') || "";
253document.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">
292var twitterURL = 'http://twitter.com/';
293var twitterAPI = 'http://api.twitter.com/1/';
294var myname = null;              // 自ユーザ名
295var myid = null;                // 自ユーザID
296var last_user = null;   // user TLに表示するユーザ名
297// 設定値
298var cookieVer = parseInt(readCookie('ver')) || 0;
299var updateInterval = (cookieVer>3) && parseInt(readCookie('update_interval')) || 60;
300var 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';
301pluginstr = pluginstr.substr(1);
302var plugins = new Array;
303var nr_limit = parseInt(readCookie('limit')) || 500;                            // 表示する発言数の上限
304var max_count = (cookieVer>3) && parseInt(readCookie('max_count')) || 50;
305var max_count_u = parseInt(readCookie('max_count_u')) || 50;
306var no_since_id = parseInt(readCookie('no_since_id') || "0");           // since_idを使用しない
307var no_counter = parseInt(readCookie('no_counter') || "0");                     // 発言文字数カウンタを無効化
308var no_resize_fst = parseInt(readCookie('no_resize_fst') || "0");       // フィールドの自動リサイズを無効化
309var replies_in_tl = parseInt(readCookie('replies_in_tl') || "1");       // フォロー外からのReplyをTLに表示
310var footer = readCookie('footer') || "";                                                        // フッタ文字列
311var decr_enter = parseInt(readCookie('decr_enter') || "0");                     // Shift/Ctrl+Enterで投稿
312// TL管理用
313var nr_tw = 0;                                  // 現在のTLの発言数
314var cur_page = 1;                               // 現在表示中のページ
315var nr_page = 0;        // 次に取得するページ
316var get_next_func = getOldTL;   // 次ページ取得関数
317var since_id = null;                    // TLの最終since_id
318var since_id_reply = null;              // Replyの最終since_id
319var in_reply_to_user = null;    // 発言の返信先
320var tl_oldest_id = null;                // TLの最も古いid
321var last_replies = [];                  // 受信した返信
322// クロスドメイン通信関連
323var seq = (new Date).getTime();
324var users_log = [];
325var users_xds = [];
326var auth_ele = null;
327var update_ele = null;
328var update_ele2 = null;
329var reply_ele = null;
330var direct_ele1 = null;
331var direct_ele2 = null;
332var direct1 = null;
333var direct2 = null;
334// UI関連
335var user_pick1 = null;                  // [⇔]で表示するユーザ名1
336var user_pick2 = null;                  // [⇔]で表示するユーザ名2
337var popup_user = null;                  // ポップアップメニューが選択されたユーザ名
338var popup_id = null;                    // ポップアップメニューが選択された発言ID
339var popup_ele = null;                   // ポップアップメニューが選択された発言ノード
340var fav_mode = 0;                               // fav表示中か
341var rep_top = 0;                                // replyのオーバーレイ位置
342var popup_top = 0;                              // ポップアップメニューの表示位置
343var selected_menu = $("TL");    // 選択中のタブ
344var update_timer = null;
345var update_reply_counter = 0;
346var update_direct_counter = 0;
347var key_press_detected = false;
348var last_post = null;
349var last_in_reply_to_user = null;
350var last_direct_id = null;
351
352//ログイン・自ユーザ名受信
353function 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}
360function auth() {
361        auth_ele = loadXDomainScript(twitterAPI + "account/verify_credentials.json?callback=twAuth&seq="+(seq++), auth_ele);
362}
363
364// enterキーで発言, "r"入力で再投稿, 空欄でTL更新
365function 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// 発言文字数カウンタ表示・更新
396function 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// フォームの初期化
403resetFrm = function() {
404        document.frm.reset();
405        setReplyId(false);
406        if ($("counter-div").style.display == "block") updateCount();
407        setFstHeight(30);
408}
409// reply先の設定/解除
410function 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先を設定
423function 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先を表示
430function 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に無い場合)
458function 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表示を閉じる
468function closeRep() {
469        $('rep').style.display = 'none';
470}
471// replyからユーザ間のタイムラインを取得
472function pickup2() {
473        switchUser(user_pick1 + "," + user_pick2);
474}
475// ポップアップメニューを表示
476function 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// ポップアップメニューを非表示
494function popup_hide() {
495        $('popup').style.display = 'none';
496        $('popup_hide').style.display = 'none';
497        popup_user = popup_id = popup_ele = null;
498}
499// 発言のReTweet
500function 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付きで引用
513function 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// 発言の削除
521function 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// 最新タイムラインを取得
531update_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}
539function resetUpdateTimer() {
540        if (update_timer) clearInterval(update_timer);
541        update_timer = setInterval(update, updateInterval*1000);
542}
543// twitのHTML表現を生成
544function 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}
549function 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}
561function 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                '&nbsp;&nbsp;&nbsp;<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表現を生成
595function 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)生成
611function 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の追加/削除
619function 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:通信中)
627function 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
636function follow(f) {
637        enqueuePost(twitterAPI + 'friendships/' + (f ? 'create' : 'destroy') + '/' + last_user + '.xml', switchUser);
638        $("loading").style.display = "block";
639}
640// ユーザ情報を表示
641function 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// ユーザ情報にフォロー関係を表示
653function 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// ダイレクトメッセージ一覧の受信
663function twDirect1(tw) {
664        if (tw.error) return alert(tw.error);
665        direct1 = tw;
666        if (direct2)
667                twDirectShow();
668}
669function twDirect2(tw) {
670        if (tw.error) return alert(tw.error);
671        direct2 = tw;
672        if (direct1)
673                twDirectShow();
674}
675function 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}
690function 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制限情報の受信
697function 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受信通知
704function 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の重複排除・要素数制限
712function 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を表示
723function 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を表示
740function 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}
773function 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}
780function 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}
793function 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}
804function 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の出現アニメーション処理
891function 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// 次ページ取得
899function 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}
908function getOldTL() {
909        update_ele2 = loadXDomainScript(twitterAPI + 'statuses/home_timeline.json?seq=' + (seq++) +
910                                '&count=200&page=' + (nr_page++) +
911                                '&callback=twOld', update_ele2);
912}
913function 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// タイムライン切り替え
927function 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}
940function switchTL() {
941        get_next_func = getOldTL;
942        switchTo("TL");
943}
944function 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}
955function 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}
976function 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}
984function 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}
992function 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 &copy; 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}
1017function togglePreps() {
1018        $('preps').style.display = $('preps').style.display == 'block' ? 'none' : 'block';
1019}
1020function 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// 初期化
1049function init() {
1050        setTimeout(function(){scrollTo(0, 1)}, 0);
1051        // 初回アップデート
1052        update = update_inited; // 初期化前にupdateが発生するのを防止
1053        callPlugins("init");
1054        setTimeout(auth, 0);
1055}
1056// プラグイン
1057function registerPlugin(obj) {
1058        plugins.push(obj);
1059}
1060function 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}
1067if (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// ホイールの回転でスクロール (スクロール不可のウィンドウ・フレーム内で有効)
1073function 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}
1090if (window.addEventListener) window.addEventListener('DOMMouseScroll', wheel, false);
1091window.onmousewheel = document.onmousewheel = wheel;
1092</script>
1093</body>
1094</html>
Note: See TracBrowser for help on using the browser.