Skip to content

Instantly share code, notes, and snippets.

@shogo82148
Last active June 13, 2017 01:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shogo82148/3953476 to your computer and use it in GitHub Desktop.
Save shogo82148/3953476 to your computer and use it in GitHub Desktop.
Togetterの編集作業便利にしたい
// ==UserScript==
// @name TogetterHelper
// @namespace https://gist.github.com/3883841
// @version 0.2
// @description Togetterの編集作業便利にしたい.
// @include http://togetter.com/create
// @include http://togetter.com/edit/*
// @copyright 2012+, shogo82148
// ==/UserScript==
(function() {
function $(expression, callback) {
var iterator, node;
if(callback) {
iterator = document.evaluate(expression, document, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
node = iterator.iterateNext();
while(node) {
callback(node);
node = iterator.iterateNext();
}
} else {
return document.evaluate(expression, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
}
}
function remove(node) {
node.parentNode.removeChild(node);
return node;
}
function click(elem) {
var e = document.createEvent("MouseEvents");
e.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false,
false, false, false, 0, null);
elem.dispatchEvent(e);
}
function Item(elem) {
this.elem = elem;
}
Item.prototype.tweet = function() {
var tweet = document.evaluate(
'.//div[@class="tweet"]',
this.elem, null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null).singleNodeValue;
if(!tweet) return null;
return tweet.innerText;
};
Item.prototype.id = function() {
return this.elem.id;
};
Item.prototype.remove = function() {
remove(this.elem);
};
Item.prototype.selected = function(flag) {
var classes = this.elem.className.split(' ');
var i, new_classes;
if(flag==undefined) {
return classes.indexOf('selected_item') > 0;
} else {
new_classes = [];
for(i=0;i<classes.length;i++) {
if(classes[i] != 'selected_item')
new_classes.push(classes[i]);
}
if(flag) new_classes.push('selected_item');
this.elem.className = new_classes.join(' ');
}
};
var ALL_CHOICES = '//*[@id="choices"]/*[contains(@class,"action_item")]';
var ALL_RESULTS = '//*[@id="results"]/*[contains(@class,"action_item")]';
var SELECTED_CHOICES = '//*[@id="choices"]/*[contains(@class,"action_item") and contains(@class,"selected_item")]';
var SELECTED_RESULTS = '//*[@id="results"]/*[contains(@class,"action_item") and contains(@class,"selected_item")]';
function getAllChices() {
var items = [];
$(ALL_CHOICES, function(elem) {
items.push(new Item(elem));
});
return items;
}
function getAllResults() {
var items = [];
$(ALL_RESULTS, function(elem) {
items.push(new Item(elem));
});
return items;
}
// リストの選択イベントを上書き
(function() {
var results = document.getElementById('results');
var choices = document.getElementById('choices');
bind(results, getAllResults);
bind(choices, getAllChices);
function bind(target, getAll) {
var last_click = null;
target.addEventListener('click', function(e) {
var target = getTargetItem(e);
var i, all, range;
if(!target) return;
if(e.ctrlKey) {
return;
} else if(e.shiftKey) {
//範囲選択
all = getAll();
range = [];
for(i=0;i<all.length;i++) {
if(all[i].elem==target.elem) range.push(i);
if(last_click && all[i].elem==last_click.elem) range.push(i);
}
if(range.length==1) {
target.selected(true);
last_click = target;
} else {
for(i=0;i<all.length;i++) {
all[i].selected(range[0] <= i && i <= range[1]);
}
}
} else {
//クリックされたものだけ選択を反転
last_click = target;
getAll().forEach(function(item) {
if(item.elem!=target.elem) item.selected(false);
});
}
getSelection().removeAllRanges();
});
function getTargetItem(e) {
var target = e.target;
while(target) {
if(target.className.indexOf('action_item')>=0)
return new Item(target);
target = target.parentNode;
}
return null;
}
}
})();
//自動読み込みスクリプト
(function() {
var autoSearch = document.createElement('input');
autoSearch.className = "btn";
autoSearch.type = "button";
autoSearch.value = "自動検索開始";
var searchButton = $('//*[@value="検索"]');
console.log(searchButton);
searchButton.parentNode.insertBefore(autoSearch, searchButton.nextSibling);
var countDown = document.createElement('span');
autoSearch.parentNode.insertBefore(countDown, autoSearch.nextSibling);
var timer, countDownTimer;
var ids = {};
autoSearch.addEventListener('click', function() {
var count = 0;
if(timer) {
clearInterval(timer);
clearInterval(countDownTimer);
timer = null;
autoSearch.value = "自動検索開始";
countDown.innerText = '';
} else {
var interval = prompt('更新間隔を秒単位で指定してください');
if(interval*1==NaN || interval < 10) {
alert('更新間隔には10以上の数字を入れてください!');
return ;
}
autoSearch.value = "自動検索停止";
$(ALL_CHOICES, function(elem) {
ids[elem.id] = true;
});
timer = setInterval(doAutoSearch, interval * 1000);
countDownTimer = setInterval(doCountDown, 1000);
countDown.innerText = interval;
doAutoSearch();
}
function doAutoSearch() {
count = interval;
var results = document.getElementById('results');
results.innerHTML = '';
var e = document.createEvent("MouseEvents");
click(searchButton);
setTimeout(function move() {
var items = [];
$(ALL_RESULTS, function(elem) {
items.push(elem);
});
if(items.length==0) {
setTimeout(move, 1000);
return ;
}
var choices = document.getElementById('choices');
items.reverse();
items.forEach(function(elem) {
if(ids[elem.id]) return ;
choices.appendChild(elem);
ids[elem.id] = true;
});
results.innerHTML = '';
}, 1000);
}
function doCountDown() {
count--;
countDown.innerText = count;
}
});
})();
})();
@nezuku
Copy link

nezuku commented Jun 13, 2017

現在TogetterがAOSSLに移行しているため、作動するURL (@include) について https://... も追加する必要があるようです。
(対象のウェブサイトに追加したところ、スクリプト自体は変更なしに動作しています。)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment