您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Changes the comment section's default linear mode to threaded mode.
当前为
// ==UserScript== // @name pixiv ツリー型コメント // @name:ja pixiv ツリー型コメント // @name:en pixiv Threaded Comments // @namespace https://gf.qytechs.cn/users/137 // @version 2.0.0 // @description Changes the comment section's default linear mode to threaded mode. // @description:ja 返信コメントを返信先の下に移動し、コメント欄を見やすく整理する // @match http://www.pixiv.net/member_illust.php?*mode=medium* // @match http://www.pixiv.net/novel/show.php?*id=* // @match http://www.pixiv.net/group/*?*id=* // @run-at document-start // @grant dummy // @icon data:image/vnd.microsoft.icon;base64,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 // @author 100の人 // @homepage https://gf.qytechs.cn/scripts/5291-pixiv-%E3%83%84%E3%83%AA%E3%83%BC%E5%9E%8B%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88 // @license Creative Commons Attribution 4.0 International Public License; http://creativecommons.org/licenses/by/4.0/ // ==/UserScript== (function () { 'use strict'; /** * ページの種類。 * @type {string} */ var pageType; switch (window.location.pathname) { case '/member_illust.php': pageType = 'illust'; break; case '/novel/show.php': pageType = 'novel'; break; case '/group/': case '/group/show.php': case '/group/comment.php': pageType = 'group'; break; default: return; } polyfill(); if (pageType !== 'group') { startScript(main, function (parent) { return parent.id === 'one_comment'; }, function (target) { return target.classList.contains(pageType === 'illust' ? 'layout-column-2' : 'worksOptionRight'); }, function () { return pageType === 'illust' ? document.querySelector('#one_comment .layout-column-2') : document.getElementsByClassName('worksOptionRight')[0]; }); } else { startScript(main, function (parent) { return parent.id === 'wrapper'; }, function (target) { return target.id === 'template-drawr-paint-ui'; }, function () { return document.getElementById('template-drawr-paint-ui'); }); } function main() { document.head.insertAdjacentHTML('beforeend', '<style>' + (pageType !== 'group' ? ' \ /*==================================== \ イラスト・小説のコメント欄 \ */ \ /*------------------------------------ \ 余白を修正 \ */ \ ._comment-items ._comment-item, \ ._comment-items ._comment-sticker-item { \ border-top: 1px solid #D6DEE5; \ display: flex; \ margin: initial; \ padding: initial; \ } \ ._comment-items ._comment-sticker-item { \ display: block; \ padding-bottom: 6px; \ } \ ._comment-items ._comment-item > .user-icon-container, \ ._comment-items .comment:first-child::before { \ /* アイコン */ \ flex-shrink: 0; \ position: initial; \ margin: 0.2em 0.4em; \ } \ ._comment-items .comment:first-child::before { \ /* 削除されたユーザーのアイコン */ \ content: ""; \ position: absolute; \ top: 0; \ left: 0; \ display: inline-block; \ width: 40px; \ height: 40px; \ background: url("http://source.pixiv.net/common/images/no_profile_s.png") 0% 0% / 100% content-box; \ opacity: 0.4; \ } \ ._comment-items .comment:first-child { \ margin-left: calc(40px + 1em); \ } \ ._comment-items .comment, \ ._comment-items .has-action-list .comment, \ ._comment-items .host-user .comment { \ /* アイコン以外の部分 */ \ flex-grow: 1; \ padding: 0; \ margin: 0.2em; \ } \ ._comment-items .meta { \ /* 名前・投稿日時 */ \ margin-bottom: initial; \ } \ #one_comment ._comment-sticker-item .sticker-item { \ /* スタンプ */ \ margin-top: 6px; \ margin-left: 6px; \ } \ ._comment-items .action-list { \ /* 返信する・削除するボタン */ \ position: absolute; \ top: 0; \ right: 0; \ } \ \ /*------------------------------------ \ 作者コメント強調方法の修正 \ */ \ ._comment-items .host-user .comment > * { \ /* 名前・投稿日時・返信先・スタンプ */ \ text-align: initial; \ } \ ._comment-items .host-user .body { \ /* 本文 */ \ float: initial; \ } \ ._comment-items .host-user { \ /* 背景色 */ \ background: lavenderblush; \ } \ \ /*------------------------------------ \ 返信コメント \ */ \ ._comment-items .tree > :nth-of-type(n+2) { \ margin-left: 2em; \ } \ ._comment-items .tree > :first-of-type.host-user { \ border-bottom: 1px solid #D6DEE5; \ margin-bottom: -1px; \ } \ \ /*==================================== \ イラスト・小説の返信ダイアログ \ */ \ /*------------------------------------ \ 余白を修正 \ */ \ ._comment-modal .comment { \ margin: initial; \ } \ ._comment-modal .comment, \ ._comment-modal .host-user .comment { \ padding-left: 90px; \ padding-right: 20px; \ } \ /*------------------------------------ \ 作者コメント強調方法の修正 \ */ \ ._comment-modal .host-user .user-icon-container { \ /* アイコン */ \ left: 20px; \ } \ ._comment-modal .host-user .comment > * { \ /* 名前・投稿日時・返信先・スタンプ */ \ text-align: initial; \ } \ ._comment-modal .host-user .body { \ /* 本文 */ \ float: initial; \ } \ ._comment-modal ._comment-item.host-user { \ /* 背景色 */ \ background: lavenderblush; \ } \ \ /*==================================== \ スタンプの表示方法の統一 \ */ \ ._comment-sticker-item .sticker { \ /* 6個連続した時の大きさに */ \ width: 67px; \ height: 67px; \ } \ .sticker-item .user-icon { \ /* 単体のスタンプを変換したアイテムのアイコン */ \ width: 100%; \ } \ .comment > .body > p > img { \ /* 単体の絵文字 */ \ width: 28px; \ height: initial; \ } \ ' + (typeof MozSettingsEvent !== 'undefined' ? ' \ /*==================================== \ URLの取得に失敗しているアイコン \ */ \ ._comment-items ._comment-item > .user-icon-container[data-profile_img="_s."] { \ background: url("http://source.pixiv.net/common/images/no_profile_s.png") 0% 0% / 100%; \ }' : '') : ' \ /*==================================== \ グループのコメント欄 \ */ \ /*------------------------------------ \ 区切り線 \ */ \ #page-group #timeline li.post div.comment div.post, \ #page-group #timeline li.post div.comment div.post ~ div.post { \ border-top: dashed 1px #DEE0E8; \ border-bottom: none; \ } \ #page-group #timeline li.post div.comment div.post::before { \ content: ""; \ position: absolute; \ top: 0; \ left: 0; \ right: 0; \ border-top: dashed 1px #FFFFFF; \ } \ #page-group #timeline li.post div.comment { \ border-bottom: dashed 1px #DEE0E8; \ } \ /*------------------------------------ \ 最初のコメント \ */ \ #page-group #timeline li.post div.comment > div.post:first-of-type, \ #page-group #timeline li.post div.comment > .tree:first-of-type > div.post:first-of-type, \ #page-group #timeline li.post div.comment > div.post:first-child::before, \ #page-group #timeline li.post div.comment > .tree:first-child > div.post:first-of-type::before { \ /* 一番上のコメント */ \ /* 「以前のコメントを見る」ボタンがある時は、白色の破線は消さない */ \ border-top: none; \ } \ /*------------------------------------ \ 返信コメント \ */ \ #page-group #timeline li.post div.comment .tree > :nth-of-type(n+2) { \ margin-left: 2em; \ } \ #page-group #timeline li.post div.comment .tree .postbody { \ width: initial; \ } \ ') + '</style>'); /** * コメントリスト要素。 * @type {HTMLDivElement} */ var commentList; /** * コメント欄のすべてのスタンプを格納するリスト。 * @type {?HTMLDivElement} */ var allStickerList = null; /** * スタンプの返信ボタン。 * @type {?HTMLUListElement} */ var itemActionsTemplate = document.getElementsByClassName('_item-actions')[0]; if (pageType !== 'novel') { // 小説ページ以外なら /** * {@link MutationObserver#observe}の第2引数に指定するオブジェクト。 * @type {MutationObserverInit} */ var observerOptions = { childList: true, }; if (pageType === 'illust') { // イラストページ commentList = document.getElementsByClassName('_comment-items')[0]; } else { // グループページ commentList = document.getElementById('timeline'); observerOptions.subtree = true; } moveAllReplyComments(); // コメントの増減を監視する new MutationObserver(function (mutations, observer) { var firstMutationRecord = mutations[0]; var firstAddedNode = firstMutationRecord.addedNodes[0]; if (firstAddedNode) { // コメントが増えていれば // 監視を一旦停止 if (pageType === 'illust' && !firstMutationRecord.previousSibling) { // イラストページへのコメント投稿時 firstAddedNode.style.display = ''; } // 監視を一旦停止して返信コメントを移動する observer.disconnect(); moveAllReplyComments(); observer.observe(commentList, observerOptions); } }).observe(commentList, observerOptions); } /** * すべての返信コメントを返信先コメントの下に移動する。 */ function moveAllReplyComments() { if (pageType === 'illust') { // イラストページ // スタンプを一か所にまとめる if (allStickerList) { // まとめ先のリストが存在すれば if (allStickerList.nextElementSibling) { // コメント欄の一番下以外の場所にあれば、移動する commentList.appendChild(allStickerList); } } /** * スタンプリスト、またはスタンプリストに含まれないスタンプ。 * @type {HTMLDivElement} */ for (var stickerListOrComment of commentList.querySelectorAll('._comment-sticker-item, ._comment-item .sticker-container')) { if (!allStickerList) { // まとめ先のリストがまだ作成されていなければ、作成 commentList.insertAdjacentHTML('beforeend', '<div class="_comment-sticker-item sticker-container sticker-6-item"></div>'); allStickerList = commentList.lastChild; } if (stickerListOrComment.classList.contains('_comment-sticker-item')) { // スタンプリストなら if (stickerListOrComment !== allStickerList) { // まとめ先のリストでなければ stickerListOrComment.remove(); for (var sticker of stickerListOrComment.childNodes) { allStickerList.appendChild(sticker); } } } else { // スタンプなら /** * コメントアイテム。 * @type {HTMLDivElement} */ var commentItem = stickerListOrComment.parentNode.parentNode; /** * 返信先コメント投稿者名 (作者コメントの場合のみ)。 * @type {?HTMLSpanElement} */ var repliedUserName = commentItem.classList.contains('host-user') ? commentItem.getElementsByClassName('reply-to')[0] : null; if (repliedUserName) { // 作者コメント、かつ返信コメントなら、返信先のコメントIDを要素に保存 commentItem.setAttribute('data-reply-to-id', repliedUserName.dataset.id); } // コメントアイテムをスタンプアイテムに変換 commentItem.classList.remove('_comment-item'); commentItem.classList.add('sticker-item'); commentItem.replaceChild(commentItem.getElementsByClassName('sticker')[0], commentItem.getElementsByClassName('comment')[0]); // 返信ボタンを追加 if (itemActionsTemplate) { commentItem.appendChild(itemActionsTemplate.cloneNode(true)); } else { commentItem.insertAdjacentHTML('beforeend', '<ul class="_item-actions"> \ <li class="reply item"> \ <i class="_icon-12 _icon-reply"></i> \ </li> \ </ul>'); itemActionsTemplate = commentItem.lastChild; } // スタンプリスト内にスタンプアイテムを移動 allStickerList.appendChild(commentItem); } } // 返信コメントの移動 /** * 返信先コメント投稿者名、または返信スタンプ。 * @type {HTMLSpanElement} */ for (var repliedUserNameOrReplyStickerItem of commentList.querySelectorAll('.reply-to, .sticker-item[data-reply-to-id]')) { /** * 返信スタンプなら真。 * @type {String} */ var replySticker = repliedUserNameOrReplyStickerItem.classList.contains('sticker-item'); /** * 返信先コメントのID。 * @type {string} */ var repliedCommentId = repliedUserNameOrReplyStickerItem.dataset[replySticker ? 'replyToId' : 'id']; /** * 返信先コメント。 * @type {?HTMLDivElement} */ var repliedComment = commentList.querySelector('._comment-item[data-id="' + repliedCommentId + '"]'); if (repliedComment) { // 返信先コメントが存在すれば /** * 返信コメント。 * @type {?HTMLDivElement} */ var replyComment = null; if (replySticker) { // スタンプなら、スタンプリストに変換する replyComment = allStickerList.cloneNode(); replyComment.classList.add('host-user'); replyComment.appendChild(repliedUserNameOrReplyStickerItem); } else { // 通常のコメントなら replyComment = repliedUserNameOrReplyStickerItem.parentNode.parentNode; // 返信先コメント投稿者名を削除 repliedUserNameOrReplyStickerItem.remove(); } moveReplyComment(repliedComment, replyComment); } } } else { // グループページ var repliedUserNames = document.querySelectorAll('.body > p > a'); for (var i = repliedUserNames.length - 1; i >= 0; i--) { /** * 返信先コメント投稿者名。 * @type {HTMLSpanElement} */ var repliedUserName = repliedUserNames[i]; /** * 返信先コメント。 * @type {?HTMLDivElement} */ var repliedComment = document.getElementById(repliedUserName.hash.replace('#', '')); if (repliedComment) { // 返信先コメントが存在すれば moveReplyComment(repliedComment, repliedUserName.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode); // 返信先コメント投稿者名を削除 repliedUserName.parentNode.remove(); } } } } /** * 返信コメントを返信先コメントの下に移動する。 * @param {HTMLDivElement} repliedComment - 返信先コメント。 * @param {HTMLDivElement} replyComment - 返信コメント。 */ function moveReplyComment(repliedComment, replyComment) { if (!replyComment.previousElementSibling) { var parent = replyComment.parentNode; if (parent && parent.classList.contains('tree')) { // 返信コメントにラッパー要素が存在すれば replyComment = parent; } } /** * 返信先コメントと返信コメントを格納するラッパー要素。 * @type {HTMLDivElement} */ var tree = null; if (!repliedComment.previousElementSibling) { var parent = repliedComment.parentNode; if (parent.classList.contains('tree')) { // ラッパー要素がすでに存在すれば tree = parent; } } if (!tree) { // ラッパー要素が存在しなければ // ラッパー要素を作成 tree = document.createElement('div'); tree.classList.add('tree'); // 返信先コメントをラッパー要素に置換 repliedComment.parentNode.replaceChild(tree, repliedComment); // 返信先コメントをラッパーに追加 tree.appendChild(repliedComment); } // 返信コメント移動 if (pageType === 'illust') { // イラストページ tree.insertBefore(replyComment, repliedComment.nextSibling); } else { // グループページ tree.appendChild(replyComment); } } } /** * 挿入された節の親節が、目印となる節の親節か否かを返すコールバック関数。 * @callback isTargetParent * @param {(Document|Element)} parent * @returns {boolean} */ /** * 挿入された節が、目印となる節か否かを返すコールバック関数。 * @callback isTarget * @param {(DocumentType|Element)} target * @returns {boolean} */ /** * 目印となる節が文書に存在するか否かを返すコールバック関数。 * @callback existsTarget * @returns {boolean} */ /** * 目印となる節が挿入された直後に関数を実行する。 * @param {Function} main - 実行する関数。 * @param {isTargetParent} isTargetParent * @param {isTarget} isTarget * @param {existsTarget} existsTarget * @param {Object} [callbacksForFirefox] * @param {isTargetParent} [callbacksForFirefox.isTargetParent] - Firefoxにおける{@link isTargetParent}。 * @param {isTarget} [callbacksForFirefox.isTarget] - Firefoxにおける{@link isTarget}。 * @param {number} [timeoutSinceStopParsingDocument=0] - DOM構築完了後に監視を続けるミリ秒数。 * @version 2014-11-25 * @global */ function startScript(main, isTargetParent, isTarget, existsTarget) { /** * {@link checkExistingTarget}で{@link startMain}を実行する間隔(ミリ秒)。 * @constant {number} */ var INTERVAL = 10; /** * {@link checkExistingTarget}で{@link startMain}を実行する回数。 * @constant {number} */ var LIMIT = 500; /** * 実行済みなら真。 * @type {boolean} */ var alreadyCalled = false; // 指定した節が既に存在していれば、即実行 startMain(); if (alreadyCalled) { return; } // FirefoxのMutationObserverは、HTMLのDOM構築に関して要素をまとめて挿入したと見なすため、isTargetParent、isTargetを変更 var callbacksForFirefox = arguments[4]; if (callbacksForFirefox && typeof MozSettingsEvent !== 'undefined') { isTargetParent = callbacksForFirefox.isTargetParent || isTargetParent; isTarget = callbacksForFirefox.isTarget || isTarget; } var observer = new MutationObserver(mutationCallback); observer.observe(document, { childList: true, subtree: true, }); var timeoutSinceStopParsingDocument = arguments[5] || 0; if (document.readyState === 'complete') { // DOMの構築が完了していれば onDOMContentLoaded(); } else { document.addEventListener('DOMContentLoaded', onDOMContentLoaded); } /** * {@link startMain}を実行し、スクリプトが開始されていなければさらに{@link timeoutSinceStopParsingDocument}ミリ秒待機し、 * スクリプトが開始されていなければ{@link stopObserving}を実行する。 */ function onDOMContentLoaded() { startMain(); if (timeoutSinceStopParsingDocument === 0) { if (!alreadyCalled) { stopObserving(); } } else { window.setTimeout(function () { if (!alreadyCalled) { stopObserving(); } }, timeoutSinceStopParsingDocument); } } /** * 目印となる節が挿入されたら、監視を停止し、{@link checkExistingTarget}を実行する。 * @param {MutationRecord[]} mutations - A list of MutationRecord objects. * @param {MutationObserver} observer - The constructed MutationObserver object. */ function mutationCallback(mutations, observer) { for (var mutation of mutations) { var target = mutation.target; if (target.nodeType === Node.ELEMENT_NODE && isTargetParent(target)) { // 子が追加された節が要素節で、かつその節についてisTargetParentが真を返せば for (var addedNode of mutation.addedNodes) { if (addedNode.nodeType === Node.ELEMENT_NODE && isTarget(addedNode)) { // 追加された子が要素節で、かつその節についてisTargetが真を返せば observer.disconnect(); checkExistingTarget(0); return; } } } } } /** * {@link startMain}を実行し、スクリプトが開始されていなければ再度実行。 * @param {number} count - {@link startMain}を実行した回数。 */ function checkExistingTarget(count) { startMain(); if (!alreadyCalled && count < LIMIT) { window.setTimeout(checkExistingTarget, INTERVAL, count + 1); } } /** * 指定した節が存在するか確認し、存在すれば{@link stopObserving}を実行しスクリプトを開始。 */ function startMain() { if (!alreadyCalled && existsTarget()) { stopObserving(); main(); } } /** * 監視を停止する。 */ function stopObserving() { alreadyCalled = true; if (observer) { observer.disconnect(); } document.removeEventListener('DOMContentLoaded', onDOMContentLoaded); } } /** * WHATWG仕様のPolyfill。 */ function polyfill() { // Polyfill for Opera and Google Chrome if (!('@@iterator' in NodeList.prototype) && !(Symbol.iterator in NodeList.prototype)) { /** @version polyfill-2014-12-07 */ Object.defineProperties(NodeList.prototype, /** @lends NodeList# */ { /** * @returns {Iterator.<Array.<number, Node>>} * @function */ entries: { writable: true, enumerable: false, configurable: true, value: function* () { for (var i = 0, l = this.length; i < l; i++) { yield [i, this[i]]; } } }, /** * @returns {Iterator.<number>} * @function */ keys: { writable: true, enumerable: false, configurable: true, value: function* () { for (var i = 0, l = this.length; i < l; i++) { yield i; } } }, /** * @returns {Iterator.<Node>} * @function */ values: { writable: true, enumerable: false, configurable: true, value: function* () { for (var i = 0, l = this.length; i < l; i++) { yield this[i]; } } }, }); /** * @returns {Iterator.<Node>} * @function NodeList#@@iterator */ Object.defineProperty(NodeList.prototype, Symbol.iterator, { writable: true, enumerable: false, configurable: true, value: function* () { for (var i = 0, l = this.length; i < l; i++) { yield this[i]; } } }); } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址