)\s*(((〉|》|>|>)[^>]+))(?!([^<]+)?>)/gmi, `$1$2`).replace(/\s*(((〉|》|>|>)[^>]+))(?!([^<]+)?>)/gmi, `$1`).replace(/
\s*(((〉|》|>|>)[^>]+))(?!([^<]+)?>)/gmi, `
$1`).replace(/
\s*(((〉|》|>|>)[^>]+))(?!([^<]+)?>)/gmi, `
$1`) } }); // 引用に着色,タグの外側だけ置き換え // これをやるとシステムのサムネ添付が終わる setTimeout(() => { popuponquote() }, location.href.match0(/shitaraba/) ? 2000 : 0) } setTimeout(() => { elegeta('//a[@class="reply_link"]').forEach(e => e.setAttribute("onclick", "return false;")) }, location.href.match0(/shitaraba/) ? 2000 : 0) document.addEventListener("click", c => { let word if (c?.target?.matches(".quoteSpeechBalloon")) { word = c?.target?.dataset?.quoteno } else { let e = c.target.closest(".t5quote,.allpopup,.reply_link"); if (e) { word = e.textContent.replace(/^〉+|^》+|^>+|^>+/gm, "").trim() } } if (word) { let t = (word.match0(/^[0-9-]+$/) && eleget0(NEW5CH ? `.post[id="${word?.match0(/^\d+/)?.replace(/post/,"")}"]` : `//div[@id="${word?.match0(/^\d+/)?.replace(/post/,"")}"]`)) || elegeta('.message,.post-content').filter(f => !f.closest(".ch5pu")).find(c => c.textContent.indexOf(word) !== -1); if ($(t).is(":hidden")) $(t.closest(".post")).show(0).css({ "display": "table" }) // 学園祭で消していたら出す t?.scrollIntoView({ behavior: "smooth", block: "center", inline: "center" }); $(t.closest(".post")).effect("highlight", 750); } }) } // h抜きのURLをリンクにする function hNukiURLHokan() { if (IIS == 2) { $(".post-content,.message").prepend('
'); addstyle.add(`.imgbox{text-align:right; float:right;clear:both; max-width:66%;vertical-align:bottom;} .post-content,.message{overflow-y:auto;clear:both}`) } if (IIS == 1) { $(".post-content,.message").append('
') } elegeta('.post .post-content img:not([src*="//img.5ch.net/ico/"])').forEach(e => e.dataset.gakusai = "1"); [...document.querySelectorAll(".post .message .escaped:not([data-urlcomplemented]),dd:not([data-urlcomplemented]),.post .post-content:not([data-urlcomplemented])")].forEach(function(ele) { [...ele.childNodes].filter(e => e.nodeType == 3).forEach(obj => { let html = obj.textContent?.trim() let url2 = html.match0(/^(t?tps?:\/\/[\w\/:%#\$&\?\(\)~\.=\+\-]+)$/) if (url2) { let url = html.replace(/^t?(tps?:\/\/[\w\/:%#\$&\?\(\)~\.=\+\-]+)$/, `ht$1`); if (/\.(jpg|jpeg|png|gif|bmp|webp|mp4|webm|mkv)$/i.test(url)) ele.dataset.gakusai = "1"; let dom = document.createElement("a") obj.replaceWith(dom) dom.outerHTML = `${sani(url2)}`; } }) }) } function setFloatKakikomi2({ textareaXP = '//form/p/textarea[@name="MESSAGE"]', submitbuttonXP = '//input[@class="submitbtn btn"]', wid = "70%", minwid = 900 } = {}) { var mes = eleget0(textareaXP); if (mes) { mes.addEventListener("input", () => floatKakikomi2({ textareaXP: textareaXP, submitbuttonXP: submitbuttonXP, wid: wid, minwid: minwid })); mes.addEventListener("focus", () => floatKakikomi2({ textareaXP: textareaXP, submitbuttonXP: submitbuttonXP, wid: wid, minwid: minwid })); resListen = 1; } } // 書き込み欄調整、クリックでフロート化 function floatKakikomi2({ string = null, addMode = 0, command = "", textareaXP = '//form/p/textarea[@name="MESSAGE"]', submitbuttonXP = '//input[@class="submitbtn btn"]', wid = '70%', minwid = 900, preventFocus = 0 } = {}) { var textarea = eleget0(textareaXP); if (!textarea) return var submitbutton = eleget0(submitbuttonXP) if (!resFloat) { $(window).resize(() => { $(textarea).css({ "width": wid, "min-width": Math.min(minwid, (window.innerWidth - 100)) + "px", "max-width": (window.innerWidth - 100) + "px" }).attr("wrap", "on").attr("tabIndex", "2"); kakikomiStretch2(textareaXP, "resetHeight") }); } resListen || setFloatKakikomi2() resFloat = true; let curRes = $(textarea).val(); $(document.body).attr("tabIndex", "4") $(textarea).css({ "overflow-x": "hidden", "z-index": "10", "position": "fixed", "right": "1em", "bottom": "3em", "height": "auto" }).attr("tabIndex", "2"); $(textarea).css({ "width": wid, "min-width": Math.min(minwid, (window.innerWidth - 100)) + "px", "max-width": (window.innerWidth - 100) + "px" }).attr("wrap", "on").attr("tabIndex", "2").attr("floated", ""); $(submitbutton).css({ "z-index": "10", "position": "fixed", "right": "1em", "bottom": "0em" }).attr("tabIndex", "3").attr("floated", ""); //$(`input[type="file"][name="upfile"]`).css({ "z-index": "1000", "position": "fixed", "right": "48em", "left": "auto", "bottom": "3px", "height": "auto", "padding": "0.1em 0.2em", "border": "2px solid #dddddd", "background-color": "#ffffff" }) $(eleget0('input[type="file"][name="upfile"]') || eleget0('input[type="file"][id="upup"]') || eleget0('input[type="file"]#up2input')).css({ "z-index": "1000", "position": "fixed", "right": "48em", "left": "auto", "bottom": "3px", "height": "auto", "padding": "0.1em 0.2em", "border": "2px solid #dddddd", "background-color": "#ffffff" }) // 添付File→あぷにアップ→futaba-add-uploaderの順に最初に見つかったものを右下に移動させる //$(eleget0('input[type="file"][id="upup"]') || eleget0('input[type="file"]#up2input') || eleget0('input[type="file"][name="upfile"]')).css({ "z-index": "1000", "position": "fixed", "right": "48em", "left": "auto", "bottom": "3px", "height": "auto", "padding": "0.1em 0.2em", "border": "2px solid #dddddd", "background-color": "#ffffff" }) // あぷにアップ→futaba-add-uploader→添付Fileの順に最初に見つかったものを右下に移動させる GM.addStyle('#ftbl,#ftb2,.ftbl,.ftb2{margin:0px 0px 0px 1em !important; left:1em !important;}') if (string > "") $(textarea).val((addMode ? curRes + ((curRes == "" || curRes.slice(-1) == "\n") ? "" : "\n") : "") + string); $(textarea).attr("stretchabletextarea", "1") if (!preventFocus) { $(textarea).focus() } else { textarea.blur() } // .idw:IDスレかIPスレ警告があればしない if ((textarea).value == "" || command === "resetHeight") textarea.rows = MINIMUM_ROWS; kakikomiStretch2(textareaXP); } function kakikomiStretch2(xp, command = "") { if ($(elegeta(xp)).is(":hidden")) return let target = eleget0(xp); var targetvalue = target ? target.value : "" if (command === "resetHeight" || targetvalue?.length < 100 || targetvalue?.match(/\n/gm)?.length < 5) target.rows = MINIMUM_ROWS; let lineHeight = Number(target.getAttribute("rows")); let height = target.scrollHeight; //+12; let clientHeight = Math.min(document.documentElement.clientHeight, window.innerHeight) - 165; for (let i = 0; i < 90 && (height >= target.offsetHeight) && target.offsetHeight < clientHeight; i++) { lineHeight++; target.setAttribute("rows", lineHeight); } displayLineLimit(target); return target; } function displayLineLimit(target) { let line = target.value.split(/\r\n|\r|\n/).length; if (ld(".2chan.net")) { if (line > 15) { target.classList.remove("fchformsizeover"); target.classList.add("fchformlineover"); } else if (target.value.split("\n").reduce((a, b) => Math.max(getWidth(b), a), 0) >= 801) target.classList.add("fchformsizeover"); else { target.classList.remove("fchformlineover"); target.classList.remove("fchformsizeover"); } } else { if (line_number && message_count) { if (line > line_number * 2) { target.classList.remove("fchformsizeover"); target.classList.add("fchformlineover"); } else if ((new Blob([target.value]).size) > message_count) target.classList.add("fchformsizeover"); else { target.classList.remove("fchformlineover"); target.classList.remove("fchformsizeover"); } } } } function getWidth(str) { var canvas = document.createElement('canvas') let width = canvas.getContext('2d').measureText(str).width * 16 / 10; canvas.remove() return width; } function sortDescendMiddle(array) { return array; /*return array.sort((a, b) => { return Math.abs(a.getBoundingClientRect().top - document.documentElement.clientHeight / 2) > Math.abs(b.getBoundingClientRect().top - document.documentElement.clientHeight / 2) ? 1 : -1 });*/ } // 画像と動画をインライン埋め込み function imageUmekomi() { if (eleget0('.ch5pu')) return; var i = 0; let IIScss = (IIS >= 2 ? "margin:0.3em 0 0 1em;" : "margin:0.4em 1em 0 0;") GF.headerbottom = eleget0('.stickymenu')?.getBoundingClientRect()?.bottom || 0; sw1("removeSysThumbs"); for (let a of sortDescendMiddle(elegeta('a[imge="af"]>div[div="thumb5ch"]'))) { if (isinscreen(a)) setTimeout((function(a) { return function() { { a.remove(); } } })(a), WAIT_IMAGE_EMBED_INTERVAL * 3 / NUMBER_IMAGE_EMBED_AT_ONCE) } sw2("removeSysThumbs"); // 画像埋め込み sw1("umegazo") for (let ele of sortDescendMiddle(elegeta('a:not([imge]),a[href*=".nicovideo.jp"]:not([nde]),a[href*="//nico.ms/sm"]:not([nde]),a[href*="youtube.com"]:not([yte]),a[href*="youtu.be"]:not([yte]),a[href*="ttps://video.twimg.com/ext_tw_video/"]:not([yte]),a[href*="ttps://i.imgur.com/"][href*=".mp4"]:not([yte])'))) { if (ele.matches('a:not([imge])')) { let isImg = 0; var url = ele.href || ($(ele).text()); url = url.replace(/^t?(tps?:\/\/)/m, "ht$1"); try { var urlImg = decodeURIComponent(url.replace(/https?:\/\/jump\.5ch\.net\/\?|https?:\/\/jbbs\.shitaraba\.net\/bbs\/link\.cgi\?url=/, "")) //.replace(/https?:\/\/jbbs\.shitaraba\.net\/bbs\/link\.cgi\?url=/,""); } catch (e) { var urlImg = url.replace(/https?:\/\/jump\.5ch\.net\/\?|https?:\/\/jbbs\.shitaraba\.net\/bbs\/link\.cgi\?url=/, "") } if ($(ele).text().match(/\.jpg|\.jpeg|\.png|\.gif|\.bmp|\.webp/)) { isImg = 1; } else { isImg = 0; } if (!isImg) ele.setAttribute("imge", "!i"); if ((!isinscreen(ele))) continue; // 画面内に無い if (isImg) { //notifyMe(url)//notifyMe(decodeURIComponent(urlImg)) let next = ele.children ? ele.children[0] : null; if (next && next.tagName === "DIV") { // システムのサムネイルあり if (ALTERNATIVE_THUMBNAIL) next.outerHTML = '
'; ele.setAttribute("imge", "rp"); } else { // if ( /^ttp/.test(ele.textContent)){ // システムのサムネ添付はhtmlに変更があると諦めて中断される ele.classList.add("inlined"); //style.color="#70a"; if (IIS >= 1) { EXTEST == 0 && $(``).hide().appendTo(eleget0('.imgbox', ele.closest(`.post,article`))).show(222); EXTEST == 1 && $(``).hide().appendTo(eleget0('.imgbox', ele.closest(`.post,article`))).on("load", e => requestAnimationFrame(() => $(e.target).show(222))); } else { $('
').hide().insertAfter(ele).show(222); } ele.setAttribute("imge", "af"); } //if (++i >= NUMBER_IMAGE_EMBED_AT_ONCE) break; // 一度に設定枚数ずつしかやらない } } sw2("umegazo") if (eleget0('.ch5pu')) return; sw1("umedouga") var i = 0; // ニコ動埋め込み(PrivacyBadger等は要Disable) if (ele.matches('a[href*="www.nicovideo.jp/watch"]:not([nde]),a[href*="sp.nicovideo.jp/watch"]:not([nde]),a[href*="//nico.ms/sm"]:not([nde])')) { //if ((!isinscreen(ele))) continue; // 画面内に無い //if (!isinscreen(ele) && Date.now() - (GF?.lateVideo || 0) < 5000) continue; else GF.lateVideo = Date.now() // 画面内にない&5秒未満 let url = ele.href; ele.setAttribute("nde", "nde"); var nico = url.match(/h?t?tps?:\/\/(?:www\.|sp\.)?nicovideo.jp\/watch\/(.*)/i); //var nico = url.match(/h?t?tps?:\/\/(?:www\.)?nicovideo.jp\/watch\/(.*)/i); if (!nico) var nico = url.match(/h?t?tps:\/\/nico\.ms\/(.*)/i); if (!nico) continue; //$(`
`).hide().insertAfter(ele).show(222) // 埋め込み外部プレイヤー版 ele.classList.add("inlined"); //style.color="#70a"; if (IIS >= 1) { $(``).hide().appendTo(eleget0('.imgbox', ele.closest(`.post,article`))).show(222) // 埋め込み外部プレイヤー版 } else { $(`
`).hide().appendTo(ele).show(222); // 埋め込み外部プレイヤー版 } //if (++i >= (NUMBER_VIDEO_EMBED_AT_ONCE)) break; // 一度に設定枚数ずつしかやらない // break; // 一度に1つずつしかやらない } sw2("umedouga") sw1("umeYT") // youtube埋め込み if (ele.matches('a[href*="youtube.com"]:not([yte]),a[href*="youtu.be"]:not([yte])')) { //if ((!isinscreen(ele))) continue; // 画面内に無い let url = ele.href?.replace(/(?:https?\:\/\/)?jump.5ch.net\/\?/, ""); ele.setAttribute("yte", "yte"); var sm = url.split(/\s/).map(v => { return [...v?.matchAll(/^(?:h?t?tps?:\/\/)?(?:youtu\.be\/|(?:m\.|www\.|)?youtube\.com\/(?:shorts\/|watch\?v=|embed\/|live\/))([a-zA-Z0-9_\-]{11})(?![a-zA-Z0-9_\-]{1})|^(?:h?t?tps?:\/\/)?www\.youtube\.com\/(?:watch_videos\?video_ids=|embed\/\?playlist=)([a-zA-Z0-9_\-,]{11,600})/gmi)]?.map(c => c.slice(1, 999)) })?.flat()?.flat()?.filter(w => w)?.map(v => v?.split(","))?.flat() // 書式が混在していても登場順に収納する if (!sm.length) continue; var pl = url.match0(/[\&\?]list=([a-zA-Z0-9_\-]+)/); pl = pl ? `?list=${pl}` : ""; var stime = url.match0(/[\&\?]t=(\d+)/); stime = stime ? `${pl?"&":"?"}start=${stime}` : ""; var url2 = sm.length == 1 ? `https://www.youtube.com/embed/${sm[0]}${pl}${stime}` : `https://www.youtube.com/embed/?playlist=${sm.join(",")}`; if (IIS >= 1) { ele.classList.add("inlined"); //style.color="#70a"; $(``).hide().appendTo(eleget0('.imgbox', ele.closest(`.post,article`))).show(222); } else { $(`

`).hide().appendTo(ele).show(222); } //if (++i >= (NUMBER_VIDEO_EMBED_AT_ONCE)) break; // 一度に設定枚数ずつしかやらない }; sw2("umeYT") // video.twimg埋め込み if (ele.matches('a[href*="ttps://video.twimg.com/ext_tw_video/"]:not([yte]),a[href*="ttps://i.imgur.com/"][href*=".mp4"]:not([yte])')) { //if ((!isinscreen(ele))) continue; // 画面内に無い let url = ele.innerText; url = url.replace(/^ttp/i, "http"); ele.setAttribute("yte", "yte"); var poster = url.match0('https://i.imgur.com/') ? ` poster="${url.replace(/\.mp4/,".jpg")}" ` : ""; ele.classList.add("inlined"); //style.color="#70a"; if (IIS >= 1) { //alert(url) $(``).hide().appendTo(eleget0('.imgbox', ele.closest(`.post,article`))).show(222) } else { $(`

`).hide().appendTo(ele).show(222) } //if (++i >= NUMBER_VIDEO_EMBED_AT_ONCE) break; // 一度に設定枚数ずつしかやらない // break; // 一度に1つずつしかやらない }; sw2("umeVideoTwimg") } } function videoUmekomi() {}; // eleはスクロール画面内に入ってる? function isinscreen(ele) { if (!ele) return; //return (eler.top > 0 - inlineImageThumbnailPreloadRadius && eler.left > 0 && eler.left < document.documentElement.clientWidth && eler.top < Math.min(window.innerHeight, document.documentElement.clientHeight) + inlineImageThumbnailPreloadRadius); if (IIS == 0) { var eler = ele.getBoundingClientRect(); return (eler.top > GF?.headerbottom && eler.left > 0 && eler.left < document.documentElement.clientWidth && eler.top < Math.min(window.innerHeight, document.documentElement.clientHeight) + inlineImageThumbnailPreloadRadius); // 先読みは画面より下側だけ(上に追加するとスクロールがずれるので) } if (IIS >= 1) { var eler = (ele?.closest(".post") || ele).getBoundingClientRect(); return (eler.bottom - 7 > GF?.headerbottom && eler.left > 0 && eler.left < document.documentElement.clientWidth && eler.top < Math.min(window.innerHeight, document.documentElement.clientHeight) + inlineImageThumbnailPreloadRadius); // 先読みは画面より下側だけ(上に追加するとスクロールがずれるので) } } function elegeta(xpath, node = document) { if (!xpath || !node) return []; let xpath2 = xpath.replace(/:inscreen|:visible|:text\*=[^:]*/g, "") // text*=~中で:は使えない let array = [] try { if (!/^\.?\//.test(xpath)) { array = [...node.querySelectorAll(xpath2)] } else { var snap = document.evaluate("." + xpath2, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null) let l = snap.snapshotLength for (var i = 0; i < l; i++) array[i] = snap.snapshotItem(i) } if (/:visible/.test(xpath)) array = array.filter(e => e.offsetHeight) else if (/:inscreen/.test(xpath)) array = array.filter(e => { var eler = e.getBoundingClientRect(); return (eler.bottom >= 0 && eler.right >= 0 && eler.left <= document.documentElement.clientWidth && eler.top <= document.documentElement.clientHeight) }) // 画面内に1ピクセルでも入っている if (/:text\*=./.test(xpath)) { let text = xpath.replace(/^.*:text\*=([^:]*)$/, "$1"); if (text) array = array.filter(e => new RegExp(text).test(e?.textContent)) } } catch (e) { alert(`XPath/CSS構文にエラーがあるかもしれません\n2023/12以前にインストールしたFirefoxを使っている場合はabout:configでlayout.css.has-selector.enabled を true にすると解決するかもしれません\n\n${e}\n\n${xpath}`); return []; } // } catch (e) { return []; } return array } function eleget0(xpath, node = document) { if (!xpath || !node) return null; if (/:inscreen|:visible|:text\*=/.test(xpath)) return elegeta(xpath, node)?.shift(); if (!/^\.?\//.test(xpath)) return node.querySelector(xpath); try { var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); return ele.snapshotLength > 0 ? ele.snapshotItem(0) : null; } catch (e) { alert(`XPath/CSS構文にエラーがあるかもしれません\n2023/12以前にインストールしたFirefoxを使っている場合はabout:configでlayout.css.has-selector.enabled を true にすると解決するかもしれません\n\n${e}\n\n${xpath}`); return null; } // } catch (e) { alert(e + "\n" + xpath + "\n" + JSON.stringify(node)); return null; } } function xa(xpath, node = document) { if (!xpath) return []; if (xpath.match(/^\//)) { try { var array = []; var ele = document.evaluate("." + xpath, node, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); let l = ele.snapshotLength; for (var i = 0; i < l; i++) array[i] = ele.snapshotItem(i); return array; } catch (e) { return []; } } else { return $(xpath); } } function sw1(s) { if (DEBUG_TIMER) console.time(s); } function sw2(s) { if (DEBUG_TIMER) console.timeEnd(s); } function pref(name, store = null) { // prefs(name,data)で書き込み(数値でも文字列でも配列でもオブジェクトでも可)、prefs(name)で読み出し if (store === null) { // 読み出し let data = GM_getValue(name) || GM_getValue(name); if (data == undefined) return null; // 値がない if (data.substring(0, 1) === "[" && data.substring(data.length - 1) === "]") { // 配列なのでJSONで返す try { return JSON.parse(data || '[]'); } catch (e) { alert("データベースがバグってるのでクリアします\n" + e); pref(name, []); return; } } else return data; } if (store === "" || store === []) { // 書き込み、削除 GM_deleteValue(name); return; } else if (typeof store === "string") { // 書き込み、文字列 GM_setValue(name, store); return store; } else { // 書き込み、配列 try { GM_setValue(name, JSON.stringify(store)); } catch (e) { alert("データベースがバグってるのでクリアします\n" + e); pref(name, ""); } return store; } } function popup(text, color = "#6080ff") { text = String(text); text = text.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/`/g, '`').replace(//g, ">").replace(/\n/gm, "
") var e = document.getElementById("hzbox"); if (e) { e.remove(); } var e = document.body.appendChild(document.createElement("span")); e.innerHTML = '/gm, "\\n") + '\"; document.body.appendChild(a); a.select(); document.execCommand(\"copy\"); a.parentElement.removeChild(a);\'">' + text + ''; setTimeout((function(e) { return function() { e.remove(); } })(e), 5000); } function popup2(text, i = 0, color = "#6080ff") { text = text.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/`/g, '`').replace(//g, ">").replace(/\n/gm, "
") var mae = eleget0('//span[@id="yhmbox"]'); if (maet && mae) { mae.remove(); clearTimeout(maet); } let bgcol = color var ele = $('' + text + '').appendTo('body'); maet = setTimeout(function() { var mae = eleget0('//span[@id="yhmbox"]'); if (mae) { mae.remove(); } }, 5000); $(ele).attr("title", "クリックでこのガイドを一時的に消す").click(function() { $(this).fadeOut(200).queue(function() { $(this).remove(); clearTimeout(maet); }) }); } function notifyMe(body, title = "") { if (!("Notification" in window)) return; else if (Notification.permission == "granted") new Notification(title, { body: body }); else if (Notification.permission !== "denied") Notification.requestPermission().then(function(permission) { if (permission === "granted") new Notification(title, { body: body }); }); } // >~にポップアップ function popuponquote() { // 引用ホバー if (/\.shitaraba\.net\/bbs\/read_archive.cgi\//.test(location.href) && eleget0('//HTML/BODY/DL[1]')) { eleget0('//HTML/BODY/DL[1]').id = "thread-body" } if (eleget0('//div[@class="post" and not(@id)]')) elegeta('.date').forEach(e => { e.closest('.post').id = e.textContent.trim().match0(/^(\d+)\s:/) || ""; }) var latestHover; //var mesEleA = elegeta(NEW5CH ? 'article.post .post-content' : '.thread .message,#thread-body .message').slice(0, 1000); // したらばで1000以上のスレは重すぎて実質固まるので1000までしか処理しない //var mesEleA = elegeta(NEW5CH ? '.post .post-content' : '.thread .message,#thread-body .message').slice(0, 1000); // したらばで1000以上のスレは重すぎて実質固まるので1000までしか処理しない var mesEleA = elegeta(NEW5CH ? '.post .post-content' : '.thread .message,#thread-body .message').slice(0, 1000); // したらばで1000以上のスレは重すぎて実質固まるので1000までしか処理しない var greenEleA = elegeta(".t5quote").slice(0, 1000) if (NEW5CH) if (eleget0('//span[@class="postid" and text()="0001"]')) elegeta('.postid').forEach(e => e.textContent = Number(e.textContent)) // 旧5chに引用ポップアップの仕込み elegeta('//div[@class="message"]/span/a[contains(text(),">>")]|//div[@class="message"]/span/span/a[contains(text(),">>")]').slice(0, 3000).forEach(e => { if (e.innerText.match(/\>\>\d+/)) e.classList.add("reply_link") }) // 右肩のバックリンクを付ける //elegeta(NEW5CH ? 'details' : '//div[@class="meta"]').slice(0, 1000).forEach(e => { elegeta(NEW5CH ? '.post-header' : '//div[@class="meta"]').slice(0, 1000).forEach(e => { let ep = e?.closest(".post"); if (ep) { let eID = ep.id let quoted = gatherRes(new RegExp(`>>${eID}[^0-9]`), ep, 2) if (quoted.length) { $('.back-links>a', ep).remove(); if (!NEW5CH) { quoted.forEach(c => { $(e).append(`\>\>${c}`) }) } else { after(e, `${quoted.map(c => `\>\>${c}`).join("") }`) //quoted.forEach(c => { after(e, `\>\>${c}`) }) } } e.dataset.quospan = "1"; if (NEW5CH) { after(eleget0('.post-header', ep), ` []`) // 見えない「>>」以降はGMヤフオクで項目のキーから外される } else { end(e, ` []`) // 見えない「>>」以降はGMヤフオクで項目のキーから外される } } else { if (NEW5CH) { //after(eleget0('details', ep), ` []`) // 見えない「>>」以降はGMヤフオクで項目のキーから外される after(eleget0('.post-header', ep), ` []`) // 見えない「>>」以降はGMヤフオクで項目のキーから外される } else { end(e, ` []`) // 見えない「>>」以降はGMヤフオクで項目のキーから外される } } } }) greenEleA.forEach(e => eleget0('.relallArea', e?.closest(".post"))?.classList?.add("relallAreaon")) setTimeout(() => $('.back-links>a').remove(), 2000) // 回線が遅くてまれに本家ポップアップがダブリで付く現象の防止? function gatherRes(eWord = "", ele = null, find = 0) { if (find == 2) { // find=2なので高速版。>>nn形式のリストだけ作ってreturn let findEle = (typeof eWord === "string") ? // (mesEleA || []).filter(e => e.textContent.indexOf(eWord) !== -1 && Number(e?.closest(".post").id) > Number(ele?.closest(".post").id)) // ">>nn" 元のレスより前のレスは引用しない (mesEleA || []).filter(e => e.textContent.indexOf(eWord) !== -1) // ">>nn" 元のレスより前のレスも引用する : // (mesEleA || []).filter(e => e.textContent.match(eWord) && Number(e?.closest(".post").id) > Number(ele?.closest(".post").id)) // ">>nn" 元のレスより前のレスは引用しない (mesEleA || []).filter(e => e.textContent.match(eWord)) // ">>nn" 元のレスより前のレスも引用する if (!ele) return false; findEle.forEach(e => { eleget0('.relallArea', e?.closest(".post"))?.classList?.add("relallAreaon") }) let mesA = mesEleA var list = (findEle.concat(greenEleA.filter(e => { var eWord = (e.textContent.match0(/^[>>]+(.+)$/m) || "").trim(); if (eWord) { var ep = e?.closest(".post") if (ep && ep != ele && ele?.textContent?.indexOf(eWord) !== -1 && Number(ep?.id) >= Number(ele?.id)) { eleget0('.relallArea', ep)?.classList?.add("relallAreaon") return true; } else { return null; } // >>ALLの場合元のレスより前のレスは引用しない } }))).map(c => c?.closest(".post")?.id) || [] return [...new Set(list)].sort((a, b) => a - b); } dc("order:" + eWord) var gathered = []; // 引用するレス要素(オリジナル)を入れていく配列 let mesA = mesEleA if (ele) { // eleが指定されているなら右肩の逆引用なので(eleレスにある文字列が引用されているレス|>>"eleのレス番"があるもの)も列挙して連結 gathered = gathered.concat([ele?.closest(".post")]).concat(greenEleA.filter(e => { var eWord = (e.textContent.match0(/^[>>]+(.+)$/m) || "").trim() if (eWord) { var ep = e?.closest(".post") if (ep != ele && ele.textContent.indexOf(eWord) !== -1 && Number(ep.id) >= Number(ele.id)) { return e?.closest(".post"); } else { return null; } // >>ALLの場合元のレスより前のレスは引用しない // if (ep != ele && ele.textContent.indexOf(eWord) !== -1 ) { return e; } else { return null; } // >>ALLの場合元のレスより前のレスでも引用する } })) dc("<<逆引用:" + gathered.map(e => e?.closest(".post")?.id)); } if (String(eWord).match0(/^>>\d+$/)) { // eWordが>>100のように「>>半角数字」だけの時は()>>レス番のレス|同じアンカーがあるレス)を連結 var ankNo = (String(eWord).match0(/^[>>]+(.+)$/m) || "").trim() dc(`本文>>数字(${String(eWord)}):${ ankNo}`) mesEleA.filter(e => (e?.closest(".post")?.id == ankNo) || (e.textContent.match0(new RegExp(">>" + ankNo + "[^0-9]")))).forEach(e => { var b = e?.closest(".post") //a.classList.add("rtdAttract"); //集めた元レスを目立たせる gathered.push(b); }) } else { gathered = gathered.concat((typeof eWord === "string") ? (mesEleA.filter(e => eWord ? e.textContent.indexOf(eWord) !== -1 : false) || false) : (mesEleA.filter(e => eWord ? e.textContent.match(eWord) : false) || false) ) dc("本文>>文字列:" + gathered.map(e => e?.closest(".post")?.id)) } // dc(gathered) let resNumA = gathered.map(e => e?.closest(".post")).map(e => e && e.id).filter(e => e).sort((a, b) => a - b) // 一旦レス番号に変換して若い順にソート&重複削除 resNumA = [...new Set(resNumA)]; dc(resNumA) let gathered2 = []; // 引用するレス要素(クローン)を入れていく配列 // >>文字列を含む列を列挙して連結 resNumA.forEach(e => { var b = $(eleget0(NEW5CH ? `.post[id="${e}"]` : `//div[@id="${e}"]`)).clone(true, true); //a.classList.add("rtdAttract"); //集めた元レスを目立たせる gathered2.push(b); }) if (POPUP_STYLE) gathered2.forEach(b => $(b).css({ "display": "inline-block" })) else gathered2.forEach(b => $(b).css({ "display": "block", "padding": "1em 3em 0.3em 3em", "border-bottom": "1px solid gray", "margin": "0" })) var quoteDesEle0 = gathered2.length ? gathered2[0] : null; return [gathered2, quoteDesEle0, gathered2.map(c => Number(c[0].id))]; } document.addEventListener("mousemove", function(e) { // hover:: var hoverEle = (document.elementFromPoint(mousex, mousey)) if (!hoverEle) return; if (latestHover != hoverEle) { let hoverPost = hoverEle?.closest(".post") let level = hoverEle.closest(".ch5pu")?.dataset.level + 0 || 0; //mesEleA = elegeta(NEW5CH ? '.post-content' : '.thread .message,#thread-body .message').slice(0, 1000) // したらばで1000以上のスレは重すぎて実質固まるので1000までしか処理しない if (hoverEle.className === "allpopup") { // >>ALL if (!hoverPost) return; var [gathered, quoteDesEle0, list] = gatherRes(new RegExp(`>>${hoverEle?.closest(".post")?.id}[^0-9]`), hoverEle?.closest(".post")) } else if (hoverEle.matches(".t5quote,.quoteSpeechBalloon")) { // 青緑色の引用文 //var eWord = (hoverEle.textContent.match0(/^[>>]+(.+)$/m) || "").trim() || hoverEle.dataset.quoteno var eWord = hoverEle.dataset.quoteno || (hoverEle.textContent.match0(/^[>>]+(.+)$/m) || "").trim() if (!eWord) return; if (/^\d+$/.test(eWord)) { var [gathered, quoteDesEle0, list] = gatherRes(">>" + eWord); if (gathered.length < 1) return; } else { var [gathered, quoteDesEle0, list] = gatherRes(eWord) if (gathered.length <= 1) return; } } else if (hoverEle.className === "reply_link") { // 元からある逆引用の>>100のポップアップ var eWord = (hoverEle.textContent.match0(/^(>>\d+)/)).trim(); //alert(eWord) if (!eWord) return; var [gathered, quoteDesEle0, list] = gatherRes(eWord); if (gathered.length < 1) return; } else if (hoverEle.parentNode.className === "back-links") { // 元からある逆引用の>>100のポップアップ var eWord = (hoverEle.textContent.match0(/(>>\d+)/)).trim(); //alert(eWord) if (!eWord) return; var [gathered, quoteDesEle0, list] = gatherRes(eWord); if (gathered.length < 1) return; //} else if (hoverEle.matches(".relallAreaon")) { // let p3 = getRelatedRsca(hoverEle.dataset.resno) } else if (hoverEle.matches(".relallAreaon,.postid")) { let p3 = getRelatedRsca(hoverEle.dataset.resno || +hoverEle?.textContent) let p1 = p3.map(v => $(elegeta('.post').find(e => e.id == v)).clone(true, true)) let p2 = p1[0] if (POPUP_STYLE) p1.forEach(b => $(b).css({ "display": "inline-block" })) else p1.forEach(b => $(b).css({ "display": "block", "padding": "1em 3em 0.3em 3em", "border-bottom": "1px solid #aaa", "margin": "0" })) //if ($(p1).is(":hidden")) $(p1.closest(".post")).show(0).css({ "display": "table" }) // 学園祭で消していたら出す var [gathered, quoteDesEle0, list] = [p1, p2?.[0], p3] } if ((quoteDesEle0 && gathered.length && !eleget0(`.ch5pu[data-list="${list.join(",")}"]`)) // 新しく黄土色文字か>>ALLの上に入った && (!eleget0(`.ch5pu[data-list="${list.slice(1).join(",")}"]`))) { // 新しく黄土色文字か>>ALLの上に入った let xr = mousex > window.innerWidth * 2 / 3 let x = `` var pos = `position:absolute;` var hitpostsEle = ``; let origLen = gathered.length //if (!hoverEle.matches(".relallAreaon") && gathered[0][0].id == hoverPost.id) { gathered.shift(); } // 先頭レスが引用元レスと同じ時だけは削除 if (!hoverEle.matches(".relallAreaon,.postid") && gathered[0][0].id == hoverPost.id) { gathered.shift(); } // 先頭レスが引用元レスと同じ時だけは削除 let ch5pu = end(document.body, hitpostsEle) if (gathered.length) { let frag = new DocumentFragment(); gathered.forEach(e => { frag.append(e[0]) if (POPUP_STYLE) $(frag).append("
") }) $(ch5pu).append(frag) if (gathered?.length > 1 && eleget0(`.post[id="${hoverPost?.id}"]`, ch5pu)) { elegeta(`.post[id="${hoverPost?.id}"]`).forEach(e => e.classList.add("relpost")) clearTimeout(GF?.relpostID); GF.relpostID = setTimeout(() => elegeta('.relpost').forEach(e => e.classList.remove("relpost")), 2000) addstyle.add(`.relpost{ box-shadow:-2px 0px 0px 0px #68f !important;}`) } if (NEW5CH) $(elegeta('.ch5pu .relallArea', ch5pu)).remove() let puY = (window.scrollY + hoverEle.getBoundingClientRect()?.top + (hoverEle.getBoundingClientRect()?.height)) - (ch5pu.getBoundingClientRect()?.height / 2) + 2 let fitR = gbcr(hoverEle).right + gbcr(ch5pu).width <= clientWidth() - 10 // 右に入り切る let fitD = gbcr(ch5pu).height <= (clientHeight() - gbcr(hoverEle).bottom) - 10 // 下に入り切る let fitU = gbcr(ch5pu).height <= (gbcr(hoverEle).top) - 10 // 上に入り切る let fitH = gbcr(ch5pu).height <= (clientHeight()) - 10 // 縦に入り切る let puWidth = gbcr(ch5pu).width //console.log(mousex-16,clientWidth(),gbcr(hoverEle).width) if (fitD) { // ホバーの下縁 ch5pu.style.top = `${(window.scrollY + hoverEle.getBoundingClientRect()?.bottom-1)}px` ch5pu.style.left = `${Math.min(mousex-16,clientWidth()-puWidth-20)}px` dc(`popup-type:${1}`) /*} else if (!fitD && fitR && fitH) { // ホバーの右 ch5pu.style.left = `${hoverEle.getBoundingClientRect().right-1}px` let puY = (window.scrollY + hoverEle.getBoundingClientRect()?.top) puY = Math.min(window.scrollY + window.innerHeight - gbcr(ch5pu).height - 10, puY) puY = Math.max(window.scrollY + 5, puY) ch5pu.style.top = `${puY}px` dc(`popup-type:${2}`)*/ } else if (!fitD && fitU) { // ホバーの上 ch5pu.style.top = `${(window.scrollY + gbcr(hoverEle).top - gbcr(ch5pu).height )}px` ch5pu.style.left = `${Math.min(mousex-16,clientWidth()-puWidth-20)}px` // ch5pu.style.right = `0px` dc(`popup-type:${3}`) /*} else if (!fitD && !fitU && fitR && !fitH) { // ホバーの右(上から) ch5pu.style.left = `${hoverEle.getBoundingClientRect().right-1}px` let puY = (window.scrollY + hoverEle.getBoundingClientRect()?.top) ch5pu.style.top = `${window.scrollY +15}px` dc(`popup-type:${2}`)*/ } else { // ホバーの下縁 ch5pu.style.top = `${(window.scrollY + hoverEle.getBoundingClientRect()?.bottom)}px` ch5pu.style.left = `${Math.min(mousex-16,clientWidth()-puWidth-20)}px` //ch5pu.style.right = `0px` dc(`popup-type:${4}`) } let eley = $(hoverEle).offset().top - $(window).scrollTop() + $(hoverEle).outerHeight() + 3; let marginheight = Math.min(window.innerHeight, document.documentElement.clientHeight) - eley let eleheight = $(hitpostsEle).height() if (marginheight / eleheight < 1) $(hitpostsEle).css({ "transform-origin": xr ? "top right" : "top left" }).delay(100).animate2({ "transform": `scale(${Math.max(CH5_QUOTE_POPUP_SCALING_LOWER_LIMIT,marginheight/eleheight)})`, "opacity": "1" }, 100) //$(".ch5pu").draggable({ cancel: "img,video,section,blockquote,a,span:not(.ch5pu),.yhmMyMemo,.allpopup",scroll:false }); //$(".ch5pu").draggable({ cancel: ".post,.yhmMyMemo,.allpopup,.relallArea", scroll: false }); dragElement(ch5pu, "*", ".post,.yhmMyMemo,.allpopup,.relallArea") } } else { if (latestHover != hoverEle && !hoverEle.closest(".ftbpu,.ch5pu,.post_hover") && !quoteDesEle0) { //&& !eWord) { // すべてのpuから降りた elegeta('.relpost').forEach(e => e.classList.remove("relpost")) $(".ch5pu").remove(); //$(".rtdAttract").removeClass("rtdAttract") } if (latestHover != hoverEle && !hoverEle.closest(".allpopup,.reply_link") && hoverEle.closest(".ftbpu,.ch5pu,.post_hover")) { // levelが低い要素に降りたら上のは消す elegeta(".ch5pu").forEach(e => { if (e.dataset?.level > level) { e.remove() } }) } } } latestHover = hoverEle }, true); } // レス番rscに引用・非引用が連鎖するレスのレス番rscを全て配列で返す rsc => [rsc,rsc,rsc,...] function getRelatedRsca(rsc) { let tableRsc = elegeta('.post').sort((a, b) => a.id === b.id ? 0 : Number(a.id) > Number(b.id) ? 1 : -1) // レステーブル[登場順] let tableRscOrder = [] // レステーブル[rsc] tableRsc.forEach(v => tableRscOrder[v.id] = v) // 速度のためにキャッシュする let ress = getRelCno([+rsc], tableRsc, tableRscOrder) while (1) { let r = getRelCno(ress, tableRsc, tableRscOrder) if (r.length <= ress.length || r.length > 100) { ress = r; break } ress = r } if (ress?.length < 2) return [] //null return ress.sort(new Intl.Collator("ja", { numeric: true, sensitivity: 'base' }).compare) } function getRelCno(resa, tableRsc, tableRscOrder) { let a = resa || [] resa.forEach(res => { a = a.concat(elegeta(`.allpopup`, tableRscOrder[res]).map(v => +v.innerText.replace(/^>>/, ""))) // 右肩の>>100のバックリンク let rscText = elegeta(`.reply_link`, tableRscOrder[res]).map(e => +e?.innerText?.replace(/^>+/, "")?.trim()) // 本文中の>>100の引用 rscText.forEach(v => { let hitno = tableRsc.find(w => w.id == v) if (hitno) a.push(+v) }) // let rscText2 = elegeta(`.t5quote`, tableRscOrder[res]).map(e => +e?.innerText?.replace(/^>+/, "")?.trim()) // 本文中の>○○の引用 let rscText2 = elegeta(`.t5quote`, tableRscOrder[res]).map(e => e?.innerText?.replace(/^>+|^>+/, "")?.trim()) // 本文中の>○○の引用 rscText2.forEach(v => { if (v.length > 3) { // 4文字以上でなければ無視 let hitno2 = tableRsc.filter(w => eleget0('.message,.post-content', w).innerText.indexOf(v) !== -1).map(e => +e?.id) if (hitno2.length) a = a.concat(hitno2) } }) }) let ret = [...new Set(a?.flat())].filter(v => v !== undefined && v !== null).sort() return ret } function dc(str, force = 0) { if (debug || force) popup3(str, 0, 1, 5000, "top"); return str; } function popup3(text, i = 0, lf = 1, timer = 15000, alignY = "bottom") { if (text == undefined) text = "null" if (typeof text == "string") text = text.slice(0, 200); if (typeof text != "number") text = String(text); text = String(text) text = text.replace(/&/g, "&").replace(/"/g, """).replace(/'/g, "'").replace(/`/g, '`').replace(//g, ">").replace(/\n/gm, "
") let id = Math.random().toString(36).substring(2); var ele = $('' + text + '').appendTo('body'); let ey = ele[0].getBoundingClientRect().height; if (ele[0].getBoundingClientRect().bottom >= (window.innerHeight)) { elegeta('.yhmpu3').forEach(e => { e.style.top = parseFloat(e?.style?.top) - (ey) - 2 + "px" }) } else { maey = (maey + (ele[0]?.getBoundingClientRect()?.height + 2)) } if (typeof text == "string") { maey += (text.match(/
/gmi) || []).length || 0; } //console.log((text.match(/
/gmi) || [] ).length) } setTimeout(() => { eleget0('//span[@id="yhmbox' + id + '"]').remove(); if (!eleget0('.yhmpu3')) maey = 0; }, timer); } function before(e, html) { e.insertAdjacentHTML('beforebegin', html); return e?.previousElementSibling; } function begin(e, html) { e.insertAdjacentHTML('afterbegin', html); return e?.firstChild; } function end(e, html) { e.insertAdjacentHTML('beforeend', html); return e?.lastChild; } function after(e, html) { e.insertAdjacentHTML('afterend', html); return e?.nextElementSibling; } function gbcr(e) { return e?.getBoundingClientRect() } function clientHeight() { return Math.min(document.documentElement.clientHeight, window.innerHeight) } function clientWidth() { return document.documentElement.clientWidth } function ct(callback, name = "test", time = 1) { console.time(name); for (let i = time; i--;) { callback() } console.timeEnd(name) } // 速度測定 function lh(re) { let tmp = location.href.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可 function ld(re) { let tmp = location.hostname.match(re); if (!tmp) { return null } else if (tmp.length > 1) { return tmp[1] } else return tmp[0] } // gフラグ不可 function autoPagerized(callback, command) { if (command !== "not1st") callback(document.body) document.body.addEventListener('AutoPagerize_DOMNodeInserted', function(evt) { callback(evt.target); }, false); } function dragElement(ele, handleSel = "*", cancelSel = "") { let x, y; (handleSel == "*" ? [ele] : elegeta(handleSel, ele)).forEach(e => e.onmousedown = dragMouseDown) function dragMouseDown(e) { if (e.target.closest(cancelSel) || e.button != 0) return; e = e || window.event; e.preventDefault(); ele.style.minWidth = `${!NEW5CH?$(ele).width():$(ele).outerWidth()}px`; /* if (ele.style.right) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする ele.style.left = `${ele.offsetLeft}px` ele.style.right = "" } if (ele.style.bottom) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする ele.style.top = `${ele.offsetTop}px` ele.style.bottom = "" } */ [x, y] = [e.clientX, e.clientY]; document.onmouseup = closeDragElement; document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); if (ele.style.right) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする ele.style.left = `${ele.offsetLeft}px` ele.style.right = "" } if (ele.style.bottom) { // right:かbottom:で張り付いてるものなら剥がしてleft/topにする ele.style.top = `${ele.offsetTop}px` ele.style.bottom = "" } ele.style.top = `${(ele.offsetTop - (y - e.clientY))}px`; ele.style.left = `${(ele.offsetLeft - (x - e.clientX))}px`; [x, y] = [e.clientX, e.clientY]; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; } } function sani(s) { return s?.replace(/&/g, "&")?.replace(/"/g, """)?.replace(/'/g, "'")?.replace(/`/g, '`')?.replace(//g, ">") || "" } function minmax(v, min, max) { return Math.min(Math.max(v, min), max) } })();