/* jshint esversion: 6 */
// ==UserScript==
// @name filterSuperfluousOnDMM
// @namespace https://greasyfork.org/ja/users/289387-unagionunagi
// @version 1.3
// @description DMM・FANZAの通販商品一覧からアウトレット、限定版、および BOD/DOD を除去
// @author unagiOnUnagi
// @include /^https?://www.dmm\.co(m|\.jp)/mono/(\w+/)?-/(list|search)/.*/
// @grant GM_setValue
// @grant GM_getValue
// @license GPL-2.0-or-later
// ==/UserScript==
function resolvePropVal(isChecked) {
// display プロパティ値を決定
return isChecked ? 'none'
: document.URL.includes('/view=text/') ? 'table-row'
: 'list-item';
}
function addStyleSheet() {
// カスタムスタイルシートの作成
let styleEl = document.createElement('style');
styleEl.id = 'filtersuperfluousondmm-css';
document.head.appendChild(styleEl);
let styleSheet = styleEl.sheet;
// .superfluous {display: none} を追加
let value = resolvePropVal(GM_getValue('checked', true));
styleSheet.insertRule(`.superfluous {display: ${value};}`, 0);
// 全作品フィルター時のラベル点滅ルール
styleSheet.insertRule(
'.filtersuperfluousondmm-blink { animation: flash 0.6s linear 3; }', 1);
styleSheet.insertRule(
'@keyframes flash { 0%,100% { opacity: 1; } 50% { opacity: 0; } }', 2);
}
function reconfigureEvenOdds(isFiltered) {
let selector = isFiltered ? '.unsuperfluous' : '.superfluous,.unsuperfluous';
for (let [i, tr] of document.querySelectorAll(selector).entries()) {
let [correct, incorrect] = (i % 2) ? ['odd', 'even'] : ['even', 'odd'];
tr.classList.replace(incorrect, correct);
}
}
function toggleFilter(ev) {
// チェックボックスの状態を見て表示・非表示を切り換え
// console.log(ev);
let rule = document.getElementById("filtersuperfluousondmm-css").sheet.rules[0];
let isChecked = ev.target.checked;
rule.style.display = resolvePropVal(isChecked);
if (document.URL.includes('/view=text/')) {
reconfigureEvenOdds(isChecked);
}
GM_setValue('checked', isChecked);
}
function createElement(tag, attrs) {
// Elementの作成
let elem = document.createElement(tag);
for (let [a, v] of attrs) elem.setAttribute(a, v);
return elem;
}
function filterSuperflouous(lineup, itemElm, getTitle) {
// アウトレット、限定版、BOD/DOD を非表示に
// ページヘッダー
let lastSpan = document.querySelectorAll(
'.d-area .list-capt .list-boxseparate div.list-unit');
if (!lastSpan.length) {
console.log('Breadcrumb list not found');
return;
}
lastSpan = lastSpan[lastSpan.length - 1];
// カスタムスタイルシートの追加
addStyleSheet();
// 対象文字列正規表現
const pattern = [/【(特選)?アウトレット】/,
/【(DMM|FANZA|数量)限定】/,
/([BD]OD)$/,
/アウトレット(BD)?】$/];
const items = document.evaluate(itemElm, lineup, null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
const itemsLength = items.snapshotLength;
let nof = 0;
for (let i=0; i < itemsLength; i++) {
let item = items.snapshotItem(i);
let title = getTitle(item);
// パターンにマッチしたらクラスを追加
if (pattern.some(re => re.test(title))) {
item.classList.add('superfluous');
nof++;
} else {
item.classList.add('unsuperfluous');
}
}
// フィルターチェックボックスの追加
let filterSpan = createElement(
'span',
[['title',
`アウトレット、限定版、BOD/DOD を非表示にします (このページに ${nof} 個)`],
['style', 'margin-left: 10px;']]);
lastSpan.insertAdjacentElement('afterend', filterSpan);
let filterCb = createElement('input',
[['type', 'checkbox'],
['id', 'filtersuperfluousondmm-cb'],
['name', 'filtersuperfluousondmm-cb']]);
filterSpan.appendChild(filterCb);
let filterLabel = createElement('label',
[['for', 'filtersuperfluousondmm-cb']]);
filterSpan.appendChild(filterLabel);
// ページ内全作品が該当したとき
if (nof == itemsLength) {
nof = '全作品が該当';
filterLabel.classList.add('filtersuperfluousondmm-blink');
}
filterLabel.innerText = ` フィルター (${nof})`;
filterCb.checked = GM_getValue('checked', true);
filterCb.addEventListener('change', toggleFilter);
}
(function() {
let lineup = document.getElementById('list');
if (lineup) {
// 画像形式表示
filterSuperflouous(
lineup, 'li',
(item) => item.querySelector('div p.tmb a span img').getAttribute('alt'));
} else if ((lineup = document.querySelector('table[summary=商品一覧] tbody'))) {
// テキスト形式表示
filterSuperflouous(
lineup, 'tr[td]',
(item) => item.querySelector('td p.ttl a').text.trim());
reconfigureEvenOdds(GM_getValue('checked', true));
}
})();