root/websites/twicli/twicli.html @ 36354

Revision 36354, 44.8 kB (checked in by NeoCat, 3 years ago)

confirm removal of followers / widen twitpic URL of thumbnail.js

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