- // ==UserScript==
- // @name chan embedded quote fixer
- // @namespace http://tampermonkey.net/
- // @version 1.6
- // @description Puts embedded quotes in end of post rather than beginning, can also click on checkboxes in posts to remove them, also works on 4channel boards, can tesselate whole thread/inlined posts, can change size of expanded media, can color posts to help keep track of embedded conversations, can hide extra options on each post via toggle (posts/thread), can manually drag posts around page via toggle (posts/thread), can remove (You)s, can change text flow on expanded images
- // @author DUVish
- // @match http://boards.4chan.org/*/thread/*
- // @match https://boards.4chan.org/*/thread/*
- // @match https://boards.4channel.org/*/thread/*
- // @match http://boards.4channel.org/*/thread/*
- // @grant none
- // ==/UserScript==
-
- document.querySelector("head").innerHTML += `
- <style>
- div.post {overflow: visible;}
- div.image-expanded:not(.regularTextFlow) {display: unset !important;}
- div.image-expanded.regularTextFlow {display: table !important;}
- </style>
- `;
-
- //window.onload(function() {
- setTimeout(function() {
- let quotesList = Array.from(document.getElementsByClassName("quotelink")).filter(node => window.getComputedStyle(node).getPropertyValue("font-size") === "10.6667px");
-
- quotesList.forEach(node => {
- node.addEventListener("click", qEV);
- });
-
- Array.from(document.getElementsByTagName("span")).filter(el => {
- try {
- if (el.children.length > 0 && el.children[0].classList.contains("quotelink")) return true;
- } catch(error) {
- //console.log("custom error in span EL", el);
- return false;
- }
- }).forEach(el => el.addEventListener("click", qSpanClick));
-
- addRemoveCapability();
- addCollapseAndExpand();
- addTessellationQuotes();
- addQuotedPostsContainer();
- addTessellationThread();
- addThreadWidthToggle();
- addMediaZoom();
- addMediaFlow();
- addColorPostsThread();
- addColorPosts();
- setPostColor();
- addCollapseExtraNodesToggle();
- addPostDraggableTogglePost();
- addPostsDraggableToggleThread();
- addRemoveYousInPost();
- addEditabilityToPost();
- addCollapseExtrasInPosts();
- addExpandExtrasInPosts();
- expandPostsPostOn();
- }, 2500);
- //});
-
- let greenTextStyler = `<style>
- blockquote > div > span.quote {
- color: #789922;
- }
- </style>`;
-
- document.querySelector("head").innerHTML += greenTextStyler;
-
- //tessellation feature - move element all the way to the right, try and move up - if interfering with getBoundingClientRect in two axes, then move left, then try and move up again - repeat until both up and left are exhausted
- //repeat for all posts - tesselation would not just add display: flex and flex-wrap:wrap to thread container, but also margin/-margin to each individual post - can either add some caching capability by storing data on
- //dome nodes themselves, or just store all of the HTML before, revert on option, and re-compute each time, possibly also add to barchive, also add for within posts themselves
-
- var postColor = '';
- var colorDiff = 38;
-
- if (window.location.href.includes("boards.4chan.org")) colorDiff = 28;
-
- function addTessellationThread() {
- let newSpan = document.createElement("span");
- newSpan.innerText = "[Tessellate Thread]";
- newSpan.classList.add("tessellateThread");
- newSpan.classList.add("collapsible");
- newSpan.style.paddingLeft = "6px";
- newSpan.style.paddingRight = "1px";
- newSpan.style.fontSize = "11px";
- newSpan.style.color = "rgb(46, 54, 144)";
- newSpan.style.opacity = "1";
- document.querySelector(".opContainer").querySelector(".postInfo.desktop").insertBefore(newSpan, document.querySelector(".opContainer").querySelector(".postMenuBtn"));
- newSpan.addEventListener("click", tessellateThread);
- }
-
- function tessellateThreadAlgorithmic(e) {
- let node = e.target;
- let threadNode = document.querySelector(".thread");
- let posts = Array.from(document.querySelectorAll(".post.reply"));
- if (e.target.style.opacity === "1") {
- //threadNode.style.maxWidth = "100%";
- //threadNode.style.display = "flex";
- //threadNode.style.flexWrap = "wrap";
- node.style.opacity = "0.55";
- Array.from(document.querySelectorAll(".sideArrows")).forEach(el => {el.style.opacity = "0"; el.style.zIndex = "-1";});
- posts.forEach(el => {el.style.position = "relative"; el.style.bottom = "0px"; el.style.top = "0px"; el.style.left = "0px"; el.style.right = "0px";});
- let topBound = Math.floor(document.querySelector(".postContainer.opContainer").getBoundingClientRect().bottom + window.scrollY);
- let leftBound = 24;
- //console.log("before top-level iteration", topBound, leftBound);
- posts.forEach((post, postIdx) => {
- if (postIdx === 0) return;
- //post.style.left = document.documentElement.clientWidth - post.getBoundingClientRect().right;
- let beginningTop = post.getBoundingClientRect().top + window.scrollY;
- let currentBottomDiff = 0;
- let currentRightDiff = 0;
- let currentLeftDiff = 0;
- let currentTopDiff = 0;
- let currentLeftBound = document.documentElement.clientWidth - post.getBoundingClientRect().right;
- //console.log("before first while loop", beginningTop, currentLeftBound);
- //console.log("collection before while loop", posts, posts.slice(0, postIdx));
- while(!intersectionCheck(post.getBoundingClientRect().top + window.scrollY - currentBottomDiff, currentLeftBound, posts.slice(0, postIdx), topBound, leftBound, post)) {
- currentBottomDiff += 2;
- //post.style.bottom = `${Number(post.style.bottom.match(/(\d+)px/)[1]) + 2}px`;
- }
- post.style.bottom = `${Number(post.style.bottom.match(/(\d+)px/)[1]) + currentBottomDiff}px`;
- let currentTopBound = beginningTop + window.scrollY - currentBottomDiff;
- while(!intersectionCheck(currentTopBound, currentLeftBound - currentRightDiff, posts.slice(0, postIdx), topBound, leftBound, post)) {
- //post.style.right = `${Number(post.style.right.match(/(\d+)px/)[1]) + 2}px`;
- currentRightDiff += 2;
- }
- post.style.left = `${Number(post.style.left.match(/(\d+)px/)[1]) - currentRightDiff + currentLeftBound}px`;
- });
- } else {
- //undo
- node.style.opacity = "1";
- threadNode.style.maxWidth = "";
- Array.from(document.querySelectorAll(".sideArrows")).forEach(el => {el.style.opacity = "1"; el.style.zIndex = "0";});
- posts.forEach(el => {el.style.position = "unset"; el.style.bottom = "0px"; el.style.top = "0px"; el.style.left = "0px"; el.style.right = "0px";});
- }
- }
-
- function intersectionCheck(currentTop, currentLeft, collection, topBound, leftBound, post) {
- //console.log("entering intersectionCheck, collection", collection);
- for (let el of collection) {
- //console.log("comparing", post, el, currentTop, currentLeft, topBound, leftBound);
- if (currentTop < el.getBoundingClientRect().bottom + window.scrollY && currentLeft < el.getBoundingClientRect().right ||
- currentTop < topBound || currentLeft < leftBound) return true;
- }
- return false;
- }
-
- function tessellateThread(e) {
- let node = e.target;
- let threadNode = document.querySelector(".thread");
- if (threadNode.style.display !== "flex") {
- threadNode.style.display = "flex";
- threadNode.style.flexWrap = "wrap";
- threadNode.style.maxWidth = "100%";
- node.style.opacity = "0.55";
- } else {
- threadNode.style.display = "";
- threadNode.style.flexWrap = "";
- threadNode.style.maxWidth = "";
- node.style.opacity = "1.0";
- }
- }
-
- function addThreadWidthToggle() {
- let newSpan = document.createElement("span");
- newSpan.innerText = "[Toggle Thread Width]";
- newSpan.classList.add("threadWidthToggle");
- newSpan.classList.add("collapsible");
- newSpan.style.paddingLeft = "6px";
- newSpan.style.paddingRight = "1px";
- newSpan.style.fontSize = "11px";
- newSpan.style.color = "rgb(46, 54, 144)";
- newSpan.title = "Toggle thread width to and from 100% viewport width (without tessellating)";
- document.querySelector(".opContainer").querySelector(".postInfo.desktop").insertBefore(newSpan, document.querySelector(".opContainer").querySelector(".postMenuBtn"));
- newSpan.addEventListener("click", toggleThreadWidth);
- }
-
- function toggleThreadWidth(e) {
- let node = e.target;
- if (Number(node.style.opacity) > 0.95 || !node.style.opacity) {
- document.querySelector(".thread").style.maxWidth = "100%";
- node.style.opacity = "0.55";
- } else {
- document.querySelector(".thread").style.maxWidth = "";
- node.style.opacity = "1.0";
- }
- }
-
- function addTessellationQuotes() {
- Array.from(document.getElementsByClassName("postInfo")).forEach(el => {
- if (el.getElementsByClassName("tessellateQuotes").length === 0) {
- let btn = el.querySelector(".postMenuBtn");
- let tesSpan = document.createElement("span");
- tesSpan.innerText = "[Tessellate]";
- tesSpan.classList.add("tessellateQuotes");
- tesSpan.classList.add("collapsible");
- tesSpan.style.paddingLeft = "6px";
- tesSpan.style.paddingRight = "1px";
- tesSpan.style.fontSize = "11px";
- tesSpan.style.color = "rgb(46, 54, 144)";
- el.insertBefore(tesSpan, btn);
- tesSpan.removeEventListener("click", tessellateQuotes);
- tesSpan.addEventListener("click", tessellateQuotes);
- }
- });
- }
-
- function tessellateQuotes(e) {
- let tesSpan = e.target;
- let quotesNode = e.target.parentNode.parentNode.querySelector(".quotedPostsContainer");
- if (quotesNode.style.display !== "flex") {
- quotesNode.style.display = "flex";
- quotesNode.style.flexWrap = "wrap";
- tesSpan.style.opacity = "0.55";
- } else {
- quotesNode.style.display = "";
- quotesNode.style.flexWrap = "";
- tesSpan.style.color = "rgb(46, 54, 144)";
- tesSpan.style.opacity = "1.0";
- }
- }
-
- function addQuotedPostsContainer() {
- Array.from(document.getElementsByClassName("postMessage")).forEach(el => {
- if (el.getElementsByClassName("quotedPostsContainer").length === 0) {
- let container = document.createElement("span");
- container.classList.add("quotedPostsContainer");
- el.appendChild(container);
- }
- });
- }
-
- function addCollapseAndExpand() {
- Array.from(document.querySelectorAll(".post.reply")).forEach(postNode => {
- if (Array.from(postNode.children[1].children).filter(node => node.classList.contains("expandSpan")).length === 0) {
- let expandSpan = document.createElement("span");
- expandSpan.classList.add("expandSpan");
- expandSpan.classList.add("collapsible");
- expandSpan.innerText = "[↓]";
- expandSpan.title = "expand all 'quoted by' posts";
- expandSpan.style.color = "#1019d2e6";
- expandSpan.style.fontSize = "11px";
- expandSpan.style.paddingLeft = "5px";
- expandSpan.style.paddingRight = "5px";
- expandSpan.style.whiteSpace = "nowrap";
- let collapseSpan = document.createElement("span");
- collapseSpan.classList.add("collapseSpan");
- collapseSpan.classList.add("collapsible");
- collapseSpan.style.color = "#1019d2e6";
- collapseSpan.innerText = "[↑]";
- collapseSpan.title = "collapse all 'quoted by' posts";
- collapseSpan.style.fontSize = "11px";
- collapseSpan.style.paddingRight = "0px";
- collapseSpan.style.whiteSpace = "nowrap";
- postNode.children[1].insertBefore(expandSpan, postNode.querySelector(".postMenuBtn"));
- postNode.children[1].insertBefore(collapseSpan, postNode.querySelector(".postMenuBtn"));
- }
- let expand = postNode.querySelector(".expandSpan");
- let collapse = postNode.querySelector(".collapseSpan");
- expand.removeEventListener("click", expandSpanEL);
- expand.addEventListener("click", expandSpanEL);
- collapse.removeEventListener("click", collapseSpanEL);
- collapse.addEventListener("click", collapseSpanEL);
- });
- }
-
- function expandSpanEL(e) {
- Array.from(Array.from(e.target.parentNode.children).filter(node => node.classList.contains("backlink"))[0].children).forEach(node => {if (!node.children[0].classList.contains("linkfade")) node.children[0].click();});
- }
-
- function collapseSpanEL(e) {
- Array.from(Array.from(e.target.parentNode.children).filter(node => node.classList.contains("backlink"))[0].children).forEach(node => {if (node.children[0].classList.contains("linkfade")) node.children[0].click();});
- }
-
- function qSpanClick(e) {
- e.preventDefault();
- }
-
- function addMediaZoom() {
- Array.from(document.querySelectorAll(".fileText")).forEach(el => {
- if (Array.from(el.children).filter(el => el.classList.contains("mediaSizeChange")).length === 0) {
- let span = document.createElement("span");
- span.classList.add("mediaSizeChange");
- span.classList.add("collapsible");
- let spanBigger = document.createElement("span");
- let spanSmaller = document.createElement("span");
- let spanBiggerMore = document.createElement("span");
- let spanSmallerMore = document.createElement("span");
- let spanReset = document.createElement("span");
- spanBigger.classList.add("mediaSizeIncrease");
- spanSmaller.classList.add("mediaSizeDecrease");
- spanBiggerMore.classList.add("mediaSizeIncreaseMore");
- spanSmallerMore.classList.add("mediaSizeDecreaseMore");
- spanReset.classList.add("mediaSizeReset");
- spanBigger.innerText = "(++)";
- spanSmaller.innerText = "(--)";
- spanBiggerMore.innerHTML = `(<span style="font-size: 16px; position: relative; top: 1.5px;">++</span>)`;
- spanSmallerMore.innerHTML = `(<span style="font-size: 18px; position: relative; top: 2px;">--</span>)`;
- spanReset.innerText = "(Reset)";
- spanBigger.style.color = "#1019d2e6";
- spanBiggerMore.style.color = "#1019d2e6";
- spanSmaller.style.color = "#1019d2e6";
- spanSmallerMore.style.color = "#1019d2e6";
- spanReset.style.color = "#1019d2e6";
- spanReset.style.fontSize = "10px";
- span.innerHTML = `[ Size - ${spanSmaller.outerHTML} ${spanSmallerMore.outerHTML} | ${spanBigger.outerHTML} ${spanBiggerMore.outerHTML} | ${spanReset.outerHTML} ]`;
- el.appendChild(span);
- span.style.fontSize = "12px";
- span.style.position = "relative";
- span.style.bottom = "1px";
- span.style.paddingRight = "4px";
- span.style.paddingLeft = "4px";
- spanReset.style.position = "relative";
- spanReset.style.bottom = "1px";
- }
- let spanBigger = el.getElementsByClassName("mediaSizeIncrease")[0];
- spanBigger.removeEventListener("click", mediaSizeIncrease);
- let spanSmaller = el.getElementsByClassName("mediaSizeDecrease")[0];
- spanSmaller.removeEventListener("click", mediaSizeDecrease);
- let spanBiggerMore = el.getElementsByClassName("mediaSizeIncreaseMore")[0];
- spanBiggerMore.removeEventListener("click", mediaSizeIncreaseMore);
- let spanSmallerMore = el.getElementsByClassName("mediaSizeDecreaseMore")[0];
- spanSmallerMore.removeEventListener("click", mediaSizeDecreaseMore);
- let spanReset = el.getElementsByClassName("mediaSizeReset")[0];
- spanReset.removeEventListener("click", mediaSizeReset);
- spanBigger.addEventListener("click", mediaSizeIncrease);
- spanSmaller.addEventListener("click", mediaSizeDecrease);
- spanBiggerMore.addEventListener("click", mediaSizeIncreaseMore);
- spanSmallerMore.addEventListener("click", mediaSizeDecreaseMore);
- spanReset.addEventListener("click", mediaSizeReset);
- });
- }
-
- function mediaSizeIncrease(e) {
- let min = 0;
- let max = Number(e.target.parentNode.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[0]);
- let fileDiv = e.target.parentNode.parentNode.parentNode;
- if (Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO").length !== 0) {
- let vidEl = Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO")[0];
- if (vidEl.style.maxWidth) {
- vidEl.style.width = vidEl.style.maxWidth;
- vidEl.style.maxWidth = "";
- vidEl.style.maxHeight = "";
- }
- vidEl.style.height = "";
- let currentWidth = Number(vidEl.style.width.match(/\d+/));
- currentWidth += 20;
- vidEl.style.width = `${currentWidth}px`;
- } else {
- if (fileDiv.classList.contains("image-expanded")) {
- let img = Array.from(fileDiv.querySelectorAll("img")).filter(el => el.classList.contains("expanded-thumb"))[0];
- if (img) {
- if (img.style.maxWidth) {
- img.style.width = img.style.maxWidth;
- img.style.maxWidth = "";
- img.style.maxHeight = "";
- }
- img.style.height = "";
- let currentWidth = Number(img.style.width.match(/\d+/));
- currentWidth += 20;
- img.style.width = `${currentWidth}px`;
- }
- }
- }
- }
-
- function mediaSizeDecrease(e) {
- let min = 0;
- let max = Number(e.target.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[0]);
- let fileDiv = e.target.parentNode.parentNode.parentNode;
- if (Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO").length !== 0) {
- let vidEl = Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO")[0];
- if (vidEl.style.maxWidth) {
- vidEl.style.width = vidEl.style.maxWidth;
- vidEl.style.maxWidth = "";
- vidEl.style.maxHeight = "";
- }
- vidEl.style.height = "";
- let currentWidth = Number(vidEl.style.width.match(/\d+/));
- currentWidth -= 20;
- if (currentWidth < 0) {
- vidEl.style.width = `0px`;
- currentWidth = 0;
- } else {
- vidEl.style.width = `${currentWidth}px`;
- }
- } else {
- if (fileDiv.classList.contains("image-expanded")) {
- let img = Array.from(fileDiv.querySelectorAll("img")).filter(el => el.classList.contains("expanded-thumb"))[0];
- if (img) {
- if (img.style.maxWidth) {
- img.style.width = img.style.maxWidth;
- img.style.maxWidth = "";
- img.style.maxHeight = "";
- }
- img.style.height = "";
- let currentWidth = Number(img.style.width.match(/\d+/));
- currentWidth -= 20;
- if (currentWidth < 0) {
- img.style.width = `${max}px}`;
- } else {
- img.style.width = `${currentWidth}px`;
- }
- }
- }
- }
- }
-
- function mediaSizeIncreaseMore(e) {
- let min = 0;
- let max = Number(e.target.parentNode.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[0]);
- let fileDiv = e.target.parentNode.parentNode.parentNode.parentNode;
- if (Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO").length !== 0) {
- let vidEl = Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO")[0];
- if (vidEl.style.maxWidth) {
- vidEl.style.width = vidEl.style.maxWidth;
- vidEl.style.maxWidth = "";
- vidEl.style.maxHeight = "";
- }
- vidEl.style.height = "";
- let currentWidth = Number(vidEl.style.width.match(/\d+/));
- currentWidth += 100;
- vidEl.style.width = `${currentWidth}px`;
- } else {
- if (fileDiv.classList.contains("image-expanded")) {
- let img = Array.from(fileDiv.querySelectorAll("img")).filter(el => el.classList.contains("expanded-thumb"))[0];
- if (img) {
- if (img.style.maxWidth) {
- img.style.width = img.style.maxWidth;
- img.style.maxWidth = "";
- img.style.maxHeight = "";
- }
- img.style.height = "";
- let currentWidth = Number(img.style.width.match(/\d+/));
- currentWidth += 100;
- img.style.width = `${currentWidth}px`;
- }
- }
- }
- }
-
- function mediaSizeDecreaseMore(e) {
- let min = 0;
- let max = Number(e.target.parentNode.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[0]);
- let fileDiv = e.target.parentNode.parentNode.parentNode.parentNode;
- if (Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO").length !== 0) {
- let vidEl = Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO")[0];
- if (vidEl.style.maxWidth) {
- vidEl.style.width = vidEl.style.maxWidth;
- vidEl.style.maxWidth = "";
- vidEl.style.maxHeight = "";
- }
- vidEl.style.height = "";
- let currentWidth = Number(vidEl.style.width.match(/\d+/));
- currentWidth -= 100;
- if (currentWidth < 0) {
- vidEl.style.width = `0px`;
- currentWidth = 0;
- } else {
- vidEl.style.width = `${currentWidth}px`;
- }
- } else {
- if (fileDiv.classList.contains("image-expanded")) {
- let img = Array.from(fileDiv.querySelectorAll("img")).filter(el => el.classList.contains("expanded-thumb"))[0];
- if (img) {
- if (img.style.maxWidth) {
- img.style.width = img.style.maxWidth;
- img.style.maxWidth = "";
- img.style.maxHeight = "";
- }
- img.style.height = "";
- let currentWidth = Number(img.style.width.match(/\d+/));
- currentWidth -= 100;
- if (currentWidth < 0) {
- img.style.width = `${max}px}`;
- } else {
- img.style.width = `${currentWidth}px`;
- }
- }
- }
- }
- }
-
- function mediaSizeReset(e) {
- let width = Number(e.target.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[0]);
- let height = Number(e.target.parentNode.parentNode.innerText.match(/\d+x\d+/)[0].split("x")[1]);
- let fileDiv = e.target.parentNode.parentNode.parentNode;
- if (Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO").length !== 0) {
- let vidEl = Array.from(fileDiv.children).filter(el => el.tagName === "VIDEO")[0];
- vidEl.style.width = `${width}px`;
- vidEl.style.height = `${height}px`;
- } else {
- if (fileDiv.classList.contains("image-expanded")) {
- let img = Array.from(fileDiv.querySelectorAll("img")).filter(el => el.classList.contains("expanded-thumb"))[0];
- if (img) {
- img.style.width = `${width}px`;
- img.style.height = `${height}px`;
- }
- }
- }
- }
-
- function addMediaFlow() {
- Array.from(document.querySelectorAll(".fileText")).forEach(el => {
- if (Array.from(el.children).filter(el => el.classList.contains("mediaFlowChange")).length === 0) {
- let span = document.createElement("span");
- span.classList.add("mediaFlowChange");
- span.classList.add("collapsible");
- span.innerText = "[Text flow]";
- el.appendChild(span);
- span.style.fontSize = "10px";
- span.style.color = "#1019d2e6";
- span.style.position = "relative";
- span.style.bottom = "1px";
- span.style.paddingRight = "4px";
- span.style.opacity = "1";
- }
- let spanFlow = el.getElementsByClassName("mediaFlowChange")[0];
- spanFlow.removeEventListener("click", mediaFlowChange);
- spanFlow.addEventListener("click", mediaFlowChange);
- });
- }
-
- function mediaFlowChange(e) {
- let flowSpan = e.target;
- let flowSpanOpacity = flowSpan.style.opacity;
- let fileTextSpan = flowSpan.parentNode.parentNode;
- console.log("in MediaFlowChange", flowSpan, fileTextSpan, flowSpanOpacity, typeof flowSpanOpacity, fileTextSpan.classList.contains("image-expanded"), fileTextSpan.style.display);
- if (fileTextSpan.classList.contains("image-expanded")) {
- if (flowSpanOpacity === "1") {
- e.target.style.opacity = "0.55";
- //fileTextSpan.style.display = "table";
- fileTextSpan.classList.add("regularTextFlow");
- } else {
- e.target.style.opacity = "1";
- //fileTextSpan.style.display = "unset";
- fileTextSpan.classList.remove("regularTextFlow");
- }
- }
- }
-
- function addYTSizeChangeCapability() {
- //change yt size
- }
-
- function addRemoveCapability() {
- //turns all delete checkboxes to simply post removal buttons
- Array.from(document.getElementsByClassName("postInfo desktop")).forEach(el => el.children[0].addEventListener("click", postRemove));
- }
-
- function postRemove(e) {
- e.preventDefault();
- e.target.parentNode.parentNode.parentNode.remove();
- }
-
- function setPostColor() {
- if (!postColor) {
- if (document.querySelectorAll(".post.reply").length > 0) {
- let post = document.querySelector(".post.reply");
- let rgbStr = window.getComputedStyle(post).backgroundColor;
- let matches = rgbStr.match(/rgb\((\d+),\s?(\d+),\s?(\d+)\)/i);
- postColor = {r: Number(matches[1]), g: Number(matches[2]), b: Number(matches[3])};
- }
- }
- }
-
- function addColorPostsThread() {
- let btn = document.querySelector(".op").querySelector(".postMenuBtn");
- let span = document.createElement("span");
- span.classList.add("colorChange");
- span.classList.add("collapsible");
- span.title = "Color all posts in thread";
- let colorOn = document.createElement("span");
- let colorOff = document.createElement("span");
- colorOn.classList.add("colorOnThread");
- colorOff.classList.add("colorOffThread");
- colorOn.innerText = "Color Posts";
- colorOff.innerText = "Off";
- span.innerHTML = `[${colorOn.outerHTML} | ${colorOff.outerHTML}]`;
- btn.parentNode.insertBefore(span, btn);
- span.style.paddingLeft = "6px";
- span.style.paddingRight = "1px";
- span.style.fontSize = "11px";
- span.style.color = "rgb(46, 53, 144)";
- document.querySelector(".colorOnThread").addEventListener("click", colorPostsThreadOn);
- document.querySelector(".colorOffThread").addEventListener("click", colorPostsThreadOff);
- }
-
- function colorPostsThreadOn(e) {
- Array.from(document.querySelectorAll(".post.reply")).forEach(el => {
- el.style.backgroundColor = `rgb(${Math.random() > 0.8 ? postColor.r - (Math.random() * (colorDiff / 5)) : postColor.r + (Math.random() * (colorDiff * 1.45))},
- ${Math.random() > 0.8 ? postColor.g - (Math.random() * (colorDiff / 5)) : postColor.g + (Math.random() * (colorDiff * 1.45))},
- ${Math.random() > 0.8 ? postColor.b - (Math.random() * (colorDiff / 5)) : postColor.b + (Math.random() * (colorDiff * 1.45))})`;
- });
- }
-
- function colorPostsThreadOff(e) {
- Array.from(document.querySelectorAll(".post.reply")).forEach(el => {
- el.style.backgroundColor = `rgb(${postColor.r}, ${postColor.g}, ${postColor.b})`;
- });
- }
-
- function addCollapseExtraNodesToggle() {
- let btn = document.querySelector(".op").querySelector(".postMenuBtn");
- let span = document.createElement("span");
- span.classList.add("collapseExtraNodes");
- span.classList.add("collapsible");
- span.title = "Collapse all extra nodes in thread";
- span.innerText = "[Collapse extras]";
- btn.parentNode.insertBefore(span, btn);
- span.style.paddingLeft = "6px";
- span.style.paddingRight = "1px";
- span.style.fontSize = "11px";
- span.style.color = "rgb(46, 53, 144)";
- span.style.opacity = "1";
- span.addEventListener("click", collapseNodesToggle);
- }
-
- let threadNodesCollapsed = false;
-
- function collapseNodesToggle(e) {
- if (!threadNodesCollapsed) {
- Array.from(document.querySelectorAll(".collapsible")).forEach(el => el.style.display = "none");
- threadNodesCollapsed = true;
- //e.target.style.opacity = "0.55";
- } else {
- Array.from(document.querySelectorAll(".collapsible")).forEach(el => el.style.display = "unset");
- threadNodesCollapsed = false;
- //e.target.style.opacity = "1";
- }
- }
-
- function addCollapseExtrasInPosts() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach((el, i) => {
- if (i === 0) return;
- if (Array.from(el.children).filter(child => child.classList.contains("collapseExtraNodes")).length === 0) {
- el.parentNode.dataset.originalColor = window.getComputedStyle(el).backgroundColor;
- let span = document.createElement("span");
- span.classList.add("collapseExtraNodes");
- span.classList.add("collapsible");
- span.title = "Collapse all extra nodes of inlined posts within this one, including this - reverse with arrow button";
- span.innerHTML = `[Collapse extras]`;
- el.insertBefore(span, el.querySelector(".postMenuBtn"));
- span.style.paddingLeft = "6px";
- span.style.paddingRight = "1px";
- span.style.fontSize = "11px";
- span.style.color = "rgb(46, 53, 144)";
- }
- let collapseSpan = el.querySelector(".collapseExtraNodes");
- collapseSpan.removeEventListener("click", collapsePostsPostOn);
- collapseSpan.addEventListener("click", collapsePostsPostOn);
- });
- }
-
- function collapsePostsPostOn(e) {
- Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply")).forEach(el => {
- Array.from(el.querySelectorAll(".collapsible")).forEach(collapsibleEl => collapsibleEl.style.display = "none");
- });
- }
-
- function addExpandExtrasInPosts() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach((el, i) => {
- if (i === 0) {
- let buttonMenuSpan = el.querySelector(".postMenuBtn");
- buttonMenuSpan.removeEventListener("click", expandPostsThreadOn);
- buttonMenuSpan.addEventListener("click", expandPostsThreadOn);
- return;
- };
- let buttonMenuSpan = el.querySelector(".postMenuBtn");
- buttonMenuSpan.removeEventListener("click", expandPostsPostOn);
- buttonMenuSpan.addEventListener("click", expandPostsPostOn);
- });
- }
-
- function expandPostsPostOn(e) {
- Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply")).forEach(el => {
- Array.from(el.querySelectorAll(".collapsible")).forEach(collapsibleEl => collapsibleEl.style.display = "unset");
- });
- }
-
- function expandPostsThreadOn(e) {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach(el => {
- Array.from(el.querySelectorAll(".collapsible")).forEach(collapsibleEl => collapsibleEl.style.display = "unset");
- });
- }
-
- function addColorPosts() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach((el, i) => {
- if (i === 0) return;
- if (Array.from(el.children).filter(child => child.classList.contains("colorChange")).length === 0) {
- el.parentNode.dataset.originalColor = window.getComputedStyle(el).backgroundColor;
- let span = document.createElement("span");
- span.classList.add("colorChange");
- span.classList.add("collapsible");
- span.title = "Color all inlined posts within this one";
- let colorOn = document.createElement("span");
- let colorOff = document.createElement("span");
- colorOn.classList.add("colorOnPost");
- colorOff.classList.add("colorOffPost");
- colorOn.innerText = "Color Posts";
- colorOff.innerText = "Off";
- span.innerHTML = `[${colorOn.outerHTML} | ${colorOff.outerHTML}]`;
- el.insertBefore(span, el.querySelector(".postMenuBtn"));
- span.style.paddingLeft = "6px";
- span.style.paddingRight = "1px";
- span.style.fontSize = "11px";
- span.style.color = "rgb(46, 53, 144)";
- }
- let colorOn = el.querySelector(".colorOnPost");
- let colorOff = el.querySelector(".colorOffPost");
- colorOn.removeEventListener("click", colorPostsPostOn);
- colorOn.addEventListener("click", colorPostsPostOn);
- colorOff.removeEventListener("click", colorPostsPostOff);
- colorOff.addEventListener("click", colorPostsPostOff);
- });
- }
-
- function colorPostsPostOn(e) {
- //console.log("colorPostsPoston", e.target);
- Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply")).forEach(el => {
- let nums = getTwoToThreeHigherNums();
- let randomDiff = getAtLeastOneQuarterFromRandom();
- let mappedNums = nums.map((num, idx) => num > 0.5 ? getSpecificColorFromMappedNumIdx(idx) + (randomDiff * colorDiff) : getSpecificColorFromMappedNumIdx(idx) - (randomDiff * colorDiff));
- el.style.backgroundColor = `rgb(${mappedNums[0]}, ${mappedNums[1]}, ${mappedNums[2]})`;
- });
- }
-
- function colorPostsPostOff(e) {
- Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply")).forEach(el => {
- el.style.backgroundColor = `rgb(${postColor.r}, ${postColor.g}, ${postColor.b})`;
- });
- }
-
- function getTwoToThreeHigherNums() {
- while(true) {
- let arr = [Math.random(), Math.random(), Math.random()];
- let numbersAboveHalf = arr.filter(el => el > 0.5).length;
- if (numbersAboveHalf > 1 && numbersAboveHalf < 4) {
- if (numbersAboveHalf === 3) {
- if (arr.filter(el => el > 0.85).length > 2) return arr;
- } else return arr;
- }
- }
- }
-
- function getAtLeastOneQuarterFromRandom() {
- while(true) {
- let num = Math.random();
- if (num > 0.25) return num;
- }
- }
-
- function getSpecificColorFromMappedNumIdx(idx) {
- // if (idx === 0) return 215;
- // if (idx === 1) return 215;
- // else return 215;
- if (idx === 0) return postColor.r;
- if (idx === 1) return postColor.g;
- else return postColor.b;
- }
-
- function addPostsDraggableToggleThread() {
- let btn = document.querySelector(".op").querySelector(".postMenuBtn");
- let metaSpan = document.createElement("span");
- metaSpan.classList.add("postsDraggableContainer");
- metaSpan.classList.add("collapsible");
- let spanDrag = document.createElement("span");
- let spanDragReset = document.createElement("span");
- spanDragReset.classList.add("postsDraggableReset");
- spanDrag.classList.add("postsDraggableToggle");
- spanDrag.title = "Toggle for whether posts are draggable/movable";
- spanDrag.innerText = "Posts Draggable";
- spanDragReset.title = "Reset positions of all posts";
- spanDragReset.innerText = "Reset";
- metaSpan.innerHTML = `[${spanDrag.outerHTML} | ${spanDragReset.outerHTML}]`;
- btn.parentNode.insertBefore(metaSpan, btn);
- metaSpan.style.paddingLeft = "6px";
- metaSpan.style.paddingRight = "1px";
- metaSpan.style.fontSize = "11px";
- metaSpan.style.color = "rgb(46, 53, 144)";
- spanDrag = document.querySelector(".postsDraggableToggle");
- spanDrag.style.opacity = "1";
- spanDragReset = document.querySelector(".postsDraggableReset");
- spanDrag.addEventListener("click", postsDraggableToggle);
- spanDragReset.addEventListener("click", postsDraggableReset);
- }
-
- function postsDraggableReset() {
- let posts = Array.from(document.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- //post.style.position = "unset";
- post.style.top = "";
- post.style.bottom = "";
- post.style.left = "";
- post.style.right = "";
- });
- }
-
- let currentStartDragHorizontal = null;
- let currentStartDragVertical = null;
- let currentStartDragHorizontalDiff = null;
- let currentStartDragVerticalDiff = null;
- let currentStartDragNode = null;
- let currentDragZIndex = 1;
-
- function postsDraggableToggle(e) {
- if (e.target.style.opacity === "1") {
- e.target.style.opacity = "0.55";
- document.addEventListener("dragover", documentDragOver, true);
- document.addEventListener("drop", documentDrop, true);
- let posts = Array.from(document.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- if (post.draggable !== true) {
- post.draggable = true;
- post.addEventListener("dragstart", postDragStart, true);
- }
- });
- } else {
- e.target.style.opacity = "1";
- document.removeEventListener("dragover", documentDragOver);
- document.removeEventListener("drop", documentDrop);
- let posts = Array.from(document.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- if (post.draggable !== false) {
- post.draggable = false;
- post.removeEventListener("dragstart", postDragStart);
- }
- });
- }
- }
-
- function addPostDraggableTogglePost() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach((el, i) => {
- if (i === 0) return;
- if (Array.from(el.children).filter(child => child.classList.contains("postsDraggableContainer")).length === 0) {
- el.parentNode.dataset.originalColor = window.getComputedStyle(el).backgroundColor;
- let metaSpan = document.createElement("span");
- metaSpan.classList.add("postsDraggableContainer");
- metaSpan.classList.add("collapsible");
- let spanDrag = document.createElement("span");
- let spanDragReset = document.createElement("span");
- spanDragReset.classList.add("postsDraggableResetPost");
- spanDrag.classList.add("postsDraggableTogglePost");
- spanDrag.title = "Toggle for whether inlined posts are draggable/movable";
- spanDrag.innerText = "Posts Draggable";
- spanDragReset.title = "Reset positions of all inlined posts";
- spanDragReset.innerText = "Reset";
- metaSpan.innerHTML = `[${spanDrag.outerHTML} | ${spanDragReset.outerHTML}]`;
- el.insertBefore(metaSpan, el.querySelector(".postMenuBtn"));
- metaSpan.style.paddingLeft = "6px";
- metaSpan.style.paddingRight = "1px";
- metaSpan.style.fontSize = "11px";
- metaSpan.style.color = "rgb(46, 53, 144)";
- }
- let spanDrag = el.querySelector(".postsDraggableTogglePost");
- spanDrag.style.opacity = "1";
- let spanDragReset = el.querySelector(".postsDraggableResetPost");
- spanDrag.removeEventListener("click", postsDraggableTogglePost);
- spanDragReset.removeEventListener("click", postsDraggableResetPost);
- spanDrag.addEventListener("click", postsDraggableTogglePost);
- spanDragReset.addEventListener("click", postsDraggableResetPost);
- });
- }
-
- function postsDraggableResetPost(e) {
- let posts = Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- //post.style.position = "unset";
- post.style.top = "";
- post.style.bottom = "";
- post.style.left = "";
- post.style.right = "";
- });
- }
-
- function postsDraggableTogglePost(e) {
- if (e.target.style.opacity === "1") {
- e.target.style.opacity = "0.55";
- document.addEventListener("dragover", documentDragOver, true);
- document.addEventListener("drop", documentDrop, true);
- let posts = Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- if (post.draggable !== true) {
- post.draggable = true;
- post.addEventListener("dragstart", postDragStart, true);
- }
- });
- } else {
- e.target.style.opacity = "1";
- document.removeEventListener("dragover", documentDragOver);
- document.removeEventListener("drop", documentDrop);
- let posts = Array.from(e.target.parentNode.parentNode.parentNode.querySelectorAll(".post.reply"));
- posts.forEach(post => {
- if (post.draggable !== false) {
- post.draggable = false;
- post.removeEventListener("dragstart", postDragStart);
- }
- });
- }
- }
-
- function postDragStart(e) {
- e.dataTransfer.setData("text", e.target.outerHTML);
- //currentStartDragHorizontalDiff = Math.floor(e.clientX - e.target.getBoundingClientRect().left);
- //currentStartDragVerticalDiff = Math.floor(e.clientY - e.target.getBoundingClientRect().top);
- currentStartDragHorizontal = e.clientX;
- currentStartDragVertical = e.clientY + window.scrollY;
- currentStartDragNode = e.target;
- //e.target.style.position = "absolute";
- if (e.target.style.top === "") e.target.style.top = "0px";
- if (e.target.style.left === "") e.target.style.left = "0px";
- e.target.style.zIndex = JSON.stringify(currentDragZIndex);
- currentDragZIndex++;
- }
-
- function documentDragOver(e) {
- e.preventDefault();
- }
-
- function documentDrop(e) {
- e.preventDefault();
- currentStartDragNode.style.left = `${Number(currentStartDragNode.style.left.match(/([-\.\d]+)px/)[1]) + e.clientX - currentStartDragHorizontal}px`;
- currentStartDragNode.style.top = `${Number(currentStartDragNode.style.top.match(/([-\.\d]+)px/)[1]) + window.scrollY + e.clientY - currentStartDragVertical}px`;
- //currentStartDragNode.style.left = `${e.clientX - currentStartDragHorizontalDiff}px`;
- //currentStartDragNode.style.top = `${window.scrollY + e.clientY - currentStartDragVerticalDiff}px`;
- //currentStartDragNode.style.position = "absolute";
- if (currentStartDragNode.style.position !== "relative") currentStartDragNode.style.position = "relative";
- currentStartDragHorizontalDiff = null;
- currentStartDragVerticalDiff = null;
- currentStartDragNode = null;
- }
-
- function addRemoveYousInPost() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach(el => {
- if (Array.from(el.children).filter(el => el.classList.contains("removeYouPost")).length === 0) {
- let btn = el.querySelector(".postMenuBtn");
- let newSpan = document.createElement("span");
- newSpan.innerText = "[Remove (You)s]";
- newSpan.style.paddingLeft = "6px";
- newSpan.style.paddingRight = "1px";
- newSpan.style.fontSize = "11px";
- newSpan.style.color = "rgb(46, 53, 144)";
- newSpan.classList.add("removeYouPost");
- newSpan.classList.add("collapsible");
- newSpan.title = "Remove all (You)s from current post (works recursively downward)";
- btn.parentNode.insertBefore(newSpan, btn);
- }
- });
- Array.from(document.querySelectorAll(".removeYouPost")).forEach(el => {
- el.removeEventListener("click", removeYouPost);
- el.addEventListener("click", removeYouPost);
- });
- }
-
- function removeYouPost(e) {
- let post = e.target.parentNode.parentNode;
- Array.from(post.querySelectorAll("a.quotelink")).forEach(el => {
- el.innerText = el.innerText.replace(" (You)", "");
- });
- }
-
- function addEditabilityToPost() {
- Array.from(document.querySelectorAll(".postInfo.desktop")).forEach(el => {
- if (Array.from(el.children).filter(el => el.classList.contains("addEditability")).length === 0) {
- let btn = el.querySelector(".postMenuBtn");
- let newSpan = document.createElement("span");
- newSpan.innerText = "[Editable]";
- newSpan.style.paddingLeft = "6px";
- newSpan.style.paddingRight = "1px";
- newSpan.style.fontSize = "11px";
- newSpan.style.color = "rgb(46, 53, 144)";
- newSpan.classList.add("addEditability");
- newSpan.classList.add("collapsible");
- newSpan.title = "Make post type-editable";
- btn.parentNode.insertBefore(newSpan, btn);
- }
- });
- Array.from(document.querySelectorAll(".addEditability")).forEach(el => {
- el.removeEventListener("click", toggleEditabilityForPost);
- el.addEventListener("click", toggleEditabilityForPost);
- });
- }
-
- function toggleEditabilityForPost(e) {
- let flag = "false";
- if ((e.target.style.opacity === "1") || !e.target.style.opacity) {
- e.target.style.opacity = "0.55";
- flag = "true";
- } else {
- e.target.style.opacity = "1";
- flag = "false";
- }
- let post = e.target.parentNode.parentNode;
- let allEmbeddedPosts = Array.from(post.querySelectorAll(".postMessage"));
- allEmbeddedPosts.forEach(post => post.contentEditable = flag);
- }
-
- function qEV(e, node=e.target) {
- //console.log("quote clicked.");
- e.preventDefault();
-
- if (!node.classList.contains("linkfade")) {
- //if not grayed out, first time clicking, adding node
- node.classList.add("linkfade");
-
- //finding post and constructing new post
- let postsArr = Array.from(document.getElementsByClassName("postNum desktop")).filter(el => el.children[1].innerText === node.innerText.slice(2));
- let post = postsArr[0].parentNode.parentNode.parentNode;
- let newPost = post.cloneNode(true);
- //newPost.outerHTML = post.outerHTML;
- newPost.classList.add("inlined");
- newPost.children[1].classList.remove("highlight");
- newPost.style.display = "";
- newPost.style.marginTop = "10px";
- newPost.children[1].style.border = "1px solid rgba(172, 127, 127, 0.6)";
- newPost.children[1].style.borderRadius = "2px";
- newPost.children[0].style.display = "none";
-
- //adding to parent post
- if (node.parentNode.parentNode.parentNode.parentNode.children[2].classList.contains("file")) {
- Array.from(node.parentNode.parentNode.parentNode.parentNode.children[3].children).filter(el => el.classList.contains("quotedPostsContainer"))[0].appendChild(newPost);
- if (JSON.parse(localStorage.getItem("4chan-settings")).inlineQuotes) setTimeout(function() {node.parentNode.parentNode.parentNode.parentNode.children[3].children[0].remove();});
- } else {
- Array.from(node.parentNode.parentNode.parentNode.parentNode.children[2].children).filter(el => el.classList.contains("quotedPostsContainer"))[0].appendChild(newPost);
- if (JSON.parse(localStorage.getItem("4chan-settings")).inlineQuotes) setTimeout(function() {node.parentNode.parentNode.parentNode.parentNode.children[2].children[0].remove();});
- }
- setTimeout(function(){newPost.style.display = "";}, 10);
-
- //resetting event listeners
- resetQLEV();
- } else {
- //grayed out, second time clicking, removing node
- node.classList.remove("linkfade");
- let idx = node.parentNode.parentNode.parentNode.parentNode.children[2].classList.contains("file") ? 3 : 2;
- Array.from(node.parentNode.parentNode.parentNode.parentNode.children[idx].children).forEach(innerNode => {
- if (innerNode.classList.contains("quotedPostsContainer")) {
- Array.from(innerNode.children).forEach(el => {
- if (el.classList.contains("inlined") && node.innerText.slice(2) === el.children[1].children[1].children[3].children[1].innerText) el.remove();
- });
- }
- });
- }
- }
-
- function resetQLEV() {
- let newQuotesList = Array.from(document.getElementsByClassName("quotelink")).filter(node => window.getComputedStyle(node).getPropertyValue("font-size") === "10.6667px");
- newQuotesList.forEach(node => node.removeEventListener("click", qEV));
- newQuotesList.forEach(node => node.addEventListener("click", qEV));
- let newSpanList = Array.from(document.getElementsByTagName("span")).filter(el => {
- try {
- if (el.children.length > 0 && el.children[0].classList.contains("quotelink")) return true;
- } catch(error) {
- return false;
- }
- });
- newSpanList.forEach(el => el.removeEventListener("click", qSpanClick));
- newSpanList.forEach(el => el.addEventListener("click", qSpanClick));
- Array.from(document.getElementsByClassName("postInfo desktop")).forEach(el => el.children[0].removeEventListener("click", postRemove));
- addRemoveCapability();
- addCollapseAndExpand();
- let tesQuoteSpans = Array.from(document.getElementsByClassName("tessellateQuotes"));
- tesQuoteSpans.forEach(el => el.removeEventListener("click", tessellateQuotes));
- tesQuoteSpans.forEach(el => el.addEventListener("click", tessellateQuotes));
- addTessellationQuotes();
- addQuotedPostsContainer();
- addMediaZoom();
- addMediaFlow();
- addColorPosts();
- setPostColor();
- addPostDraggableTogglePost();
- addRemoveYousInPost();
- addEditabilityToPost();
- addCollapseExtrasInPosts();
- addExpandExtrasInPosts();
- expandPostsPostOn();
- }
-
- let observer = new MutationObserver(resetQLEV);
- observer.observe(document.getElementsByClassName("thread")[0], {childList: true});
-
- let quotePreviewObserver = new MutationObserver(quotePreviewHandler);
- quotePreviewObserver.observe(document.querySelector("body"), {childList: true});
-
- function quotePreviewHandler(newNodes) {
- if (newNodes[0] && newNodes[0].addedNodes.length > 0) newNodes[0].addedNodes.forEach(el => {if (el.id === "quote-preview") el.style.zIndex = currentDragZIndex++;});
- }