/* ほぼ、マウス前提なので、Vimperatorらしからぬプラグインですが... 短縮URLはアイテムを選択すると展開されるはず、 あと、画像っぽいURLも展開する(まだ出来るものが少ない) ToDo: YouTubeとかも展開出来るとイイね! == Settings == g:twittperator_plugin_twlist_win = 1 $RUNTIMEDIR/plugin/twittperator に入れている場合は設定してください。 g:twittperator_screen_name = "" g:twlist_max_rows = num 表示するアイテム数 (default: 50) == Command == :showtwin ウィンドウの表示/非表示 ToDo: 表示位置と幅、高さを維持したい */ let win = null; let winXML = .toXMLString(); let URL = "data:application/vnd.mozilla.xul+xml;base64," + btoa('' + winXML); function setStyleSheet() { styles.addSheet(true, "twlist-styles", "data:*", <>label { margin: 1px 2px 2px 2px !important; } .twlist-screenname { font-weight: bold; } .twlist-link { color: -moz-hyperlinktext; } .twlist-link:hover { chrome://browser/content/browser.xul cursor: pointer !important; } .twlist-hash { color: DarkGreen !important; } .twlist-image { max-height: 300px; border:thin solid; } ]]>.toString()); } function TweetItem(msg){ this.init.call(this, msg); } TweetItem.prototype = { init: function(msg) { }, }; function getItemXML(msg) { XML.prettyPrinting = true; XML.ignoreWhitespace = true; let xml; if ("direct_message" in msg) { xml = {formatText(msg.direct_message.text)} ; } else if ("retweeted_status" in msg) { xml = {formatText(msg.retweeted_status.text)} ; } else { xml = {formatText(msg.text)} ; } return xml; } function onLoad () { let gv = liberator.globalVariables; __context__.__defineGetter__("screenName", function() gv.twittperator_screen_name || ""); __context__.__defineGetter__("maxRows", function() gv.twlist_max_rows || 50); setStyleSheet(); plugins.twittperator.ChirpUserStream.addListener(streamListener); commands.addUserCommand(["showtwin"], "popup/hide twittperator window", function(arg){ if (!win) { open() } else { win.close(); } },{ bang: true }, true); } function open(){ win = openDialog(URL, null, "chrome", liberator, __context__ ); } function onClose(){ win = null; } function onUnload () { if (win) win.close(); plugins.twittperator.ChirpUserStream.removeListener(streamListener); } function streamListener(msg, raw) { if (!win) return; if ((msg.text && msg.user) || ("direct_message" in msg)) { win.add(msg); } } function getMedia (uri) { if (/\.gif$|\.jpe?g$|\.pi?ng$/.test(uri.path)) return ["image", uri.spec]; switch (uri.host) { case "twitpic.com": return ["image", "http://twitpic.com/show/thumb" + uri.path + ".jpg"]; case "movapic.com": return ["image", "http://image.movapic.com/pic/m_" + uri.path.substr(uri.path.lastIndexOf("/")+1) + ".jpeg"]; case "gyazo.com": return ["image", uri.spec]; case "twittgoo.com": let elm = util.httpGet(uri.spec + "/?format=atom").responseXML.getElementsByTagName("icon")[0]; return ["image", elm.textContent]; case "www.flickr.com": case "f.hatena.ne.jp": default: return []; } } function isShortenURL (uri) { switch (uri.host) { case "bit.ly": case "is.gd": case "j.mp": case "goo.gl": case "htn.to": case "tinyurl.com": case "ff.im": case "youtu.be": return true; } return false; } function getRedirectedURL (aURI, aElement, aCallback){ if (!aURI.schemeIs("http") && !aURI.schemeIs("https")) return; if (isShortenURL(aURI)){ let x = new XMLHttpRequest; x.open("HEAD", aURI.spec, true); x.onreadystatechange = function(){ if (x.readyState == 4){ aCallback.call(aElement, x.channel.URI); } }; x.send(null); } else { aCallback.call(aElement, aURI); } } function onSelect (evt) { let item = evt.target.selectedItem; let links = item.querySelectorAll("a.twlist-url"); function detectMedia (uri) { this.setAttribute("href", uri.spec); this.textContent = uri.spec; let [type, src] = getMedia(uri); if (type && src) { switch (type) { case "image": if (this.hasAttribute("shown") && this.getAttribute("shown") == "true") break; let img = document.createElementNS(XHTML, "img"); img.setAttribute("src", src); img.setAttribute("class", "twlist-image"); img.setAttribute("align", "right"); this.parentNode.appendChild(img); this.setAttribute("shown", "true"); break; default: } } } for (let i=0; i < links.length; i++) { let elm = links[i]; let uri = util.newURI(elm.getAttribute("href")); getRedirectedURL(uri, elm, detectMedia); } } 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 class = "twlist-link", href = ""; switch (m[0].charAt(0)){ case "@": class += " twlist-user"; href = "http://twitter.com/" + m[0].substr(1); break; case "#": class += " twlist-hash"; href = "http://twitter.com/search?q=%23" + m[0].substr(1); break; default: class += " twlist-url"; href = m[0]; } x.appendChild({m[0]}); i=reg.lastIndex; } buf = str.substr(i); if (buf) x.appendChild(buf); return x; } function onClick (evt) { if (evt.button == 2) return; evt.preventDefault(); evt.stopPropagation(); let where = (evt.ctrlKey || evt.button == 1) ? liberator.NEW_TAB : liberator.CURRENT_TAB; let url = evt.target.getAttribute("href"); liberator.open(url, {where: where}); } function onReply (elm, isDirectMessage) { let item = elm.parentNode.parentNode; let label = item.getAttribute("searchlabel"); let cmd = "tw " + (isDirectMessage ? "D @" : "@") + label + " "; commandline.open(":", cmd, modes.EX); window.focus(); } function onRetweet(elm){ let id = elm.parentNode.parentNode.value; plugins.twittperator.OAuth.post("http://api.twitter.com/1/statues/retweet/" + id + ".json", null, function(text){ }); } function onFav (elm) { let id = elm.parentNode.parentNode.value; let fav = elm.value; if (fav == "\u2605") { plugins.twittperator.OAuth.post("http://api.twitter.com/1/favorites/destroy/" + id + ".json", null, function(text){ elm.value = "\u2606"; }); } else { plugins.twittperator.OAuth.post("http://api.twitter.com/1/favorites/create/" + id + ".json", null, function(text){ elm.value = "\u2605"; }); } } onLoad(); // vim: sw=2 ts=2 et filetype=javascript: