// ==UserScript==
// @name ヤフオクで非表示とメモ
// @description Q:非表示に追加 W:非表示を一個アンドゥ B:NGワードを追加 Shift+B:非表示リストを編集 12:メモを書く !":自由メモ R:メモをリセット .:上限価格にフォーカス
// @match *://auctions.yahoo.co.jp/search/*
// @match *://page.auctions.yahoo.co.jp/jp/auction/*
// @version 0.2
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @namespace https://greasyfork.org/users/181558
// @downloadURL none
// ==/UserScript==
(function() {
const ENABLEREPORTXPATH = 1; //0で自動非表示登録が働いてもレポートを表示しない
const COLOR1 = "#6080ff",
COLOR2 = "#c03020",
KEYHIDE = "q",
KEYUNDO = "w",
KEYBW = "b",
KEYEDIT = "Shift+B",
KEYMAXP = ".",
KEYMEMO1 = "1",
KEYMEMO2 = "2",
KEYMEMO1S = "Shift+!",
KEYMEMO2S = "Shift+\"",
KEYRESET = "r";
var mousex = 0;
var mousey = 0;
document.addEventListener('keydown', function(e) {
if (/input|textarea/i.test(e.target.tagName) == false) {
var key = (e.shiftKey ? "Shift+" : "") + (e.altKey ? "Alt+" : "") + (e.ctrlKey ? "Ctrl+" : "") + e.key;
if (key === KEYHIDE) { // hide
e.preventDefault();
var ele = location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") != -1 ? eleget0('//h1[@class="ProductTitle__text"]') : document.elementFromPoint(mousex, mousey);
blockElement(ele);
}
if (key == KEYUNDO) { // undo
e.preventDefault();
let undoTitle = (pref('YAJSearchHideTitle') || "").match(/\|[^\|]*$|^[^|]*$/);
pref('YAJSearchHideTitle', (pref('YAJSearchHideTitle') || "").replace(/\|[^\|]*$|^[^|]*$/, ""))
if (undoTitle[0]) {
showByTitle(undoTitle[0].replace(/^\|/, ""))
popup2(undoTitle[0].replace(/^\|/, "") + "
を非表示登録から削除しました
編集後:
" + (pref('YAJSearchHideTitle') || "").substr(0, 500));
}
}
if (key == KEYBW) { // NGword
e.preventDefault();
addNGWord();
}
if (key === KEYEDIT) { // edit NGs
e.preventDefault();
let tmp = prompt(KEYEDIT + ":\n非表示にするタイトルを正規表現で編集してください\n|で区切ると複数指定できます\n\n" + (pref('YAJSearchHideTitle') || ""), pref('YAJSearchHideTitle') || "");
if (tmp !== null) {
pref('YAJSearchHideTitle', tmp || "")
location.reload();
}
}
if (key == KEYMEMO1) { // 1memo
e.preventDefault();
var ele = location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") != -1 ? eleget0('//h1[@class="ProductTitle__text"]') : document.elementFromPoint(mousex, mousey);
memoElement(ele, document);
}
if (key == KEYMEMO2) { // 2memo
e.preventDefault();
var ele = location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") != -1 ? eleget0('//h1[@class="ProductTitle__text"]') : document.elementFromPoint(mousex, mousey);
memoElement(ele, document, COLOR2);
}
if ((key == KEYMEMO1S || key == KEYMEMO2S)) { // free memo
e.preventDefault();
var target = (prompt("メモを付けたい出品物のタイトルが含むキーワードを入力してください") || "").trim();
if (!target) return;
var memo = (prompt("「" + target + "」\nのメモを書いてください") || "").trim();
if (!memo) return;
storeMemo(target.trim(), memo, key == KEYMEMO1S ? COLOR1 : COLOR2)
}
if (key == KEYRESET) { // reset
e.preventDefault();
console.log(pref('YAJSearchMyMemo'))
if (confirm(KEYRESET + ":\nメモを全て削除します。良いですか?\n\n" + JSON.stringify(pref('YAJSearchMyMemo') || '[]'))) {
pref('YAJSearchMyMemo', "");
popup2("メモをクリアしました", 1);
location.reload();
}
}
if (location.href.indexOf("://page.auctions.yahoo.co.jp/jp/auction/") == -1) {
if (key == KEYMAXP) { // maxprice
e.preventDefault();
let ele = eleget0('//input[@class="InputText__input" and @name="max"]');
if (ele) {
ele.focus();
ele.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" });
ele.select();
}
popup2("上限価格にフォーカス", 1);
}
}
}
}, false);
document.addEventListener("mousemove", function(e) {
mousex = e.clientX;
mousey = e.clientY;
}, false);
setTimeout(() => { run() }, 500);
document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { run(evt.target); }, false);
function run(node = document) {
if (pref('YAJSearchMyMemo')) {
for (let a of pref('YAJSearchMyMemo')) {
memoByTitle(a.t, a.m, node, a.c || COLOR1);
}
}
let help = KEYHIDE + ":非表示 " + KEYUNDO + ":アンドゥ " + KEYBW + ":NGワード " + KEYEDIT + ":NG編集 " + KEYMEMO1 + KEYMEMO2 + ":メモを追加 " + KEYMEMO1S + KEYMEMO2S + ":自由メモ " + KEYRESET + ":メモをリセット " + KEYMAXP + ":上限価格";
if (pref('YAJSearchHideTitle')) {
var i = 0;
for (let title of pref('YAJSearchHideTitle').split("|")) {
i += hideByTitle(title, node);
}
if (i && ENABLEREPORTXPATH) { help = i + "個の出品を非表示にしました
" + help; }
}
popup2(help, 1)
return;
}
function memoElement(ele, node, color = COLOR1) { //A memo
if (!ele) return;
var title = checkSome(ele);
if (!title) return;
var memo = (prompt("「" + title + "」\nのメモを書いてください") || "").trim();
storeMemo(title, memo, color, node);
return true;
}
function storeMemo(title, memo, color = COLOR1, node = document) {
if (title && memo) {
let tmp = pref('YAJSearchMyMemo') || [];
tmp.push({ t: title, m: memo, c: color })
pref('YAJSearchMyMemo', tmp)
memoByTitle(title, memo, node, color);
}
}
function memoByTitle(title, memo, node, color) {
var xp = '//a[contains(@class,"Product__titleLink") and contains(text(),"' + title + '")]/../..|.//h1[@class="ProductTitle__text" and contains(text(),"' + title + '")]/..';
for (var titleEle of elegeta(xp, node)) {
if (titleEle) {
var ele = titleEle.parentNode.parentNode.insertBefore(document.createElement("span"), titleEle.parentNode.nextSibling);
ele.innerHTML = '' + memo + '';
setRemoveMemo(ele, title, memo)
}
}
}
function setRemoveMemo(ele, title, memo) {
ele.onclick = (e) => {
pref('YAJSearchMyMemo', (pref('YAJSearchMyMemo') || []).filter(n => n.t != title || n.m != memo))
for (let e of elegeta('//span[@class="' + escape(title + memo) + '"]')) e.remove(); //ele.remove();
}
}
function checkSome(ele) {
if (ele.className == "ProductTitle__text") return ele.innerText.replace(/\|/g, '\|').trim();
for (let i = 0; i < 4; i++) {
var ele2 = elegeta('//a[@class="Product__titleLink"]|.//a[@class="Product__titleLink u-textBold"]', ele);
if (ele2.length == 1) { return ele2[0].innerText.replace(/\|/g, '\|').trim(); }
ele = ele.parentNode;
}
return;
}
function blockElement(ele) { //Q toggle
if (!ele) return;
var title = checkSome(ele);
if (!title) return;
if ((pref('YAJSearchHideTitle') || "").match(new RegExp("(^|\|)" + title.replace(/(\(|\)|\[|\]|\?|\*|\^|\$|\.|\+|\{|\}|\|)/gm, "\\$1") + "($|\|)"))) {
pref('YAJSearchHideTitle', (pref('YAJSearchHideTitle') || "").replace(new RegExp("(^|\|)" + title.replace(/(\(|\)|\[|\]|\?|\*|\^|\$|\.|\+|\{|\}|\|)/gm, "\\$1") + "($|\|)"), "").replace(/(^\|)|(\|\|)|(\|$)/gm, ""));
showByTitle(title);
popup2(title + "
を非表示登録から削除しました
編集後:
" + (pref('YAJSearchHideTitle') || "").substr(0, 500));
return;
} else {
if ((pref('YAJSearchHideTitle') || "").indexOf(title) != -1) return;
}
hideByTitle(title);
if (pref('YAJSearchHideTitle')) pref('YAJSearchHideTitle', pref('YAJSearchHideTitle') + "|" + title);
else pref('YAJSearchHideTitle', title);
popup2(title + "
を非表示登録しました(" + KEYUNDO + ":取り消し " + KEYEDIT + ":編集)
編集後:
" + pref('YAJSearchHideTitle').substr(0, 500));
}
function hideByTitle(title, node) {
let i = 0;
var xp = '//a[contains(@class,"Product__titleLink") and contains(text(),"' + title + '")]/../../../../..';
for (let ele of elegeta(xp, node)) {
i++;
setTimeout(function() { ele.style.opacity = "0.75" }, 17 * 0);
setTimeout(function() { ele.style.opacity = "0.50" }, 17 * 1);
setTimeout(function() { ele.style.opacity = "0.25" }, 17 * 2);
setTimeout(function() {
ele.style.display = "none";
ele.style.opacity = "0"
}, 17 * 3);
}
var xp = '//h1[@class="ProductTitle__text" and contains(text(),"' + title + '")]/../../../..';
for (let ele of elegeta(xp, node)) {
i++;
ele.style.opacity = "0.5";
}
return i;
}
function showByTitle(title) {
var xp = '//a[contains(@class,"Product__titleLink") and contains(text(),"' + title + '")]/../../../../..';
for (let ele of elegeta(xp)) {
setTimeout(function() {
ele.style.display = "block";
ele.style.opacity = "0.25"
}, 17 * 0);
setTimeout(function() { ele.style.opacity = "0.50" }, 17 * 1);
setTimeout(function() { ele.style.opacity = "0.75" }, 17 * 2);
setTimeout(function() { ele.style.opacity = "1" }, 17 * 3);
}
var xp = '//h1[@class="ProductTitle__text" and contains(text(),"' + title + '")]/../../../..';
for (let ele of elegeta(xp)) { ele.style.opacity = "1"; }
}
function addNGWord() {
var newWord = (prompt("非表示にしたい出品物が含むNGワードを入力してください") || "").trim();
if (newWord) {
hideByTitle(newWord)
if (pref('YAJSearchHideTitle')) pref('YAJSearchHideTitle', pref('YAJSearchHideTitle') + "|" + newWord);
else pref('YAJSearchHideTitle', newWord);
popup2(title + "
を非表示登録しました(" + KEYUNDO + ":取り消し " + KEYEDIT + ":編集)
編集後:
" + pref('YAJSearchHideTitle').substr(0, 500));
}
}
function elegeta(xpath, node = document) {
if (!xpath) return [];
try {
var array = [];
var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0; i < ele.snapshotLength; i++) array[i] = ele.snapshotItem(i);
return array;
} catch (e) { return []; }
}
function eleget0(xpath, node = document) {
if (!xpath) return null;
try {
var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
return ele.snapshotLength > 0 ? ele.snapshotItem(0) : "";
} catch (e) { return null; }
}
var maet;
function popup2(text, i = 0) {
var mae = eleget0('//span[@id="mllbox"]');
if (maet && mae) {
mae.remove();
clearTimeout(maet);
}
var ele = document.body.appendChild(document.createElement("span"));
ele.outerHTML = '' + text + '';
maet = setTimeout(function() {
var mae = eleget0('//span[@id="mllbox"]');
if (mae) { mae.remove(); }
}, 5000);
}
function pref(name, store = null) {
if (store === null) {
let data = GM_getValue(name)
if (data == undefined) return;
if (data.substr(0, 1) === "[") return JSON.parse(data || '[]');
else return data;
}
if (store === "" || store === []) {
GM_deleteValue(name);
return;
} else if (typeof store === "string") {
GM_setValue(name, store);
return store;
} else {
GM_setValue(name, JSON.stringify(store));
return store;
}
}
})()