Last active
February 4, 2016 13:39
-
-
Save satyr/103277 to your computer and use it in GitHub Desktop.
twitter tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Cu.import("resource://ubiquity/modules/oauth.js") | |
const self = this, | |
H = Utils.escapeHtml, | |
Twitter = 'http://twitter.com/', | |
TWS = 'http://search.twitter.com/', | |
TWAPI = 'https://api.twitter.com/1.1/', | |
Yats = 'http://yats-data.com/yats/', | |
twicli = 'http://twicli.neocat.jp/', | |
Icon = 'chrome://ubiquity/skin/icons/twitter.ico', | |
Logo = '<a href='+ Twitter +' id=twlogo accesskey="/">' | |
+ '<img border=0 width=60 style="margin:30px"' | |
+ ' src=https://g.twimg.com/Twitter_logo_blue.png>' | |
+ '</a>' | |
NoLogin = 'Error (need to <a href='+ Twitter +'login accesskey=l>' | |
+ '<u>l</u>ogin</a>, maybe?)', | |
CSS = '\ | |
a img {border:none; max-width:99%; height:auto; vertical-align:top}\ | |
.error {font-style:oblique; line-height:1.8}\ | |
.logo {clear:both}\ | |
.logo img {vertical-align:middle}\ | |
.loading {opacity:0.9}\ | |
.loading + .logo {opacity:0.4}\ | |
.error + .logo {opacity:0.7}\ | |
', | |
CSS_TW = '\ | |
.entry-content {margin:0 0.2em; white-space:pre-wrap}\ | |
.entry-content img {display:block}\ | |
.actions, .actions-hover .del, .actions-hover span:not(.reply), .geo-pin\ | |
{display:none}\ | |
.entry-meta, .actions-hover {font-size:92%}\ | |
.actions-hover {list-style:none; padding-left:0}\ | |
.listable, .actions-hover, .actions-hover > li {display:inline}\ | |
.entry-date + span + a {margin-right:0.3em}\ | |
.reply::before {content:"["}\ | |
.reply::after {content:"]"}\ | |
.big-retweet-icon + *::before {content:"\267a "}\ | |
.status-body + .status-body {font-size:92%}\ | |
p.clearleft {margin:0.5ex 0}\ | |
#twlogo {display:inline-block}\ | |
', | |
XQ = [], | |
XHosts = { | |
'am6.jp': 'bit.ly', 'digs.by': 'bit.ly', 'ht.ly': 'ow.ly', | |
'tumblr.com': 'www.tumblr.com', | |
}, | |
XCache = {__proto__: null}, | |
B58Seq = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' | |
function xpand(target){ | |
var $t = $(target) | |
for (let a of $t.find('a').add($t.filter('a')).get()) | |
~XQ.indexOf(a) || XQ.push(a) | |
if(XQ.length) Utils.setTimeout(xproc) | |
return target | |
} | |
function xproc(){ | |
XQ.forEach(xpit); | |
XQ.length = 0; | |
} | |
function xpit(a){ | |
if(/^(?!\s*http:\/\/\S)/.test(a.textContent)) return; | |
var h = a.hostname; | |
if(h in XHosts) a.hostname = h = XHosts[h]; | |
else if(h == 'bit.ly') a.href = a.href.replace(/\+$/, ''); | |
var {href} = a; | |
if(href in XCache) return void(a.innerHTML = XCache[href]); | |
xsrc(a) || xget(a, xpandurl, | |
'http://api.longurl.org/v2/expand?format=json&title=1&url='+ | |
encodeURIComponent(href), 'json') | |
} | |
function xtrim(u){ | |
u = u.replace(/^http:\/+(?:www\.)?([^/]+)(?:\/$)?/, '$1') | |
.replace(/[?&#]utm_\w+=\w+/g, '') | |
.replace(/\/#!/, '') | |
try { while(u !== (u = decodeURIComponent(u))); } catch([]){} | |
return Utils.escapeHtml(u); | |
} | |
var xset = (a, h) => a.innerHTML = XCache[a.href] = h; | |
var ximg = (a, s) => s && xset(a, '<img src="'+ H(s) +'" align=top>') | |
function xget(a, f, u, dt, hs){ | |
a.style.opacity = .6; | |
function x_ok(r){ | |
f(a, r); | |
a.style.opacity = 'inherit'; | |
} | |
function x_ng(x){ | |
Utils.reportInfo( | |
'failed to expand ('+ x.status +' '+ x.statusText +')\n'+ a); | |
a.style.opacity = .9; | |
} | |
o = {url: u, dataType: dt || 'text', success: x_ok, error: x_ng}; | |
if(hs) o.beforeSend = function(x){ | |
for(var k in hs) x.setRequestHeader(k, hs[k]); | |
}; | |
return $.ajax(o); | |
} | |
function xsrc(a){ | |
if(a.querySelector('img')) return true; | |
var {href, hostname, pathname} = a, it; | |
if(pathname == '/') return false; | |
hostname = hostname.replace(/^www\./, ''); | |
if(it = ( | |
'grab.by' == hostname && /^\/[^/]+$/.test(pathname) | |
? [tinygrab, href] : | |
'photozou.jp' == hostname && (it = /\d+$/.exec(pathname)) | |
? [photozou, | |
'http://api.photozou.jp/rest/photo_info?photo_id='+ it, 'xml'] : | |
'twitpaint.com' == hostname && /\/\w+$/.test(pathname) | |
? [twitpaint, href] : | |
~['p.tl', 'pixiv.net'].indexOf(hostname) && /[id][\/=]\d+/.test(href) | |
? [pixiv, href] : | |
(it = ( | |
/^http:\/\/www\.flickr\.com\/photos\/[\w-_@]+\/(\d+)/.test(href) | |
? RegExp.$1 : | |
/^http:\/\/flic\.kr\/p\/(\w+)/.test(href) | |
? Array.reduce(RegExp.$1, (r, c) => r * 58 + B58Seq.indexOf(c), 0) | |
: '')) | |
? [flickr, | |
'https://api.flickr.com/services/rest/'+ Utils.paramsToString({ | |
method: 'flickr.photos.getInfo', | |
photo_id: it, format: 'json', nojsoncallback: 1, | |
api_key: '88dd5c2e369b0c2d5e7cff6f6258f215'})] : | |
/^https?:\/\/pic\.twitter\.com\/\w+/.test(href) || | |
/^https?:\/\/twitter\.com\/\w+\/status\/\d+\/photo\//.test(href) | |
? [twimg, href] : | |
/^http:\/\/movapic\.com\/\w+\/pic\/\d+/.test(href) | |
? [movapic, href] : | |
/^(http:\/\/[\w-]+\.tumblr\.com\/)post\/(\d+)/.test(href) | |
? [tumblr, RegExp.$1 +'api/read/json?id='+ RegExp.$2] : | |
/^http:\/+(twit(?:draw|paint))\.com\/\w+$/.test(href) | |
? [self[RegExp.$1], href] : | |
/^http:\/+instagr\.?am(?:\.com)?\/p\/\w/.test(href) | |
? [instagram, href] : | |
/^http:\/+picplz\.com\/\w{4,}/.test(href) | |
? [picplz, href] : | |
/^http:\/+cl\.ly\/\w+/.test(href) | |
? [clly, href] : | |
/^http:\/\/lockerz\.com\/s\/\d/.test(href) | |
? [lockerz, href] : | |
0)) return xget.apply(this, [a].concat(it)); | |
return ximg( | |
a, | |
/\.(?:png|gif|jpe?g)$/i.test(pathname) || /^data:image\/\w/.test(href) | |
? href : | |
'gyazo.com' == hostname && /^\/\w+$/.test(pathname) | |
? href + '.png' : | |
~['twitpic.com', 'img.ly'].indexOf(hostname) && | |
/^(?!\/show\/)/.test(pathname) | |
? 'http://'+ hostname +'/show/thumb'+ pathname : | |
~['plixi.com', 'tweetphoto.com', 'pic.gd'].indexOf(hostname) | |
? ('http://api.plixi.com/api/tpapi.svc/imagefromurl?'+ | |
'size=medium&url='+ encodeURIComponent(href)) : | |
'pic.im' == hostname && /^(?!\/website\/)/.test(pathname) | |
? 'http://pic.im/website/thumbnail'+ pathname : | |
'twitgoo.com' == hostname | |
? href + (pathname.lastIndexOf('/') > 0 ? '' : '/img') : | |
'p.twipple.jp' == hostname | |
? 'http://p.twpl.jp/show/orig'+ pathname : | |
'movapic.com' == hostname && /\/pic\/(\w+)$/.test(pathname) | |
? 'http://image.movapic.com/pic/m_'+ RegExp.$1 +'.jpeg' : | |
'moby.to' == hostname | |
? 'http://mobypicture.com/?'+ pathname.slice(1) +':medium' : | |
'pikchur.com' == hostname | |
? 'http://img.pikchur.com/pic_'+ pathname.slice(1) +'_m.jpg' : | |
'bcphotoshare.com' == hostname && (it = /\d+$/.exec(pathname)) || | |
'bctiny.com' == hostname && (it = parseInt(pathname.slice(2), 36)) | |
? 'http://images.bcphotoshare.com/storages/'+ it +'/thumb180.jpg' : | |
/^http:\/+yfrog\.(?:com|us)\/\w+$/.test(href) | |
? href +'.th.jpg' : | |
/^http:\/+ow\.ly\/i\/(\w+)/.test(href) | |
? 'http://static.ow.ly/photos/normal/'+ RegExp.$1 +'.jpg' : | |
'youtu.be' == hostname && (it = pathname.slice(1)) || | |
'youtube.com' == hostname && (it = (/\bv=([\w-]+)/.exec(a.search) || 0)[1]) | |
? 'http://i.ytimg.com/vi/'+ it +'/hqdefault.jpg' : | |
~['nico.ms', 'nicovideo.jp'].indexOf(hostname) && | |
(it = (/^\/(?:watch\/)?(?!lv)..(\d+)/.exec(pathname) || 0)[1]) | |
? 'http://tn-skr.smilevideo.jp/smile?i='+ it : | |
'twitvid.com' == hostname | |
? 'http://images.twitvid.com'+ pathname +'.jpg' : | |
''); | |
} | |
function twimg(a, htm){ | |
var m = /https:\/\/pbs\.twimg\.com\/media\/[\w-]+\.\w+:/.exec(htm) | |
if(m) return ximg(a, m +'small') | |
} | |
var clly = (a, htm) => | |
ximg(a, (/"embed" href="(.+?)"/.exec(htm) || 0)[1]) | |
var picplz = (a, htm) => | |
ximg(a, /http:\/+[^/]+.picplzthumbs.com\/[^\"\'\s]+?\.jpg/.exec(htm)) | |
var instagram = (a, htm) => | |
ximg(a, /http:\/+distilleryimage\d+\.ak\.instagram\.com\/[^\"' ]+/.exec(htm)) | |
var twitdraw = (a, htm) => | |
ximg(a, /<link rel="image_src"[^>]*(http:.+\.png)/.test(htm) && RegExp.$1) | |
var twitpaint = (a, htm) => | |
ximg(a, /http:\/+twitpaint\.com\/public\/graffiti\/\w+\.png/.exec(htm)) | |
function xpandurl(a, res){ | |
const GSORRY = 'http://sorry.google.com/sorry/?continue=' | |
var lu = res['long-url'] | |
if(~lu.lastIndexOf(GSORRY, 0)) | |
lu = decodeURIComponent(lu.slice(GSORRY.length)) | |
if(a.hash && !~lu.indexOf('#')) lu += a.hash | |
var {href} = a | |
if(lu == href) return a.innerHTML = XCache[href] = xtrim(href); | |
xset(a, xtrim(lu)); | |
a.title = (a.title && a.title +' ') + res.title +' '+ href | |
a.href = lu | |
return xsrc(a) | |
} | |
var pixiv = (a, htm) => ( | |
RegExp('<img[^>]+\\D'+ /\d+/.exec(a.href) +'_[^>]+>').test(htm) && | |
xset(a, RegExp.lastMatch.replace(/_\w\.j/, '_m.j'))); | |
var photozou = (a, xml) => ( | |
ximg(a, xml.querySelector('original_image_url').textContent)); | |
function flickr(a, json){ | |
try{ var {farm, server, id, secret} = JSON.parse(json).photo } | |
catch(e){ | |
e.message += '\n'+ a.href +'\n'+ json; | |
Cu.reportError(e); | |
return ''; | |
} | |
return ximg(a, ( | |
'http://farm'+ farm +'.static.flickr.com/'+ server +'/'+ | |
id +'_'+ secret +'.jpg')); | |
} | |
var tinygrab = (a, htm) => | |
/<img[^>]*\ssrc="http:\/\/grab\.by\/grabs\/.+?"/.test(htm) && | |
xset(a, RegExp.lastMatch) | |
var lockerz = (a, htm) => | |
/<img id="photo"[^>]+>/.test(htm) && | |
xset(a, RegExp.lastMatch) | |
var movapic = (a, htm) => ( | |
/<img class="image"[^>]*>/.test(htm) && xset(a, RegExp.lastMatch)); | |
var tumblr = (a, js) => ( | |
ximg(a, JSON.parse(js.slice(22, -2)).posts[0]['photo-url-500'])); | |
function ok(c, it){ | |
if(!it) return ng(ok.caller.name); | |
if(it.jquery) $(c).empty().append(it); | |
else c.innerHTML = it; | |
c.className = ''; | |
c.ownerDocument.defaultView.scrollTo(0, 0); | |
return c; | |
} | |
function ng(c){ | |
c.innerHTML = Array.slice(arguments, 1).join(' '); | |
c.className = 'error'; | |
return c; | |
} | |
var ngx = (c) => function(x){ if(x.status) ng(c, x.status, x.statusText) } | |
function jax(cn, url, cb, oauth){ | |
cn.className = 'loading' | |
var o = {url: url, success: cb, error: ngx(cn)} | |
if(oauth) o = ocomp(o) | |
return CmdUtils.previewAjax(cn.ownerDocument.body, o) | |
} | |
var atlink = (h) => h.replace(/[@\uff20](\w+)/g, _atlink); | |
var _atlink = (_, i) => _.link(Twitter + i); | |
var qsi = (l, s) => new Iterator(Array.slice(l.querySelectorAll(s))); | |
function noop(){} | |
function execurl(args){ | |
Utils.openUrlInBrowser((this._url || noop)(args) || this._du || this._hp); | |
} | |
function content(pb, cb){ | |
for(var cn, set;; set = pb.innerHTML = this._base) | |
if((cn = pb.ownerDocument.getElementById(this._name))){ | |
set && cb && cb.call(this, cn); | |
return cn; | |
} | |
} | |
function ocomp(o, name){ | |
if(!name){ | |
let [login] = noun_type_twitter_user.logins() | |
if(login) name = login.text | |
} | |
let pair = CmdUtils.loadPassword('TwitterOAuth', name) | |
if(!pair) return o | |
let [key, secret] = pair.split(' '), token = { | |
token: key, tokenSecret: secret, | |
consumerKey : 'C6h2HUUjmOcqXTtPRYqAVg', | |
consumerSecret : 'AYNHPfkpm5lL3uPKXRCuzGFYItA8EOWlrkajyEBOd6s', | |
} | |
return OAuth.completeAjaxSettings(o, token) | |
} | |
function TwitterCommand(o, notw){ | |
if('_css' in o || '_logo' in o){ | |
let [name] = o.names || [o.name]; | |
o._name = name = name.replace(/\W+/g, '_'); | |
o._base = '<style>'+ CSS + (notw ? '' : CSS_TW) + [o._css] +'</style>' | |
+ '<div class='+ name +'>' | |
+ '<div id='+ name +'>'+ H(o._htm || ' ') +'</div>' | |
+ '<div class=logo>'+ (o._logo || Logo) +'</div>' | |
+ '</div>' | |
o._content = content; | |
o._htm = o._css = o._logo = null; | |
} | |
'execute' in o || (o.execute = execurl); | |
'icon' in o || (o.icon = Icon); | |
return CmdUtils.CreateCommand(o); | |
} | |
const noun_twitter_friend = { | |
name: 'twitter friend', | |
label: 'screen name', | |
suggest: function ntf_suggest(txt, htm, cb, sx){ | |
var id = (/^\s*[@\uff20]?(\w+)\s*$/.exec(txt) || 0)[1]; | |
if(!id) return []; | |
var ss = this._friends(id, cb) || []; | |
ss.some(s => s.score === 1) || | |
ss.push(CmdUtils.makeSugg(id, htm, null, .1, sx && [0, id.length])); | |
return ss; | |
}, | |
_friends: function ntf_friends(input, cb){ | |
var ls = this._list; | |
if(ls.length) return CmdUtils.grepSuggs(input, ls); | |
var ms = Date.now(); | |
if(ms - this._last < 6e4) return; | |
this._last = ms; | |
var dic = {__proto__: null}; | |
var fun = (ss) => | |
(ss = CmdUtils.grepSuggs(input, ss)).length && cb(ss); | |
for(let {text} of noun_type_twitter_user.logins()){ | |
dic[text] = 1; | |
this._request(fun, text, ls, dic); | |
} | |
}, | |
_request: function ntf_request(back, name, list, dict){ | |
$.ajax(ocomp({ | |
url: TWAPI +'friends/ids.json', | |
dataType: 'json', | |
data: {screen_name: name, stringify_ids: 1}, | |
success: function ntf_ids_success({ids}){ | |
list.push({text: name, summary: name}) | |
while(ids.length) lookup(ids.splice(0, 100)) | |
}, | |
error: function ntf_ids_error(x){ | |
Utils.reportInfo([ | |
'error retrieving friends of @'+ name, | |
'status: '+ x.status +' '+ x.statusText].join('\n')) | |
Utils.setTimeout(function(){ list.length = 0 }, 6e4) | |
}, | |
}, name)) | |
function lookup(ids){ | |
$.ajax(ocomp({ | |
url: TWAPI +'users/lookup.json', dataType: 'json', | |
data: {user_id: ''+ids}, | |
success: function(users){ | |
var ss = [] | |
for(let {screen_name: sn} of users) if(!(sn in dict)) | |
ss.push({text: dict[sn] = sn, summary: sn}) | |
list.push.apply(list, ss) | |
back(ss) | |
}, | |
}, name)) | |
} | |
}, | |
_list: [], | |
_last: 0, | |
} | |
TwitterCommand({ | |
names: ['peek', 'view tweets'], | |
description: | |
'Peeks '+ 'tweets'.link(Twitter) +' of the specified user.', | |
authors: [{name: 'powchin', homepage: 'http://friendfeed.com/powchin'}, | |
'satyr'], | |
arguments: noun_twitter_friend, | |
execute: function peek_execute({object: {text: sn}}){ | |
var u = sn && Twitter + sn | |
if(!u){ | |
let {list} = noun_twitter_friend | |
if(list) u = Twitter + list[list.length * Math.random() | 0].text | |
} | |
u && Utils.openUrlInBrowser(u) | |
}, | |
preview: function peek_preview(pb, {object: {text: sn}}){ | |
var cn = this._content(pb), me = this | |
if(!sn) return | |
jax(cn, TWAPI +'statuses/user_timeline.json?count=100&screen_name='+ sn | |
, function peek_success(rs){ | |
var htm = '<a class=user href='+ Twitter + sn +' accesskey="@">' | |
+ '<span class=name>'+ sn +'</span></a>' | |
rs.length | |
? htm = '<img class=image src="' | |
+ H(rs[0].user.profile_image_url) | |
+ '">' + htm | |
: htm += '<br><em>No recent tweets.' | |
for(let r of rs) htm += | |
'<pre class=text>'+ H(r.text) + | |
' <a class="created" href='+ Twitter + sn +'/status/'+ r.id_str +'>'+ | |
H(new Date(r.created_at).toLocaleString()) +'</a></pre>' | |
ok(cn, htm) | |
}, true) | |
}, | |
_css: '\ | |
.user {magin-left:1em}\ | |
.image {vertical-align:middle; max-height:5ex}\ | |
.name {font-weight:bolder; font-size:128%; margin:0 0.5em}\ | |
.text {margin:0 0.5em 0.5ex}\ | |
.created {display:block; text-decoration:none; font-size:88%}\ | |
', | |
}) | |
TwitterCommand({ | |
names: ['glance', 'search tweets'], | |
arguments: { | |
object: noun_arb_text, | |
format: CmdUtils.NounType('language', { | |
'*': 'all', | |
'Arabic (\u0627\u0644\u0639\u0631\u0628\u064A\u0629)': 'ar', | |
'Danish (dansk)': 'da', | |
'Dutch (Nederlands)': 'nl', | |
'English': 'en', | |
'Farsi/Persian (\u0641\u0627\u0631\u0633\u06CC)': 'fa', | |
'Finnish (suomen kieli)': 'fi', | |
'French (fran\xE7ais)': 'fr', | |
'German (Deutsch)': 'de', | |
'Hungarian (Magyar)': 'hu', | |
'Icelandic (\xCDslenska)': 'is', | |
'Italian (Italiano)': 'it', | |
'Japanese (\u65E5\u672C\u8A9E)': 'ja', | |
'Norwegian (Norsk)': 'no', | |
'Polish (polski)': 'pl', | |
'Portuguese (Portugu\xEAs)': 'pt', | |
'Russian (\u0440\u0443\u0441\u0441\u043A\u0438\u0439 \u044F\u0437\u044B\u043A)': 'ru', | |
'Spanish (espa\xF1ol)': 'es', | |
'Swedish (Svenska)': 'sv', | |
'Thai (\u0E44\u0E17\u0E22)': 'th', | |
}, '^\\*'), | |
}, | |
description: 'Twitter Search'.link(TWS), | |
preview: function tws_preview(pb, {object: {text: q}, format: {data: l}}){ | |
var cn = this._content(pb), q = q.trim() | |
if(!q) return | |
jax(cn | |
, TWAPI +'search/tweets.json?count=100&q='+ | |
encodeURIComponent(q) +'&lang='+ l | |
, function tws_success({statuses: ss}){ | |
var htm = '' | |
for(var s of ss){ | |
let sn = s.user.screen_name | |
htm += '<div class=entry>' | |
+ '<a class=author href="'+ Twitter + sn +'">' | |
+ sn +'</a>' | |
+ '<a class=updated href="' | |
+ Twitter + sn +'/status/'+ s.id_str +'">' | |
+ H(new Date(s.created_at).toLocaleString()) +'</a>' | |
+ '<p class=tweet>'+ H(s.text) | |
let {urls} = s.entities | |
if(urls.length){ | |
htm += '<ul class=urls>' | |
for(let u of urls){ | |
let hu = H(u.url) | |
htm += '<li>'+ hu.link(hu) | |
} | |
htm += '</ul>' | |
} | |
htm += '</p></div>' | |
} | |
ok(cn, htm || '<p><em>No results.') | |
}, true) | |
}, | |
_hp: TWS, | |
_du: 'http://support.twitter.com/groups/31-twitter-basics/topics/'+ | |
'110-search/articles/71577-how-to-use-advanced-twitter-search', | |
_url: function tws_url({object: {text: q}, format: {data: l}}){ | |
return (q = q.trim()) | |
&& Twitter +'search?q='+ encodeURIComponent(q) + (l ? '&lang='+ l : '') | |
}, | |
_css: '\ | |
a {text-decoration:none; margin-left:0.3em}\ | |
.author {font-weight:bold}\ | |
.updated {margin-left:1ex}\ | |
.tweet {margin:0 0.5em 0.5ex}\ | |
.urls {margin:0}\ | |
', | |
}) | |
let logo = '<a href="http://longurl.org">' | |
+ '<img src="http://assets.longurl.org/static/images/longurl-logo.png"' | |
+ ' border=0></a>' | |
TwitterCommand({ | |
names: ['expand URLs'], | |
description: | |
'Expands all shortened and/or image links in <b>the focused page</b>.', | |
execute: function lu_execute(){ | |
!function recur(win){ | |
xpand(win.document.body) | |
Array.forEach(win, recur) | |
}(context.focusedWindow.top) | |
}, | |
preview: function lu_preview(pb){ | |
var cn = this._content(pb, this._form) | |
$(cn).find('b').text(context.focusedWindow.top.location.href) | |
}, | |
_form: function lu_form(cn){ | |
cn.innerHTML = this.previewDefault() | |
}, | |
_css: '', | |
_logo: logo, | |
}) & TwitterCommand({ | |
names: ['expand a URL'], | |
description: 'Expands a single URL.', | |
argument: { | |
default: function xau_default(){ | |
var [a] = CmdUtils.getSelectedNodes('a') | |
if(a) return CmdUtils.makeSugg(a.href) | |
}, | |
suggest: function xau_suggest(text){ | |
var url = text.trim() | |
if(/^(?:\w+:)?\/+\S+$/.test(url)) return CmdUtils.makeSugg(url) | |
}, | |
}, | |
execute: function xau_execute(args){ | |
var a = this._a(args) | |
if(a) CmdUtils.setSelection(a) | |
for (let a of CmdUtils.getSelectedNodes('a')) xpand(a) | |
}, | |
preview: function xau_preview(pb, args){ | |
var cn = this._content(pb) | |
;(cn.innerHTML = this._a(args)) | |
? xpand(cn) | |
: this.previewDefault(cn) | |
}, | |
_a: function xau_a({object: {text: u}}){ | |
if(!u) return | |
var hu = H(u) | |
return '<a href="'+ hu +'" class=url>'+ hu +'</a>' | |
}, | |
_css: '.url {display:inline-block; padding:1ex 1em}', | |
_logo: logo, | |
}) | |
/* | |
CmdUtils.onPageLoad(function autoxpand(doc){ | |
var win = doc.defaultView | |
if(win.parent != win) return | |
var target = doc.querySelector('#tw') | |
if(!target) return | |
xpand(target) | |
new win.MutationObserver(function(ms){ | |
for(let m of ms) if(m.type == 'childList'){ | |
for(let n of Array.slice(m.addedNodes)) xpand(n) | |
break | |
} | |
}).observe(target, {childList: true}) | |
}, [twicli +'twicli.html']) | |
*/ | |
$.extend(feed, { | |
author: {name: 'satyr', homepage: 'http://ubigist.appspot.com/?o=satyr'}, | |
license: 'X', | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment