您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
DMM・FANZAで商品(など)のリンクに(だいたいの)フルタイトルをポップアップ
当前为
/* jshint esversion: 6 */ // ==UserScript== // @name popupTitleOverAnchorsOnDMM // @namespace https://greasyfork.org/ja/users/289387-unagionunagi // @description DMM・FANZAで商品(など)のリンクに(だいたいの)フルタイトルをポップアップ // @author unagiOnUnagi // @match *://*.dmm.co.jp/* // @match *://*.dmm.com/* // @grant none // @license GPL-2.0-or-later // @version 0.6.5 // ==/UserScript== function getTrimText(node) { return node.textContent.trim().replace(/\s+/g, ' '); } function getTitle(anchor) { // タイトルの取得 // alt がなかったら a タグの onclick を見てみる // onclick もダメだったら a タグ内のタイトル文字列をそのまま // DMM 動画top: altなし、div/div(title, (price)?, summary) // VR top: altなし、span(title, price) // Idol top: altなし、span(title, price) // IdolCh top: altなし、a直下 // 見放題ch top: altなし、a直下 // FANZA 動画top pickup: altなし、span(title, maker, price) let title = anchor.getElementsByTagName('img')[0].getAttribute('alt'); if (title) return title; let nameNode = anchor.querySelector('.mainListLinkWork__txt,.responsive-name,.c-product-card__ttl,.bx-title'); if (nameNode) { if ((title = getTrimText(nameNode))) return title; } let onclick = anchor.getAttribute('onclick'); if (onclick && onclick.startsWith('_gaq.push') && !onclick.endsWith("'');")) { if ((title = onclick.split("'")[13])) return title; } for (let c of anchor.childNodes) { if (c.nodeName == '#text') { if ((title = c.nodeValue.trim())) return title; } } for (let s of anchor.getElementsByTagName('span')) { let txt = getTrimText(s); if (txt) { title = txt; break; } } if (!title || title == 't') { if ((title = getTrimText(anchor))) return title; } return title; } function addTitleAttrAll(nodes, verbose=false) { // a タグに子要素の img の alt から取ってきたタイトルを title 属性として追加 // ランキングのところは別 let length = nodes.length || nodes.snapshotLength; let getItem = nodes.item || nodes.snapshotItem; getItem = getItem.bind(nodes); for ( let i=0 ; i < length; i++ ) { let anchor = getItem(i); let title = getTitle(anchor); if (title) { anchor.title = title; if (verbose) { } } } } function addTitleAttr2Rankings(target) { // ランキング内商品 anchorに title= 追加 // DMM DVD通販 IdolTop: altがt、タイトルがa直下 (非固定spanのtail) // FANZA 動画 ビデオtop ranking[1:]: altなし、span(rank) a直下 title br latest let prefix = '.'; if (!target) { prefix = './/div[@id="side-rank-tab"]'; target = document.body; } const ranking = document.evaluate( prefix + '//li[div[a[not(@title) or @title=""]]]', target, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); const rankingLength = ranking.snapshotLength; for ( let i=0 ; i < rankingLength; i++ ) { let li = ranking.snapshotItem(i); let alt = li.getElementsByTagName('img')[0].getAttribute('alt'); if (!alt || alt == 't') alt = getTrimText(li); let textEl = li.querySelector('div > a'); if (textEl) textEl.title = alt; } } function createObserver(target, callback) { // MutationObserver の作成 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => callback(mutation)); }); for (let t of target()) { observer.observe(t, { childList: true, subtree: true }); } } function addTitleAttr2Anchors() { // とりあえず title のない画像つきリンクに一律処理 addTitleAttrAll( document.evaluate('.//a[.//img and not(@title)]', document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)); // カテゴリトップページランキング // 最初に一発やっとかないとあとで更新されないページがある addTitleAttr2Rankings(); // ページの動的変更を監視 // '.clist,#recent_check_list,#actorother_main,.d-boxslidelist,#recommend_parts,div[id^="list-product"],.mainList'), createObserver( () => document.querySelectorAll('body'), mutation => { let target = mutation.target console.log(target); addTitleAttrAll(document.evaluate( './/a[.//img and not(@title)]', target, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null) ); if (target.id.match(/(ranking|s-tb-sect)/)) { addTitleAttr2Rankings(target); } } ); } (function() { // load 後に追加される要素を待ってから let waitAppear = []; let waitDisappear = []; if (document.querySelector('#browserecommend,#browserecommend1')) { waitAppear = ['#list-history-min a img[alt]',]; } else if (document.querySelector('#recommend')) { waitAppear = ['#recommend_main li a img[alt]', '.d-modtogglelink-close,.d-modtogglelink-open']; } else if (document.querySelector('#recommend_all')) { waitAppear = ['#recent_check_list',]; } if (document.getElementsByClassName('loading').length) { waitDisappear = ['.loading',]; } if (waitAppear.length || waitDisappear.length) { // 要素が追加されない場合もあるので setInterval でタイムアウトするように const isExists = targets => document.querySelectorAll(targets).length; let waitId = null; let c = 1; const waiter = () => { let isAppeared = waitAppear.length ? waitAppear.every(t => isExists(t)) : true; let isDisappeared = waitDisappear.length ? waitDisappear.every(t => !isExists(t)) : true; if ((isAppeared && isDisappeared) || c > 15) { clearInterval(waitId); setTimeout(addTitleAttr2Anchors, 300); } c++; } waitId = setInterval(waiter, 200); } else { addTitleAttr2Anchors(); } })();