From 27950925687f7c19135268a35b18a7efa643b4ac Mon Sep 17 00:00:00 2001 From: Jagua Date: Sun, 8 Jul 2012 22:34:13 +0900 Subject: modified scrolling --- twittperator/twsidebar.tw | 1172 +++++++++++++++++++++++---------------------- 1 file changed, 606 insertions(+), 566 deletions(-) mode change 100755 => 100644 twittperator/twsidebar.tw (limited to 'twittperator/twsidebar.tw') diff --git a/twittperator/twsidebar.tw b/twittperator/twsidebar.tw old mode 100755 new mode 100644 index 9418e0a..bc81f28 --- a/twittperator/twsidebar.tw +++ b/twittperator/twsidebar.tw @@ -1,566 +1,606 @@ -liberator.modules.TWAnekoSB = ANekoSB = (function () { - - /********************************************************************************* - * Config - *********************************************************************************/ - - let Config = liberator.globalVariables.twittperator_sidebar_config || { - // for Keyword タグ - keyword: /neko|vimp|cat|猫/i, - - // ツイート内に含まれると、表示上抹殺される (reply とか除く - vanish: /うぎぃいいい/i, - - // 自分のスクリーンネーム - screenName: 'anekos', - - // 自分のその他の名前 - myNames: /anekos|悪魔猫将軍/i, - - // ログファイル てけとーなフォーマットで保存されます - //logFile: io.File('~/.chirpstream'), - //myLogFile: io.File('~/.mychirpstream'), - - // 各イベント時に音がなる - sound: { - meow: makeAudio('file:///home/anekos/sound/my/meow.wav'), - fanfare: makeAudio('file://C:/sound-data/fanfare.wav', 0.5), - retweet: makeAudio('file:///home/anekos/sound/my/meow.wav', 0.8), - favorite: makeAudio('file:///home/anekos/sound/my/meow.wav', 0.6), - reply: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), - debug: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), - filter: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), - }, - - // 文字のサイズ - fontSize: 15, - - // リストの最大保持数 - listMax: 100, - - // 日本語だけ for filter stream - jpOnly: true, - - // 地震ツイートの本文に場所をくっつける - earthquake: true, - - // サイドバーを閉じても機能を停止しない - dontStop: true, - - // サイドバーが閉じていても、こっそり開始しておく - silentStart: false, - - // 配列かオブジェクトを返すと、変更できる。 - // 文字列 "reject" を返すと、そもそもツイートが表示されなくなる。 - modifier: function (msg, tab, streamName) { - return [msg, tab, streamName]; - } - }; - - // 日本語判定 - JP = new RegExp("[\\u4e00-\\u9fa0\\u30A1-\\u30F6\\u30FC\\u3042-\\u3093\\u3001\\u3002\\uFF01\\uFF1F]"); - - /********************************************************************************* - * Main - *********************************************************************************/ - - // util {{{ - - function className (n) - ('tw-anekos-sb-plugin-' + n); - - function px (n) - parseInt(n, 10) + 'px'; - - // }}} - - function formatText (str) { // {{{ - str = str.trim(); - let reg = /https?:\/\/[^\s]+|[#@]\w+/g; - XML.ignoreWhitespace = false; - let m, i = 0, buf = "", x = ; - while((m=reg.exec(str))){ - buf = str.substring(i, m.index); - if (buf) - x.appendChild(buf); - let klass = "twlist-link", href = ""; - switch (m[0].charAt(0)){ - case "@": - klass += " twlist-user"; - href = "http://twitter.com/" + m[0].substr(1); - break; - case "#": - klass += " twlist-hash"; - href = "http://twitter.com/search?q=%23" + m[0].substr(1); - break; - default: - klass += " twlist-url"; - href = m[0]; - } - x.appendChild({m[0]}); - i=reg.lastIndex; - } - buf = str.substr(i); - if (buf) - x.appendChild(buf); - return x; - } // }}} - - function escapeBreakers (text) // {{{ - text.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]+/g, function(c) uneval(c)); // }}} - - function getSidebarWindow () - document.getElementById('sidebar')._contentWindow; - - let appendTweet = (function () { // {{{ - function messageToXML (t) { - XML.prettyPrinting = true; - XML.ignoreWhitespace = true; - let xml; - let sbWidth = getSidebarWindow().document.width; - xml = - 70 ? 2 : 0)), - "width: " + px(sbWidth - 100) + ' !important' - ].join(';')} - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - - - - - - - - - - {escapeBreakers(t.text)} - - - ; - return xml; - } - - function xmlToDom(xml, xmlns) { - XML.prettyPrinting = true; - XML.ignoreWhitespace = true; - var doc = (new DOMParser).parseFromString( - '' + xml.toXMLString() + "", - "application/xml"); - var imported = document.importNode(doc.documentElement, true); - var range = document.createRange(); - range.selectNodeContents(imported); - var fragment = range.extractContents(); - range.detach(); - return fragment.childNodes.length > 1 ? fragment : fragment.firstChild; - } - - let latest = {}; - let latestNode = null; - - function append (t, tab, streamName) { - tab = tab || 'home'; - - let modified = Config.modifier && Config.modifier(t, tab, streamName); - if (modified) { - if (modified instanceof Array) { - [t, tab, streamName] = modified; - } if (modified === 'reject') { - return; - } else { - t = modified; - } - } - - let now = JSON.stringify({name: t.name, text: t.text, tab: tab}); - if (latest === now) { - if (latestNode) - latestNode.setAttribute( - 'class', - latestNode.getAttributeNode('class') + className('tweet-' + t.type) - ); - return; - } - latest = now; - - let cntr = getSidebarWindow().document.getElementById('tw-anekos-sb-' + tab + '-list'); - let dom = xmlToDom(messageToXML(t)); - let repDom = dom.cloneNode(true); - let len = cntr.itemCount; - cntr.appendChild(repDom); - latestNode = repDom; - - cntr.scrollToIndex(len - 1); - if (len > Config.listMax) - cntr.removeChild(cntr.firstChild); - } - - return append; - })(); // }}} - - function objectToString (obj, head) { // {{{ - if (!head) - head = ''; - - let nextHead = head + ' '; - - let result = ''; - for (let [n, v] in Iterator(obj)) { - let vstr = - (v && typeof v === 'object') ? objectToString(v, nextHead) - : (v || '').toString(); - result += head + n + ':\n' + vstr.split(/\n/).map(function(s) nextHead + s).join('\n') + '\n'; - } - - return result.trim(); - } // }}} - - function onMsg (real, msg, raw, streamName) { // {{{ - if (real) { - Tweets.unshift(msg); - if (Tweets.length > Config.listMax) - Tweets.splice(Config.listMax); - } - - if (sidebarClosed) - return; - - let screenName = Config.screenName; - let my = (msg.retweeted_status && msg.retweeted_status.user.screen_name === screenName) - || - (msg.target_object && msg.event && ( - (msg.event === 'favorite' && msg.target_object.user.screen_name == screenName) - || - (msg.event === 'list_member_added' && msg.target.screen_name == screenName) - )) - || - (msg.user && msg.text && Config.myNames.test(msg.text)) - || - (msg.user && msg.text && msg.in_reply_to_screen_name == screenName) - || - (msg.direct_message); - - // Fav test - try { - //liberator.log(JSON.stringify(msg, null, 2)); - if (msg.event && msg.event === 'favorite' && msg.source && msg.source.screen_name === screenName) { - let t = { - name: '>' + msg.target_object.user.screen_name + '<', - img: msg.target_object.user.profile_image_url, - text: msg.target_object.text, - type: 'favorite' - }; - appendTweet(t, 'home', streamName); - } - } catch (e) { - liberator.log(e); - } - - // Ignore not JP - if (!my && streamName === 'filter' && msg.text && Config.jpOnly && !JP.test(msg.text)) { - return; - } - - if (msg.text && msg.user && msg.user && msg.user.screen_name === screenName) - my = false; - - let t, dummy; - - if (msg.direct_message) { - t = { - name: msg.direct_message.sender.screen_name, - img: msg.direct_message.sender.profile_image_url, - text: msg.direct_message.text, - sub: 'DM', - type: 'DM' - }; - } else if (msg.retweeted_status) { - t = { - name: my ? msg.user.screen_name : msg.retweeted_status.user.screen_name, - img: my ? msg.user.profile_image_url : msg.retweeted_status.user.profile_image_url, - text: msg.retweeted_status.text, - sub: '\u21BB ' + msg.user.screen_name, - type: 'retweet' - }; - dummy = true; - } else if (my && msg.target && msg.event) { - if (msg.event === 'favorite' && msg.target_object && !msg.target_object.retweeted_status) { - t = { - name: msg.source.screen_name, - img: msg.source.profile_image_url, - text: msg.target_object.text, - type: 'favorite', - sub: 'fav' - }; - dummy = true; - } else if (msg.event === 'list_member_added' && msg.target) { - // 結構漏れがある? - t = { - name: msg.source.screen_name, - img: msg.source.profile_image_url, - text: - '\u3042\u306A\u305F\u3092\u30EA\u30B9\u30C8\u300C' + - msg.target_object.name + - '\u300D\u306B\u8FFD\u52A0\u3057\u307E\u3057\u305F\u3002\n' + - 'http://twitter.com' + msg.target_object.uri, - type: 'list-member-added', - sub: 'listed' - }; - dummy = true; - } - } else if (msg.event === 'follow' && msg.target && msg.source) { - t = { - name: msg.source.screen_name, - img: msg.source.profile_image_url, - text: 'follow ' + msg.target.screen_name, - type: 'follow' - }; - my = msg.target.screen_name === screenName; - dummy = true; - } else if (msg.user && msg.text && msg.in_reply_to_screen_name == screenName) { - t = { - name: msg.user.screen_name, - img: msg.user.profile_image_url, - text: msg.text, - type: 'reply' - }; - } else if (msg.user && msg.text) { - t = { - name: msg.user.screen_name, - img: msg.user.profile_image_url, - text: msg.text, - type: 'normal' - }; - } - - if (t) { - if (Config.earthquake && /\u5730\u9707/.test(t.text) && msg.text.length < 20 && msg.user && msg.user.location) { - t.text += ' [\u5730\u57DF: ' + msg.user.location + ']'; - } - - if (!t.sub && msg.created_at) { - t.sub = new Date(msg.created_at).toLocaleTimeString().replace(/:\d+$/,'');; - } - - if (real && dummy) { - if (typeof dummy != 'object') { - dummy = { - user: { - screen_name: t.name || '', - profile_image_url: t.img - }, - text: '[' + t.type + '] ' + t.text + ' - http://twitter.com/' + t.name - }; - } - plugins.twittperator.Twittperator.onMessage(dummy); - } - - if (my || !Config.vanish.test([t.name, t.text, t.sub].join(' '))) { - if (my) { - if (real) { - let sound = Config.sound[t.type] || Config.sound.fanfare; - sound.play(); - } - t.type += '-my'; - } else { - if (t.type === 'normal' && Config.keyword.test(t.text)) - t.type = 'keyword'; - } - - if (streamName === 'filter') { - if (!msg.retweeted_status) { - t.type = 'filter'; - appendTweet(t, 'home', streamName); - appendTweet(t, 'filter', streamName); - let (s = Config.sound.filter) (s && s.play()); - } - } else if (/^(keyword)$/.test(t.type)) { - appendTweet(t, 'home', streamName); - appendTweet(t, t.type, streamName); - } else if (my) { - appendTweet(t, 'home', streamName); - appendTweet(t, 'my', streamName); - } else { - appendTweet(t, 'home', streamName); - } - } - } - - if (real) { - let s = - '----------------------------------------\n' + - objectToString(msg).replace(/\x0D\x0A|\x0D|\x0A/g, '\n'); - if (Config.logFile) - Config.logFile.write(s, '>>'); - if (my && Config.myLogFile) - Config.myLogFile.write(s, '>>'); - } - } // }}} - - function makeOnMsg (real, streamName) // {{{ - function (msg, raw) - onMsg(real, msg, raw, streamName); // }}} - - function addCommands () { // {{{ - commands.addUserCommand( - ['tws[idebar'], - 'nosidebar commands', - function (args) { - }, - { - subCommands: [ - new Command( - ['v[anish]'], - 'Vanish matched tweets', - function (args) { - Config.vanish = new RegExp(args.literalArg, 'i'); - }, - { - literal: 0, - completer: function (context, args) { - context.completions = [ - [util.escapeRegex(Config.vanish.source), ''] - ]; - } - } - ), - new Command( - ['k[eyword]'], - 'Show matched tweets in keyword tab', - function (args) { - Config.keyword = new RegExp(args.literalArg, 'i'); - }, - { - literal: 0, - completer: function (context, args) { - context.completions = [ - [util.escapeRegex(Config.keyword.source), ''] - ]; - } - } - ), - new Command( - ['j[ponly]'], - 'Show only Japanese Tweet', - function (args) { - Config.jpOnly = /yes/i.test(args.literalArg); - }, - { - literal: 0, - completer: function (context, args) { - context.completions = [ - ['yes', 'yes'], - ['no', 'no'] - ]; - } - } - ), - new Command( - ['t[ab]'], - 'select tab', - function (args) { - let tabbox = getSidebarWindow().document.getElementById('tw-anekos-sb-tabbox'); - let index = parseInt(args.literalArg, 10); - tabbox.selectedIndex = index; - }, - { - literal: 0, - completer: function (context, args) { - let tabs = getSidebarWindow().document.getElementById('tw-anekos-sb-tabbox').querySelectorAll('tab'); - context.completions = [ - [i + ': ' + tab.getAttribute('label'), tab.getAttribute('label')] - for ([i, tab] in Iterator(Array.slice(tabs))) - ]; - } - } - ) - ] - }, - true - ); - } // }}} - - /********************************************************************************* - * Install - *********************************************************************************/ - - let Store = storage.newMap("twittperator-anekos-sb", {store: true}); - let started = false; - let readyToStart = false; - let sidebarClosed = true; - - let Tweets = __context__.Tweets; - if (!Tweets) - Tweets = __context__.Tweets = Store.get("history", []); - - let added = {}; - - function start (isOpen, silent) { // {{{ - function restore () { - Array.slice(Tweets).reverse().forEach(makeOnMsg(false)); - } - - if (silent && (started || readyToStart)) - return; - - if (isOpen && sidebarClosed) { - sidebarClosed = false; - if (started) { - restore(); - return; - } - } - - if (readyToStart) - return; - if (started) - stop(); - - readyToStart = true; - started = true; - setTimeout( - function () { - readyToStart = false; - restore(); - plugins.twittperator.ChirpUserStream.addListener(added.chirp = makeOnMsg(true, 'chirp')); - plugins.twittperator.TrackingStream.addListener(added.filter = makeOnMsg(true, 'filter')); - }, - 1000 - ); - } // }}} - - function stop (isClose) { // {{{ - if (!started) - return liberator.echoerr('TWAnekoSB has not been started!'); - - if (isClose && Config.dontStop) { - sidebarClosed = true; - return; - } - - plugins.twittperator.ChirpUserStream.removeListener(added.chirp); - plugins.twittperator.TrackingStream.removeListener(added.filter); - Store.set("history", Tweets); - } // }}} - - function makeAudio (path, volume) { // {{{ - let audio = new Audio(path); - // XXX 効いてない - if (volume) - audio.volume = volume; - return audio; - } // }}} - - __context__.onUnload = function() { stop(); }; - - addCommands(); - - if (Config.silentStart) - start(false, true); - - return {start: start, stop: stop}; - -})(); +liberator.modules.TWAnekoSB = ANekoSB = (function () { + + /********************************************************************************* + * Config + *********************************************************************************/ + + let Config = liberator.globalVariables.twittperator_sidebar_config || { + // for Keyword タグ + keyword: /neko|vimp|cat|猫/i, + + // ツイート内に含まれると、表示上抹殺される (reply とか除く + vanish: /うぎぃいいい/i, + + // 自分のスクリーンネーム + screenName: 'anekos', + + // 自分のその他の名前 + myNames: /anekos|悪魔猫将軍/i, + + // ログファイル てけとーなフォーマットで保存されます + //logFile: io.File('~/.chirpstream'), + //myLogFile: io.File('~/.mychirpstream'), + + // 各イベント時に音がなる + sound: { + meow: makeAudio('file:///home/anekos/sound/my/meow.wav'), + fanfare: makeAudio('file://C:/sound-data/fanfare.wav', 0.5), + retweet: makeAudio('file:///home/anekos/sound/my/meow.wav', 0.8), + favorite: makeAudio('file:///home/anekos/sound/my/meow.wav', 0.6), + reply: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), + debug: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), + filter: makeAudio('file:///home/anekos/sound/my/meow.wav', 1.0), + }, + + // 文字のサイズ + fontSize: 15, + + // リストの最大保持数 + listMax: 100, + + // リストの表示順(昇順/降順) + listAscendingOrder: true, + + // ツイートされる度に最新ツイート位置までスクロールする + listAutoScroll: true, + + // 日本語だけ for filter stream + jpOnly: true, + + // 地震ツイートの本文に場所をくっつける + earthquake: true, + + // サイドバーを閉じても機能を停止しない + dontStop: true, + + // サイドバーが閉じていても、こっそり開始しておく + silentStart: false, + + // 配列かオブジェクトを返すと、変更できる。 + // 文字列 "reject" を返すと、そもそもツイートが表示されなくなる。 + modifier: function (msg, tab, streamName) { + return [msg, tab, streamName]; + } + }; + + // 日本語判定 + JP = new RegExp("[\\u4e00-\\u9fa0\\u30A1-\\u30F6\\u30FC\\u3042-\\u3093\\u3001\\u3002\\uFF01\\uFF1F]"); + + /********************************************************************************* + * Main + *********************************************************************************/ + + // util {{{ + + function className (n) + ('tw-anekos-sb-plugin-' + n); + + function px (n) + parseInt(n, 10) + 'px'; + + // }}} + + function formatText (str) { // {{{ + str = str.trim(); + let reg = /https?:\/\/[^\s]+|[#@]\w+/g; + XML.ignoreWhitespace = false; + let m, i = 0, buf = "", x = ; + while((m=reg.exec(str))){ + buf = str.substring(i, m.index); + if (buf) + x.appendChild(buf); + let klass = "twlist-link", href = ""; + switch (m[0].charAt(0)){ + case "@": + klass += " twlist-user"; + href = "http://twitter.com/" + m[0].substr(1); + break; + case "#": + klass += " twlist-hash"; + href = "http://twitter.com/search?q=%23" + m[0].substr(1); + break; + default: + klass += " twlist-url"; + href = m[0]; + } + x.appendChild({m[0]}); + i=reg.lastIndex; + } + buf = str.substr(i); + if (buf) + x.appendChild(buf); + return x; + } // }}} + + function escapeBreakers (text) // {{{ + text.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]+/g, function(c) uneval(c)); // }}} + + function getSidebarWindow () + document.getElementById('sidebar')._contentWindow; + + let appendTweet = (function () { // {{{ + function messageToXML (t) { + XML.prettyPrinting = true; + XML.ignoreWhitespace = true; + let xml; + let sbWidth = getSidebarWindow().document.width; + xml = + 70 ? 2 : 0)), + "width: " + px(sbWidth - 100) + ' !important' + ].join(';')} + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + + + + + + + + + + + {escapeBreakers(t.text)} + + + ; + return xml; + } + + function xmlToDom(xml, xmlns) { + XML.prettyPrinting = true; + XML.ignoreWhitespace = true; + var doc = (new DOMParser).parseFromString( + '' + xml.toXMLString() + "", + "application/xml"); + var imported = document.importNode(doc.documentElement, true); + var range = document.createRange(); + range.selectNodeContents(imported); + var fragment = range.extractContents(); + range.detach(); + return fragment.childNodes.length > 1 ? fragment : fragment.firstChild; + } + + let latest = {}; + let latestNode = null; + + function append (t, tab, streamName) { + tab = tab || 'home'; + + let modified = Config.modifier && Config.modifier(t, tab, streamName); + if (modified) { + if (modified instanceof Array) { + [t, tab, streamName] = modified; + } if (modified === 'reject') { + return; + } else { + t = modified; + } + } + + let now = JSON.stringify({name: t.name, text: t.text, tab: tab}); + if (latest === now) { + if (latestNode) + latestNode.setAttribute( + 'class', + latestNode.getAttributeNode('class') + className('tweet-' + t.type) + ); + return; + } + latest = now; + + let cntr = getSidebarWindow().document.getElementById('tw-anekos-sb-' + tab + '-list'); + let dom = xmlToDom(messageToXML(t)); + let repDom = dom.cloneNode(true); + let visibleIndex = cntr.getIndexOfFirstVisibleRow(); + let len = cntr.itemCount; + if (Config.listAscendingOrder) { + cntr.appendChild(repDom); + } else { + cntr.insertBefore(repDom, cntr.firstChild); + visibleIndex += 1; + } + latestNode = repDom; + + if (len > Config.listMax) { + if (Config.listAscendingOrder) { + cntr.removeChild(cntr.firstChild); + visibleIndex -= 1; + } else { + cntr.removeChild(cntr.lastChild); + } + len -= 1; + } + + if (Config.listAutoScroll) { + if (Config.listAscendingOrder) { + cntr.scrollToIndex(len - 1); + } else { + cntr.scrollToIndex(0); + } + } else { + if (Config.listAscendingOrder) { + if (len - visibleIndex < 10) { // 10 = 絶妙な値!これでいいのか! + cntr.scrollToIndex(len - 1); + } else { + cntr.scrollToIndex(visibleIndex); + } + } else { + if (visibleIndex < 3) { // 3 = 絶妙な値!これでいいのか! + cntr.scrollToIndex(0); + } else { + cntr.scrollToIndex(visibleIndex); + } + } + } + } + + return append; + })(); // }}} + + function objectToString (obj, head) { // {{{ + if (!head) + head = ''; + + let nextHead = head + ' '; + + let result = ''; + for (let [n, v] in Iterator(obj)) { + let vstr = + (v && typeof v === 'object') ? objectToString(v, nextHead) + : (v || '').toString(); + result += head + n + ':\n' + vstr.split(/\n/).map(function(s) nextHead + s).join('\n') + '\n'; + } + + return result.trim(); + } // }}} + + function onMsg (real, msg, raw, streamName) { // {{{ + if (real) { + Tweets.unshift(msg); + if (Tweets.length > Config.listMax) + Tweets.splice(Config.listMax); + } + + if (sidebarClosed) + return; + + let screenName = Config.screenName; + let my = (msg.retweeted_status && msg.retweeted_status.user.screen_name === screenName) + || + (msg.target_object && msg.event && ( + (msg.event === 'favorite' && msg.target_object.user.screen_name == screenName) + || + (msg.event === 'list_member_added' && msg.target.screen_name == screenName) + )) + || + (msg.user && msg.text && Config.myNames.test(msg.text)) + || + (msg.user && msg.text && msg.in_reply_to_screen_name == screenName) + || + (msg.direct_message); + + // Fav test + try { + //liberator.log(JSON.stringify(msg, null, 2)); + if (msg.event && msg.event === 'favorite' && msg.source && msg.source.screen_name === screenName) { + let t = { + name: '>' + msg.target_object.user.screen_name + '<', + img: msg.target_object.user.profile_image_url, + text: msg.target_object.text, + type: 'favorite' + }; + appendTweet(t, 'home', streamName); + } + } catch (e) { + liberator.log(e); + } + + // Ignore not JP + if (!my && streamName === 'filter' && msg.text && Config.jpOnly && !JP.test(msg.text)) { + return; + } + + if (msg.text && msg.user && msg.user && msg.user.screen_name === screenName) + my = false; + + let t, dummy; + + if (msg.direct_message) { + t = { + name: msg.direct_message.sender.screen_name, + img: msg.direct_message.sender.profile_image_url, + text: msg.direct_message.text, + sub: 'DM', + type: 'DM' + }; + } else if (msg.retweeted_status) { + t = { + name: my ? msg.user.screen_name : msg.retweeted_status.user.screen_name, + img: my ? msg.user.profile_image_url : msg.retweeted_status.user.profile_image_url, + text: msg.retweeted_status.text, + sub: '\u21BB ' + msg.user.screen_name, + type: 'retweet' + }; + dummy = true; + } else if (my && msg.target && msg.event) { + if (msg.event === 'favorite' && msg.target_object && !msg.target_object.retweeted_status) { + t = { + name: msg.source.screen_name, + img: msg.source.profile_image_url, + text: msg.target_object.text, + type: 'favorite', + sub: 'fav' + }; + dummy = true; + } else if (msg.event === 'list_member_added' && msg.target) { + // 結構漏れがある? + t = { + name: msg.source.screen_name, + img: msg.source.profile_image_url, + text: + '\u3042\u306A\u305F\u3092\u30EA\u30B9\u30C8\u300C' + + msg.target_object.name + + '\u300D\u306B\u8FFD\u52A0\u3057\u307E\u3057\u305F\u3002\n' + + 'http://twitter.com' + msg.target_object.uri, + type: 'list-member-added', + sub: 'listed' + }; + dummy = true; + } + } else if (msg.event === 'follow' && msg.target && msg.source) { + t = { + name: msg.source.screen_name, + img: msg.source.profile_image_url, + text: 'follow ' + msg.target.screen_name, + type: 'follow' + }; + my = msg.target.screen_name === screenName; + dummy = true; + } else if (msg.user && msg.text && msg.in_reply_to_screen_name == screenName) { + t = { + name: msg.user.screen_name, + img: msg.user.profile_image_url, + text: msg.text, + type: 'reply' + }; + } else if (msg.user && msg.text) { + t = { + name: msg.user.screen_name, + img: msg.user.profile_image_url, + text: msg.text, + type: 'normal' + }; + } + + if (t) { + if (Config.earthquake && /\u5730\u9707/.test(t.text) && msg.text.length < 20 && msg.user && msg.user.location) { + t.text += ' [\u5730\u57DF: ' + msg.user.location + ']'; + } + + if (!t.sub && msg.created_at) { + t.sub = new Date(msg.created_at).toLocaleTimeString().replace(/:\d+$/,'');; + } + + if (real && dummy) { + if (typeof dummy != 'object') { + dummy = { + user: { + screen_name: t.name || '', + profile_image_url: t.img + }, + text: '[' + t.type + '] ' + t.text + ' - http://twitter.com/' + t.name + }; + } + plugins.twittperator.Twittperator.onMessage(dummy); + } + + if (my || !Config.vanish.test([t.name, t.text, t.sub].join(' '))) { + if (my) { + if (real) { + let sound = Config.sound[t.type] || Config.sound.fanfare; + sound.play(); + } + t.type += '-my'; + } else { + if (t.type === 'normal' && Config.keyword.test(t.text)) + t.type = 'keyword'; + } + + if (streamName === 'filter') { + if (!msg.retweeted_status) { + t.type = 'filter'; + appendTweet(t, 'home', streamName); + appendTweet(t, 'filter', streamName); + let (s = Config.sound.filter) (s && s.play()); + } + } else if (/^(keyword)$/.test(t.type)) { + appendTweet(t, 'home', streamName); + appendTweet(t, t.type, streamName); + } else if (my) { + appendTweet(t, 'home', streamName); + appendTweet(t, 'my', streamName); + } else { + appendTweet(t, 'home', streamName); + } + } + } + + if (real) { + let s = + '----------------------------------------\n' + + objectToString(msg).replace(/\x0D\x0A|\x0D|\x0A/g, '\n'); + if (Config.logFile) + Config.logFile.write(s, '>>'); + if (my && Config.myLogFile) + Config.myLogFile.write(s, '>>'); + } + } // }}} + + function makeOnMsg (real, streamName) // {{{ + function (msg, raw) + onMsg(real, msg, raw, streamName); // }}} + + function addCommands () { // {{{ + commands.addUserCommand( + ['tws[idebar'], + 'nosidebar commands', + function (args) { + }, + { + subCommands: [ + new Command( + ['v[anish]'], + 'Vanish matched tweets', + function (args) { + Config.vanish = new RegExp(args.literalArg, 'i'); + }, + { + literal: 0, + completer: function (context, args) { + context.completions = [ + [util.escapeRegex(Config.vanish.source), ''] + ]; + } + } + ), + new Command( + ['k[eyword]'], + 'Show matched tweets in keyword tab', + function (args) { + Config.keyword = new RegExp(args.literalArg, 'i'); + }, + { + literal: 0, + completer: function (context, args) { + context.completions = [ + [util.escapeRegex(Config.keyword.source), ''] + ]; + } + } + ), + new Command( + ['j[ponly]'], + 'Show only Japanese Tweet', + function (args) { + Config.jpOnly = /yes/i.test(args.literalArg); + }, + { + literal: 0, + completer: function (context, args) { + context.completions = [ + ['yes', 'yes'], + ['no', 'no'] + ]; + } + } + ), + new Command( + ['t[ab]'], + 'select tab', + function (args) { + let tabbox = getSidebarWindow().document.getElementById('tw-anekos-sb-tabbox'); + let index = parseInt(args.literalArg, 10); + tabbox.selectedIndex = index; + }, + { + literal: 0, + completer: function (context, args) { + let tabs = getSidebarWindow().document.getElementById('tw-anekos-sb-tabbox').querySelectorAll('tab'); + context.completions = [ + [i + ': ' + tab.getAttribute('label'), tab.getAttribute('label')] + for ([i, tab] in Iterator(Array.slice(tabs))) + ]; + } + } + ) + ] + }, + true + ); + } // }}} + + /********************************************************************************* + * Install + *********************************************************************************/ + + let Store = storage.newMap("twittperator-anekos-sb", {store: true}); + let started = false; + let readyToStart = false; + let sidebarClosed = true; + + let Tweets = __context__.Tweets; + if (!Tweets) + Tweets = __context__.Tweets = Store.get("history", []); + + let added = {}; + + function start (isOpen, silent) { // {{{ + function restore () { + Array.slice(Tweets).reverse().forEach(makeOnMsg(false)); + } + + if (silent && (started || readyToStart)) + return; + + if (isOpen && sidebarClosed) { + sidebarClosed = false; + if (started) { + restore(); + return; + } + } + + if (readyToStart) + return; + if (started) + stop(); + + readyToStart = true; + started = true; + setTimeout( + function () { + readyToStart = false; + restore(); + plugins.twittperator.ChirpUserStream.addListener(added.chirp = makeOnMsg(true, 'chirp')); + plugins.twittperator.TrackingStream.addListener(added.filter = makeOnMsg(true, 'filter')); + }, + 1000 + ); + } // }}} + + function stop (isClose) { // {{{ + if (!started) + return liberator.echoerr('TWAnekoSB has not been started!'); + + if (isClose && Config.dontStop) { + sidebarClosed = true; + return; + } + + plugins.twittperator.ChirpUserStream.removeListener(added.chirp); + plugins.twittperator.TrackingStream.removeListener(added.filter); + Store.set("history", Tweets); + } // }}} + + function makeAudio (path, volume) { // {{{ + let audio = new Audio(path); + // XXX 効いてない + if (volume) + audio.volume = volume; + return audio; + } // }}} + + __context__.onUnload = function() { stop(); }; + + addCommands(); + + if (Config.silentStart) + start(false, true); + + return {start: start, stop: stop}; + +})(); -- cgit v1.2.3