There are 52 previous versions of this script.
Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)
// ==UserScript==
// @name Post Now browsing to Twitter
// @namespace http://efcl.info/
// @description Usage: Ctrl + Shift + Enter -> "Now browsing: ****" on Twitter.
// @include http://*
// @include https://*
// @exclude http://twicli.neocat.jp/twicli.html
// @require https://raw.github.com/azu/usconfig/v1.13/usconfig.js
// @require https://raw.github.com/azu/OAuth-for-Greasemonkey/master/oauth.js
// @require https://raw.github.com/azu/OAuth-for-Greasemonkey/master/sha1.js
// @require https://raw.github.com/azu/OAuth-for-Greasemonkey/master/GMwrap.js
// @run-at document-end
// @noframes
// ==/UserScript==
(function() {
// XPath関数
var XPath = {
cache: null,
reset: function () {
this.cache = {__proto__: null};
},
get: function (context, expr, type) {
var x = new XPathEvaluator();
var cache = this.cache, evaluator;
if (expr in cache) {
evaluator = cache[expr];
} else {
evaluator = cache[expr] = x.createExpression(expr, null);
}
return evaluator.evaluate(context, type, null);
},
has: function (context, expr) {
return this.get(context, expr, XPathResult.BOOLEAN_TYPE).booleanValue;
},
first: function (context, expr) {
return this.get(context, expr, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
},
last: function (context, expr) {
var all = this.get(context, expr, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
return all.snapshotItem(all.snapshotLength - 1) || null;
},
all: function (context, expr) {
var all = this.get(context, expr, XPathResult.ORDERED_NODE_ITERAATE_TYPE);
var ret = [];
for (var i; (i = all.iterateNext()) !== null;) {
ret.push(i);
}
return ret;
}
};
XPath.reset();
// OAuth
var clientInfo = {
name: 'PNBT',
consumerKey: '9zzFsVFm4nLyfF5WXZsbrg',
consumerSecret: '318LbLBmvECeZZmSUKVzdq8dpazGtMFf2P6hMPUjWU'
}
var TWOauth = new TwitterOauth(clientInfo);// OAuth認証オブジェクト初期化
TWOauth.injectToConfig = function(authorizeURL) {
var iframe = document.getElementById("usconfig_frame");
var iframeDoc = iframe.contentDocument;
// buttons_holder
var section = iframeDoc.createElement("div");
section.className = "section_header_holder";
section.setAttribute("style", <>
<![CDATA[
font-size: 95%;
line-height: 120%;
margin-left: 20%;
margin-right: 20%;
]]></>.toString());
if (TWOauth.isAuthorize()) {// OAuth認証済みな時
var configDiv1 = iframeDoc.createElement("div");
configDiv1.style.textAlign = "center";
configDiv1.className = "config_var";
var text = iframeDoc.createElement("span");
text.className = "field_label"
text.innerHTML = "OAuth logined ";
var resetBt = iframeDoc.createElement("Button");
resetBt.textContent = "Logout";
resetBt.addEventListener("click", function(e) {
if (window.confirm("Do you really logout?")) {
TWOauth.deleteAccessor();
Config.remove();
}
}, false)
configDiv1.appendChild(text);
configDiv1.appendChild(resetBt);
section.appendChild(configDiv1);
} else {
XHRloading.removeText(iframeDoc);// delete loading...
var configDiv1 = iframeDoc.createElement("div");
configDiv1.className = "config_var";
var explaintext = iframeDoc.createElement("p");
explaintext.innerHTML = <ol>
<li>Click "Sign in with Twitter" button</li>
<li>Allow {clientInfo.name} access</li>
<li>Copy PIN code</li>
<li>Input PIN code and Confirm</li>
</ol>.toString();
configDiv1.appendChild(explaintext);
var imgOauth = iframeDoc.createElement("img");
imgOauth.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJcAAAAYCAYAAAD3eW90AAAH30lEQVRoge2b/VNT6RXH87cwlW6d3W5H90UWEATa3e262247ne7UbmednXZW1850dGpZx5e17trRrCO+CyKiKEbCBpAQiIQIBglBCBJeFRABERYoBoQA4Saf/nD33kK4F4hNWjqTHz4zPJxzvufkPl/yPGQmGo1Go4lK1RIhQijRSMb6ua09bIRbP8LqJCpVS8RcEcK275qoVC3vVraEDclc4ewRYfUhm+sdqytsSOYKZ48Iqw/ZXG+XNyqyzd7OwKQHQRAQBIH8niHVXDUkcwVbF+H/G9lcPy2rV2TguYeWcYFt7QIn+kSDHXU9Us1XQjLXcnlJN2tINNwhxVQn/y7+hoXEAltQ/VZCuHRXqr/uzA1irpjC1v+//XrV9l0TlaolxeRQRBBEY0XXiNSMCTiHn7Gztk1my+1G1foUk0M2l1o82WjnFW0Wr391hp+lZbN2fxobLhtJMTn47fnrvJ9dtKT+ixAu3aX0k0tq5Z8z7tSx22RbVif6y1P8YO9xRV5Lzw/ZPErr/xTZXMnFdkUEQWBLy0JzSUekhHt6ln11HaoakrnU4nFZhZS3duLzw9ScgODzc7C2leRiOwDFjwdVa1+UcOmq6Ud/eYp1xy8viOc3P1xWZ3DSw8TsHBOzXtyeacanZ79fz5HR0hOyeQLXoUA2V1JhtSKB5gpkvUPAPCLgnp5R1ZDMpRY/YnMCcKjczibDHT6paOB3t+pJKqwm5ugFYs/lybnrz9yQ/3J/fCyb6AMnefNiEUmF1UQfOMlP0nJ4+UgmUV98w9rD6Wwy3FHsGai70tp1p3X88OBpNhXYSCqs5qVDZ3lFm0VSYTWxV8t46dDZRfqvHs+hb8xNcVMHP/r6PEmF1QDomx4s2+8TSwNbK5zsuC0+I1PHI7ZWONla4eSXptqQzKM032vn8ojef0KeLSHPKj+nV49fYe3X6aw9nK66p9K+a6JStSQaqhRZzlzRNWJcEARVDclcavGTjQ8B0NW5ePnQWd7ILJBjfWNuLt1rJtFQRcxlI9+Ybbg9M0zMzlHU1kXfmJtUi0POvWJvpKrnCYLPT213H/GXihR7ztcNpjbD2U7nd6PEZhcTc9lI85MhjE0PSMi/zcd5ZXQMjbKpYKG+obMfwednctaLa+QZiYYqAAqcbSuaNdFQxQdFd0RDuh6EfJ7A9YZLNzlcUsnQ8ykEvx9HTz8pGXr5OeXWuXA+HcY5OKo6r7TvmqhULQl6qyIrMZd00VfTkMylFn+noIrWUTcAPSNj7Lh2k3Wnr5Ogt8oPNEFv5dP8W/j8fsxd/bxdUMVVVycAB6x1cu6U10tmyyP0rd0AfFFuV+w5XzeY2j3VTQBsL6jgU71ZPMpnvcRdKuK8rR5rd/8i/V8b7zIxM0tFZy9bSu1Bz5qgt/K+oXLRzKGaJ3C93WDB5/eTbr9Pcoae0ckpcutbZB339AznXF3srGpUnVfad01UqpaNOosigebKGhDvXRJ9HtFYF11dqhqSudTiG3UWkvOsXG59xHPvHD6/n3+U2dios8jHx0adhfRaFwB/Kb3LRp2FXWU1orkqHHJuUUunGDMvjAUyXzeY2hS9lalZL5k1jWTVNFLdOwjADkM59b0DHHO0Kuq7PTOUtHUF3U9ic751kWYo55m/vtrQBoChuZMrznYGxidpGhyVdb51PVxyL+fvuyYqVUt8rlmRQHOZRxZf6Ct7B1Xr43PNsrnU4hsuFvJWdjHxuWa2FFYy5fXSNTxGfK75+4fSQXyumUvODgD+pCth/dkb/DmvVNwUS+2i3F1ldxfEApmfG2xtzeMBGnoHaHs6TGqVk/5nE+jrm/HOCfyqoFJRf9wzQ0lL5wv1i881szmvfJFmKOeZv9Y1iyfCxdom0u61caK+nYNVDYo6y+27JipVS1yOSRFBENj98N/m+qBJNNj8dy9BENC1dqtqSOZSi390zUjC0QzW7Esj7kgGkzMzNA2NEpdjEl/M/Q7ickzsqWwAwNLWzc68UpoHh+VNCczdabIBsL/crthzfm6wtefvtTIn+HjmmSbhaik327vxCgL3B4ZV9UcmPdg6H7Nm7/Gg+8XlmHhPZ16kGcp55q93W+sByG9oYe2+NNbsOcaHF/SKOkshmys226hIx8gYNWNL37kOdYsGU9OQzKUWT2/owOf3MzTpYWZOoH98ks9L7cRmG8Xj40GvnJvf9ogZQWBo0kOWQzwm91oci3L/VnEPgK9s9xV7BuoGU/tHo/jfXkXPU2KzjRy+K957rrg6VfVzW7rx+f2MTE0H3S8228hm3a1FmqGcJ3Cd4ezg+ayX2TkfM3M+7E+GFXWWQjZXTFaRIttN4scRJ/rUzbWtXTSXmoZkLrV4TFYRH+bd4rMSGx8X3OatJfLitZms2ZfGmv0nOFfpAOAPhZVLaq8W3rtexm/yLf/zOdTmCVzHZxfz0bcVvJtb+kL6srk2XDCo8vfKewiCeATufijewSS2tQu0jAv0uydU6yVzLdVjpTwZn6TfPcHjsXF8fj/61u6Q6EYIPbK53jyvX5K/llbT/t0/F13mBUGg/9kEv9ffUq2VzLVcj5WQmFnAZ0WV7Cqt5hfXSkKiGSE8yOZ648yNsCGZK5w9Iqw+ZHO9fio3bEjmCmePCKsP2Vzr03LChmSucPaIsPqQzbXuWHbYkMwVzh4RVh8LvgEUIUIo0Wg0mn8B8xp8c6hoOjUAAAAASUVORK5CYII=";
imgOauth.addEventListener("click", function() {
GM_openInTab(authorizeURL);
}, false);
configDiv1.appendChild(imgOauth);
var configDiv2 = iframeDoc.createElement("div");
configDiv2.className = "config_var";
var textPin = iframeDoc.createElement("span");
textPin.className = "field_label"
textPin.innerHTML = "Input PIN code ";
var inputPin = iframeDoc.createElement("input");
var submitBt = iframeDoc.createElement("Button");
submitBt.textContent = "Confirm";
submitBt.addEventListener("click", function(e) {
XHRloading.createText(iframeDoc);
TWOauth.getAccessToken(inputPin.value.replace(/\s/g, ""), function() {
XHRloading.removeText(iframeDoc);
alert("Authorization copplete!\nHave fun!");
});
}, false)
configDiv2.appendChild(textPin);
configDiv2.appendChild(inputPin);
configDiv2.appendChild(submitBt);
section.appendChild(configDiv1);
section.appendChild(configDiv2);
}
var inp = XPath.last(iframeDoc.body, '//div[@class="section"]');
inp.appendChild(section);
}
// ショートカットの設定関数
// http://d.hatena.ne.jp/jimo1001/20090601/1243782686 を改変
var ShortcutKey = function() {
this.list = [];
this.init();
}
ShortcutKey.prototype.keys = {
8: 'BS',
9: 'TAB',
10: 'Enter',
13: 'Enter',
32: 'SPC',
27: 'ESC',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'Left',
38: 'Up',
39: 'Right',
40: 'Down',
45: 'Insert',
46: 'Delete',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12'
}
ShortcutKey.prototype.skeys = {
8: 'BS',
10: 'Enter',
13: 'Enter',
32: 'SPC'
}
ShortcutKey.prototype.mkeys = {
'altKey' : 'A',
'ctrlKey' : 'C',
'metaKey' : 'M',
'shiftKey' : 'S'
}
ShortcutKey.prototype.init = function() {
var self = this;
window.addEventListener('keydown', function(evt) {
var key = self.get(evt);
self.list.forEach(function(a) {
if (a.key == key && (a.element == evt.target || a.element == evt.view)) {
// console.log(a.key +"=="+ key);
a.func(evt);
}
});
}, false);
}
ShortcutKey.prototype.add = function(elm, key, func) {
this.list.push({
'element' : elm,
'key' : key,
'func' : func
});
}
ShortcutKey.prototype.get = function(evt) {
var key = [], k = '';
for (mk in this.mkeys) {
if (evt[mk]) {
key.push(this.mkeys[mk]);
}
}
if (evt.which) {
k = this.keys[evt.which] || String.fromCharCode(evt.which).toLowerCase();
key.push(key.length ? '-' + k : k);
} else if (evt.keyCode) {
k = this.keys[evt.keyCode];
key.push(key.length ? '-' + k : k);
}
return key.join("");
}
// ショートカットの定義
var shortcut = new ShortcutKey();
Config.define('usc_basic', function() {
with (this.builder) {
var shortURL_opt = [
'bit.ly',
'j.mp',
'goo.gl',
'is.gd',
'tinyurl.com'
];
dialog(
"Post Now browsing to Twitter Settings",
{ width: 600, height: 700 },
section(
"User options",
"Behavior/keyboard Preference",
grid(
text("Prefix:", 'defaultTag', "Now browsing: ", { size: 20 }), '\n',
checkbox("Use selection quote", 'isSelection', true), '\n',
checkbox("remove utm_* parameter", 'removeUtm', false), '\n',
checkbox("avoid link to @ and #", 'avoidLinktoMeta', false), '\n',
checkbox("Post with Ctrl+Enter", 'PostWithCtrl', false), '\n',
text("ShortcutKey:", 'ShortCutKey', "CS-Enter", { size: 16 })
)
),
section(
"Short URL options",
"select used Short URL service",
grid(
select("Short URL Services", 'ShortURL', shortURL_opt, "bit.ly"), '\n',
text("bit.ly Username:", 'bitlyUserName', "remiko"), '\n',
text("bit.ly APIKey :", 'bitlyAPIKey', 'R_fa2240c646c07b2091c6bc6d109089ef', { size: 30 }),
'\n',
text("goo.gl APIKey :", 'googlAPIKey', '', { size: 30 })
)
),
section(
"OAuth Authorization",
"Sign in with Twitter"
)
);
}
},
// options
{
saveKey: 'GM_config',
aftersave: function() {
},
afteropen : function() {
// ショートカットの入力補助
var iframeDoc = this.frame.contentDocument;
iframeDoc.getElementById("control_ShortCutKey").addEventListener('keydown', function (evt) {
evt.preventDefault();
this.value = shortcut.get(evt);
}, false);
// OAuth Setting
if (TWOauth.isAuthorize()) {
TWOauth.injectToConfig();
} else {
XHRloading.createText(iframeDoc);
TWOauth.getRequestToken(TWOauth.injectToConfig);
}
}
});
GM_registerMenuCommand('Post Now browsing to Twitter Setting', function() {
// https://twitter.com/azu_re/statuses/70426009136144384
Config.open();
});
/* config-設定の初期化 */
var GM_settings = Config.load();
var defaultTag = GM_settings.defaultTag;// prefix - 何も書かなかった時の接頭辞
var UseSelection = GM_settings.isSelection;
var siteAPI = GM_settings.ShortURL;
const inputFramename = "GM_INPUT_FRAME";
var message = {
/*
必須
method
action
任意
headers ヘッダーオブジェクト
noparam trueならばactionのクエリにURLを付けないようにする
body POSTのdataを設定 $URL$となってる要素はURLに変わる
response jsonなら内容に従って取り出す
*/
'goo.gl' : {
method: "POST",
action: "https://www.googleapis.com/urlshortener/v1/url"
+ ((GM_settings.googlAPIKey !== "") ? "?key=" + GM_settings.googlAPIKey : ""),
headers : {
"Content-Type": "application/json"
},
noparam : true,
body : {
"longUrl": "$URL$"
},
response : "id"
},
'bit.ly' : {
method: "GET",
action: "http://api.bit.ly/v3/shorten?&format=txt&login="
+ GM_settings.bitlyUserName + "&apiKey=" + GM_settings.bitlyAPIKey + "&longUrl="
},
'j.mp' : {
method: "GET",
action: "http://api.j.mp/v3/shorten?&format=txt&login="
+ GM_settings.bitlyUserName + "&apiKey=" + GM_settings.bitlyAPIKey + "&longUrl="
},
'is.gd' : {
method: "GET",
action: "http://is.gd/api.php?longurl="
},
'tinyurl.com' :{
method: "GET",
action: "http://tinyurl.com/api-create.php?url="
}
};
// make ShortURL: url
function makeShortURL() {
this.initialize.apply(this, arguments);
}
makeShortURL.prototype = {
initialize: function(url) {
this.url = url;
this.shortAPI = siteAPI;
},
// test
showURL: function() {
alert(this.url);
},
formatParams : function(content) {
var result;
if (typeof(content) === "object") {
result = {};
for (var key in content) {
if (content[key] === "$URL$") {
result[key] = this.url;
} else {
result[key] = content[key];
}
}
result = JSON.stringify(result);
} else {
result = content;
}
return result;
},
getShortURL: function(callbackFunc) {
var btnDiv = XPath.first(document, 'id("GM_Now_browsing")');
var inpuFrame = XPath.first(document, '//iframe[@name="' + inputFramename + '"]');
if (!btnDiv && !inpuFrame) {
var mes = message[siteAPI];
var XHRobj = {};
XHRobj.method = mes.method;
XHRobj.url = mes.action + ((mes.noparam) ? "" : encodeURIComponent(this.url));
mes.headers && (XHRobj.headers = mes.headers);
mes.body && (XHRobj.data = this.formatParams(mes.body));
XHRobj.onload = function(res) {
if (res.readyState == 4 && (res.status == 200 || res.status == 201)) {
clearInterval(timerId);
XHRloading.removeDiv();
var shortedURL = res.responseText;
// 上手く取得できてない場合はkill
if (typeof shortedURL === "undefined" || shortedURL === "undefined") {
return;
}
if (mes.response) {
var resJSON = JSON.parse(shortedURL);
shortedURL = getObjValueFromString(resJSON, mes.response);
}
callbackFunc(shortedURL);
}
}
XHRobj.onerror = function(e) {
GM_log(e);
}
// ローディング表示
XHRloading.create();
var GM_xhr = GM_xmlhttpRequest(XHRobj);
// タイムアウト
var self = this;
var timerId = setTimeout((function(arg) {
return function() {
GM_xhr.abort();
var isChanged = self.changeShortAPI();// 短縮URLを変える。
XHRloading.removeDiv();
if (isChanged) {
arg.callee.apply(self, arg);
}
}
})(arguments), 7000);
}
},
// siteAPIを切り替えていく
changeShortAPI : function() {
message[siteAPI].mark = true;
for (var i in message) {
if (message[i] != siteAPI && !message[i].mark) {
siteAPI = i;
return true;
}
}
}
}
/* ポストメッセージの構造
Message
comment
activity
quotes
title
url
*/
// post to Twitter : url ,title
function postTwitter() {
this.initialize.apply(this, arguments);
}
postTwitter.prototype = {
initialize: function(url, title) {
this.url = url;
this.title = title;
this.comment = "";
this.activity = "";
},
make_message: function() {
if (UseSelection) {
var sel = window.getSelection();
var count = sel.rangeCount;
var r,t;
if (count > 1) {// 複数の選択範囲→「引用」「引用」"タイトル"
var selectionRange = [];
for (var i = 0; i < count; i++) {
if (sel.getRangeAt(i) != "") {// 空は取り除く
selectionRange.push(sel.getRangeAt(i));
}
}
if (selectionRange.length > 1) {
r = selectionRange.join('」「')
} else {
r = selectionRange;
}
var selection = r.toString().trim();
if (selection.length > 1) {
t = [' 「',selection,'」 ',' "',this.title,'" '].join('');
} else {
t = [' "',this.title,'" '].join('');
}
} else if (count == 1) {// 単一の選択範囲→「引用」"タイトル"
var selection = sel.toString().trim();
if (selection.length > 1) {
t = [' 「',selection,'」 ',' "',this.title,'" '].join('');
} else {
t = [' "',this.title,'" '].join('');
}
} else {// 選択範囲なし→"タイトル"
t = [' "',this.title,'" '].join('');
}
}
this.activity = t;
// 渡すオブジェクト
var defObj = {
activity : this.activity,
url : this.url
}
var self = this;
makeFrame(function gotFrame1(iframe, win, doc) {
self.doc = doc;
self.iframe = iframe;
iframe.width = "100%";
iframe.style.width = "100%";
iframe.style.position = "fixed";
var inputUI = self.createHTML(defObj);
self.addCSS(doc);
// 入力領域を表示
doc.body.appendChild(inputUI);
self.addInputEvent();
}, inputFramename);
},
// 入力領域のイベントを追加
addInputEvent : function() {
var self = this;
var doc = self.doc;
var inputHTML = XPath.first(doc, 'id("GM_Now_Box")');
var inputFiled = XPath.first(inputHTML, 'id("GM_Now_InputField")');
var activityFiled = XPath.first(inputHTML, 'id("GM_Now_SubActivity")');
var counterBox = XPath.first(inputHTML, 'id("GM_Now_SubCounter")');
var counter = parseInt(counterBox.textContent, 10); // 引用 + タイトル + URLの文字数
counterBox.textContent = counter + strlen(activityFiled.textContent);// デフォルトの表示
// bodyにもESCキーが聞くように
document.addEventListener("keypress", function(e) {
var esc = (e.keyCode == 27);
if (esc) {
this.removeEventListener("keypress", arguments.callee, false);
document.body.removeChild(self.iframe);
}
}, false)
// フォーカスをinputFiledへ移す
inputFiled.focus();
inputFiled.addEventListener("keypress", function(e) {
var shortcutFlag = false;
if (GM_settings.PostWithCtrl) {// Enterでポスト
var c = (e.ctrlKey);
var v = (e.keyCode == 13);
shortcutFlag = c && v;
} else {
shortcutFlag = (e.keyCode == 13);
}
var esc = (e.keyCode == 27);
if (shortcutFlag) {
this.removeEventListener("keypress", arguments.callee, false);
self.comment = inputFiled.value;
self.activity = activityFiled.textContent;
document.body.removeChild(self.iframe);
focusBody();
self.arrangeMes();
} else if (esc) { // Escでキャンセル
this.removeEventListener("keypress", arguments.callee, false);
document.body.removeChild(self.iframe);
focusBody();
} else if (e.keyCode == 9) {// TabキーでactivityFiledを有効化して移動
e.preventDefault()
activityFiled.setAttribute("contenteditable", "true");
activityFiled.focus();
}
}, false);
// contenteditableの日本語バグ?回避 - https://twitter.com/azu_re/statuses/16587183821
inputFiled.addEventListener("focus", function(e) {
activityFiled.setAttribute("contenteditable", "false");
}, false);
activityFiled.addEventListener("click", function(e) {
activityFiled.setAttribute("contenteditable", "true");
}, false);
// 文字数カウント
inputFiled.addEventListener("keyup", function(e) {
counterBox.textContent = counter + strlen(activityFiled.textContent) + strlen(inputFiled.value);
}, false);
},
// プロンプトのHTML生成
createHTML : function(obj) {
if (!obj) {
obj = {};
}
var defVal = {
activity : obj.activity || "",
url : obj.url || ""
}
var counter = strlen(obj.url);
// バグ - https://twitter.com/azu_re/statuses/16219838145
var E4Xhtml = <div style="display: block;" id="GM_Now_Box" class="GM_Now_ThemeDefault">
<input type="text" value="" id="GM_Now_InputField" class="GM_Now_ThemeDefault" />
<div id="GM_Now_Sub">
<div class="edit_guard">
<div contenteditable="false" id="GM_Now_SubActivity">{defVal.activity}</div>
</div>
<div id="GM_Now_SubCounter" style="font-size: 25px;">{counter}</div>
<div id="GM_Now_SubURL">{defVal.url}</div>
</div>
</div>;
var dom = e4xToDOM(E4Xhtml);
return dom;
},
addCSS : function(doc) {
// based on gleebox
addCSS(doc, <>
<![CDATA[
#GM_Now_Box {
line-height: 20px;
z-index: 7890;
position: fixed;
display: none;
overflow: auto;
width: 95%;
background-color: #333;
color: #fff;
padding: 4px 6px;
}
#GM_Now_InputField {
outline: none;
width: 90%;
margin: 0;
padding: 0;
margin: 3px 0;
border: none;
font-size: 32px;
background: none;
color: #fff;
/* ime-mode:active; */
}
#GM_Now_Sub{
}
.edit_guard{
width: auto;
float: left;
}
#GM_Now_SubURL, #GM_Now_SubActivity {
background: none;
color: #fff;
font-size: 15px;
width: auto;
margin-top : 3px;
font-weight: bold;
}
#GM_Now_SubURL {
display: inline;
float: right;
}
#GM_Now_SubCounter{
background: none;
color: #fff;
margin-left : 5px;
padding-bottom : -5px;
display: inline;
float: right;
}
#GM_Now_SubActivity {
height: 10px;
display: inline;
padding-left: 5px;
}
]]></>);
},
arrangeMes : function() {
if (this.comment == null) {
return;
}
if (this.comment == '') {
this.comment = defaultTag;
}
var s = [this.comment,this.activity,this.url].join(' ');
var l = this.activity.length || true;
var cutlength;
if (l && strlen(s) > 140) {
cutlength = strlen(s) - (140 - strlen(defaultTag));
this.activity = this.activity.slice(0, -cutlength);
l = strlen(this.activity);
if (UseSelection && cutlength > strlen(this.title)) {
// タイトルを削られた
this.activity += '…」';
} else {
this.activity += '…" '
}
s = [this.comment,this.activity,this.url].join('');
}
// ポストメッセージの完成
this.post_message = s;
this.post();
},
post : function() {
var content = {status: this.post_message, source: clientInfo.name};
TWOauth.post('https://api.twitter.com/1/statuses/update.json', content, function() {
GM_log("POST!");
});
}
}
// iframeから元のbodyにフォーカスを戻す
// bodyに直接フォーカスできないので、適当なボタンを作ってフォーカスさせる。
function focusBody() {
var inf = document.createElement("button");
inf.setAttribute("style", "position:fixed; top:4px; left:4px; width:1px; height:1px; border:none; background-color:#55f; opacity:0;");//-moz-opacityは3.5で廃止
document.body.appendChild(inf);
inf.focus();
document.body.removeChild(inf);
}
/* CSSをcontextに加える
how to use
addCSS(document ,<><![CDATA[
*{
font-size:12px;
background-color:#000;
}
]]></>);
*/
function addCSS(context, css) {
if (!context) {
context = document;
}
if (context.createStyleSheet) { // for IE
var sheet = context.createStyleSheet();
sheet.cssText = css;
return sheet;
} else {
var sheet = context.createElement('style');
sheet.type = 'text/css';
var _root = context.getElementsByTagName('head')[0] || context.documentElement;
sheet.textContent = css;
return _root.appendChild(sheet).sheet;
}
}
// フレームパネルの作成
function makeFrame(callback/*(iframeTag, window, document)*/, name) {
function testInvasion() {
iframe.removeEventListener("load", done, true);
var message = ((new Date) - load.start) + "ms passed, ";
try { // probe for security violation error, in case mozilla struck a bug
var url = unsafeWindow.frames[framename].location.href;
message += url == "about:blank" ? "but we got the right document." : "and we incorrectly loaded " + url;
done();
}
catch(e) {
document.body.removeChild(iframe);
makeFrame(callback, name);
}
}
function done() {
clearTimeout(load.timeout);
var win = unsafeWindow.frames[framename];
var doc = iframe.contentWindow.document;
callback(iframe, win, doc);
}
var iframe = document.createElement("iframe");
var framename = iframe.name = typeof name != "undefined" ? name : ("pane" + (makeFrame.id = (makeFrame.id || 0) - 1));
iframe.setAttribute("style", "overflow:auto;z-index:7890; border:0; margin:0; padding:0;top:82%; bottom:0; left:0;");
iframe.src = "about:blank";
iframe.addEventListener("load", done, true);
var frames = makeFrame.data || {};
var load = frames[framename] || {
start: new Date,
sleepFor: 400
};
load.timeout = setTimeout(testInvasion, load.sleepFor);
load.sleepFor *= 1.5;
frames[framename] = load;
makeFrame.data = frames;
document.body.appendChild(iframe);
}
// ローディング■の操作
var XHRloading = {
create : function () {
var btnDiv = XPath.first(document, 'id("GM_Now_browsing")');
if (!btnDiv) {
var btn = document.createElement('div');
btn.setAttribute("style", 'background: rgb(255, 0, 0) none repeat scroll 0% 0%; font-size: 12px; position: fixed;overflow:auto; bottom: 3px; right: 3px; -moz-background-clip: border; -moz-background-origin: padding; -moz-background-inline-policy: continuous; color: rgb(255, 255, 255); width: 20px; height: 20px; z-index: 255;');
btn.id = "GM_Now_browsing";
document.body.appendChild(btn);
}
},
removeDiv : function() {
var btn = XPath.first(document, 'id("GM_Now_browsing")');
if (btn) {
btn.parentNode.removeChild(btn);
}
},
createText : function(_doc) {
var txt = XPath.first(_doc, 'id("loading_message")');
if (!txt) {
var loading = _doc.createElement("p");
loading.setAttribute("style", <>
<![CDATA[
position:fixed;
right:0;
top:80%;
color:#fff;
background:#000;
]]></>.toString());
loading.innerHTML = "Now Loading...";
loading.id = "loading_message";
_doc.body.appendChild(loading);
}
},
removeText : function(_doc) {
var txt = XPath.first(_doc, 'id("loading_message")');
if (txt) {
_doc.body.removeChild(txt);
}
}
}
// 文字列を元にJSONオブジェクトの値を取り出す
function getObjValueFromString(obj, str) {
var req = str.split(".");
for (var i = 0,len = req.length; i < len; i++) {
obj = obj[req[i]];
}
return obj;
}
// E4X to DOM
function e4xToDOM(html) {
var range = document.createRange();
var dom = range.createContextualFragment(html);
return dom;
}
// http://liosk.blog103.fc2.com/blog-entry-162.html
function strlen(str) {
var i = 0, len = str.length, result = 0;
while (i < len) {
result++;
var x = str.charCodeAt(i++);
if (0xD800 <= x && x < 0xDC00) {
i++;
}
}
return result;
}
// debug関数
function log(m) {
if (unsafeWindow.console) {
unsafeWindow.console.log(m);
} else {
console.log(m); //GM_log(m)でも同じ。
}
}
// ショートカットのイベント設定
shortcut.add(window, GM_settings.ShortCutKey, function(evt){
evt.preventDefault();
launchPNBT();
});
GM_registerMenuCommand("Post to Twitter", function() {
launchPNBT();
})
function launchPNBT() {
if (!TWOauth.isAuthorize()) {
alert("You must Sign-in with Twitter");
Config.open();
return;
}
var normalURL = window.location.href;
var title = (document.title) ? document.title : window.parent.document.title;
if (/(^http:\/\/reader\.livedoor\.com\/|^http:\/\/fastladder\.com\/reader\/)/.test(normalURL)) {
var w = unsafeWindow;
var item = w.get_active_item(true);
var feed = w.get_active_feed();
normalURL = item.link;
title = item.title + " - " + feed.channel.title;
}
// utm_*を取り除く
if (GM_settings.removeUtm) {
normalURL = normalURL.replace(/([\?\&]utm_(source|medium|campaign|content)=.+)/ig, '');
}
// @や#を取り除く
if (GM_settings.avoidLinktoMeta) {
title = removeMeta(title);
}
var receivedShortUrl = new makeShortURL(normalURL);// 初期化
receivedShortUrl.getShortURL(function(shortedURL) {
var twitterNew = new postTwitter(shortedURL, title)
twitterNew.make_message();
});
}
// ユーザー名やハッシュタグのリンクをさせないようにゼロ幅文字を挟む
function removeMeta(str) {
var reg = {
'userName' : /\B([@@])([a-zA-Z0-9_]{1,20})\b/g,
'hashTag' : /\B([##])([a-zA-Z0-9_]+)/g
};
for (var i in reg) {
str = str.replace(reg[i], "$1$2");// $1 ゼロ幅文字 $2
}
return str;
}
})();