barchive image and quote fixer

replaces thumbnails with full image or webm on click, inlines "quoted by" posts on click, can remove posts, tessellate inlined posts, tessellate entire thread, expand/collapse all 'quoted by' posts, can color posts recursively downward or entire thread (helps keep track of deeply-embedded conversations), can hide all extra options on posts via toggle in OP, can change media size when expanded, can drag posts around via toggle in OP

As of 2019-04-20. See the latest version.

// ==UserScript==
// @name         barchive image and quote fixer
// @namespace    thebarchive
// @version      0.8
// @description  replaces thumbnails with full image or webm on click, inlines "quoted by" posts on click, can remove posts, tessellate inlined posts, tessellate entire thread, expand/collapse all 'quoted by' posts, can color posts recursively downward or entire thread (helps keep track of deeply-embedded conversations), can hide all extra options on posts via toggle in OP, can change media size when expanded, can drag posts around via toggle in OP
// @author       DUVish
// @match        https://thebarchive.com/b/thread/*
// @match        https://archived.moe/*/thread/*
// @grant        none
// ==/UserScript==

$(".thread_image_link").on("click", function(e) {
  e.preventDefault();
});

Array.from($(".post_data")).forEach(el => {
    el.innerHTML += `<span class="expandAllQuotes collapsible" style="font-size: 10px;position: relative;top: -2px;padding-left: 1px;color: #7fa5c6;opacity: 0.95;padding-right: 0px;" title="Expand all 'quoted by' posts">[↓]</span>`;
});

Array.from($(".post_data")).forEach(el => {
    el.innerHTML += `<span class="collapseAllQuotes collapsible" style="font-size: 10px;position: relative;top: -2px;padding-left: 3px;color: #7fa5c6;opacity: 0.95;padding-right: 6px;" title="Collapse all 'quoted by' posts">[↑]</span>`;
});

Array.from($(".post_data")).forEach(el => {
    el.innerHTML += '<span class="tessellatePost collapsible" style="font-size: 10px;position: relative;top: -2px;padding-left: 4px;color: #7fa5c6;opacity: 0.95;padding-right: 13px;">[Tessellate]</span>';
});

document.querySelector(".post_data").innerHTML += '<span class="tessellateThread" style="font-size: 10px;position: relative;top: -2px;padding-left: 2px;color: #7fa5c6;opacity: 0.95;padding-right: 11px;">[Tessellate Thread]</span>';

document.querySelector(".post_data").innerHTML += '<span class="colorPosts" style="font-size: 10px;position: relative;top: -2px;padding-left: 2px;color: #7fa5c6;opacity: 0.95;padding-right: 11px;" title="Color all posts in thread">[<span class="colorOn">Color Posts</span> | <span class="colorOff">Off</span>]</span>';

Array.from($(".post_data")).forEach((el, i) => {
    if (i === 0) return;
    el.innerHTML += '<span class="colorPosts collapsible" style="font-size: 10px;position: relative;top: -2px;padding-left: 0px;color: #7fa5c6;opacity: 0.95;padding-right: 8px;right:2px" title="Color all posts in thread">[<span class="colorPostOn">Color Posts</span> | <span class="colorPostOff">Off</span>]</span>';
});

Array.from($(".post_data")).forEach(el => {
    el.children[8].children[0].style.paddingLeft = "0px";
    el.children[8].children[0].style.marginLeft = "-3px";
    el.innerHTML += '<span class="postRemove collapsible" style="font-size: 9.5px;position: relative;top: -2px;padding-left: 3px;color: darkgrey;opacity: 0.45;">Remove</span>';
});

Array.from(document.querySelectorAll(".text")).forEach(el => el.innerHTML += '<span class="inlinedQuotesContainer"></span>');

setTimeout(function() {document.querySelector(".colorOn").addEventListener("click", function(e) {
  Array.from(document.getElementsByClassName("post_wrapper")).forEach(el => {el.style.backgroundColor = `rgb(${Math.random() < 0.5 ? 40 - Math.floor(Math.random() * 16) : 40 + Math.floor(Math.random() * 16)}, ${Math.random() < 0.5 ? 42 - Math.floor(Math.random() * 16) : 42 + Math.floor(Math.random() * 16)}, ${Math.random() < 0.5 ? 46 - Math.floor(Math.random() * 16) : 46 + Math.floor(Math.random() * 16)})`;});
});}, 1800);

setTimeout(function() {document.querySelector(".colorOff").addEventListener("click", function(e) {
  Array.from(document.getElementsByClassName("post_wrapper")).forEach(el => {el.style.backgroundColor = `#282a2e`;});
});}, 1800);

$(".colorPostOn").on("click", function(e) {
  Array.from(e.target.parentNode.parentNode.parentNode.parentNode.querySelectorAll(".post_wrapper")).forEach(el => {el.style.backgroundColor = `rgb(${Math.random() < 0.5 ? 40 - Math.floor(Math.random() * 16) : 40 + Math.floor(Math.random() * 16)}, ${Math.random() < 0.5 ? 42 - Math.floor(Math.random() * 16) : 42 + Math.floor(Math.random() * 16)}, ${Math.random() < 0.5 ? 46 - Math.floor(Math.random() * 16) : 46 + Math.floor(Math.random() * 16)})`;});
});

$(".colorPostOff").on("click", function(e) {
  Array.from(e.target.parentNode.parentNode.parentNode.parentNode.querySelectorAll(".post_wrapper")).forEach(el => {el.style.backgroundColor = `#282a2e`;});
});

$(".postRemove").on("click", function(e) {
    postRemove(e, this);
});

$(".backlink").on("click", function(e) {
    inOnClickFunc(e, this);
});

function postRemove(e, node) {
    let possibleThread = node.parentNode.parentNode.parentNode.parentNode.parentNode;
    let possibleArticle = node.parentNode.parentNode.parentNode.parentNode;
    node.parentNode.parentNode.parentNode.remove();
    possibleArticle.style.display = "none";
    //if (possibleThread.tagName === "ASIDE");
}

function inOnClickFunc(e, node) {
    e.preventDefault();
    backlinkClick(e, node);
    backlinkReset(e, node);
}

document.querySelector("head").innerHTML += '<style>.clicked {opacity: 0.3;}</style>';

document.querySelector("title").innerText = "/b/ - " + document.querySelector(".text").innerText;

$(".tessellatePost").on("click", function(e) {
    tessellatePost(e, this);
});


setTimeout(function() {document.querySelector(".tessellateThread").addEventListener("click", function(e) {
    tessellateThread(e);
});}, 1500);

function tessellatePost(e, node) {
  let container = node.parentNode.parentNode.parentNode.parentNode.querySelector(".inlinedQuotesContainer");
  let tesSpan = node.parentNode.parentNode.parentNode.parentNode.querySelector(".tessellatePost");
  if (container.style.display !== "flex") {
    container.style.display = "flex";
    container.style.flexWrap = "wrap";
    tesSpan.style.opacity = "0.45";
    tesSpan.style.color = "darkgrey";
  } else {
    container.style.display = "";
    container.style.flexWrap = "";
    tesSpan.style.opacity = "0.95";
    tesSpan.style.color = "#7fa5c6";
  }
}

function tessellateThread(e) {
  let container = document.querySelector(".posts");
  let tesSpan = e.target;
  if (container.style.display !== "flex") {
    let threadImgBottomBound = document.querySelector(".thread_image_box").getBoundingClientRect().bottom;
    let dividerTopBound = document.querySelector(".thread_tools_bottom").getBoundingClientRect().top;
    let diff = threadImgBottomBound - dividerTopBound;
    if (threadImgBottomBound > dividerTopBound)  document.querySelector(".thread_tools_bottom").style.paddingBottom = `${diff + 10}px`;
    Array.from(document.getElementsByClassName("post_controls")).forEach(el => el.children[0].style.display = "none");
    container.style.display = "flex";
    container.style.flexWrap = "wrap";
    tesSpan.style.opacity = "0.45";
    tesSpan.style.color = "darkgrey";
  } else {
    Array.from(document.getElementsByClassName("post_controls")).forEach(el => el.children[0].style.display = "");
    document.querySelector(".thread_tools_bottom").style.paddingBottom = "";
    container.style.display = "";
    container.style.flexWrap = "";
    tesSpan.style.opacity = "0.95";
    tesSpan.style.color = "#7fa5c6";
  }
}

$(".expandAllQuotes").on("click", function(e) {
  expandAllQuotes(e, this);
});

$(".collapseAllQuotes").on("click", function(e) {
  collapseAllQuotes(e, this);
});

function expandAllQuotes(e, node) {
  Array.from(node.parentNode.parentNode.parentNode.querySelector(".backlink_list").children[0].children).filter(el => !el.classList.contains("clicked")).forEach(el => $(el).trigger("click"));
}

function collapseAllQuotes(e, node) {
  Array.from(node.parentNode.parentNode.parentNode.querySelector(".backlink_list").children[0].children).filter(el => el.classList.contains("clicked")).forEach(el => $(el).trigger("click"));
}

function backlinkClick(e, node) {
    e.preventDefault();
    let targetID = node.innerHTML.slice(8);
    if (!node.classList.contains("clicked")) {
        node.classList.add("clicked");
        //console.log("targetID is", targetID, $("#"+targetID));
        let newPost = $("#"+targetID)[0].cloneNode(true);
        newPost.style.border = "1px solid #0b0e1580";
        newPost.style.borderRadius = "6px";
        newPost.style.marginTop = "13px";
        setTimeout(function(){newPost.classList.remove("highlight");}, 10);
        node.parentNode.parentNode.parentNode.children[node.parentNode.parentNode.parentNode.children[0].classList.contains("post_file") ? 4 : 2].getElementsByClassName("inlinedQuotesContainer")[0].appendChild(newPost);
    } else {
        node.classList.remove("clicked");
        Array.from(node.parentNode.parentNode.parentNode.children[node.parentNode.parentNode.parentNode.children[0].classList.contains("post_file") ? 4 : 2].getElementsByClassName("inlinedQuotesContainer")[0].children)
            .filter(el => el.id === targetID).forEach(el => el.remove());
    }
}

function backlinkReset(e, node) {
    $(".backlink").off();
    $(".backlink").on("click", function(e) {
        inOnClickFunc(e, this);
    });
    $(".post_image").off();
    $(".post_image").on("click", function(e) {
        settingClickHandler(e, this);
    });
    $(".tessellatePost").off();
    $(".tessellatePost").on("click", function(e) {
        tessellatePost(e, this);
    });
    $(".postRemove").off();
    $(".postRemove").on("click", function(e) {
        postRemove(e, this);
    });
    $(".expandAllQuotes").off();
    $(".expandAllQuotes").on("click", function(e) {
      expandAllQuotes(e, this);
    });
    $(".collapseAllQuotes").off();
    $(".collapseAllQuotes").on("click", function(e) {
      collapseAllQuotes(e, this);
    });
}

$(".post_image").on("click", function(e) {
    settingClickHandler(e, this);
});

function settingClickHandler(e, node) {
    e.preventDefault();
    if (node === document.getElementsByClassName("post_image")[0]) {
        node.src = node.parentNode.href;
        node.attributes.removeNamedItem("height");
        node.attributes.removeNamedItem("width");
    } else {
        if (node.src.split("/")[5] === "thumb") {
            let fileRow = node.parentNode.parentNode.parentNode.querySelector(".post_file");
            let widthHeightArr = fileRow.children[2].innerText.split(", ")[1].trim().split("x");
            if (fileRow.children[1].href.slice(-4) === "webm") {
                let newVideoNode = document.createElement("video");
                newVideoNode.src = fileRow.children[1].href;
                newVideoNode.controls = true;
                newVideoNode.autoplay = true;
                newVideoNode.loop = true;
                newVideoNode.width = widthHeightArr[0];
                node.parentNode.insertBefore(newVideoNode, node);
                node.style.display = "none";
                let newSpan = document.createElement("span");
                newSpan.style.paddingLeft = "5px";
                newSpan.style.color = "#81a2be";
                newSpan.innerText = "[close webm]";
                fileRow.appendChild(newSpan);
                let sizeSpan = document.createElement("span");
                let increaseSize = document.createElement("span");
                increaseSize.classList.add("videoIncreaseSize");
                let decreaseSize = document.createElement("span");
                decreaseSize.classList.add("videoDecreaseSize");
                let increaseSizeMore = document.createElement("span");
                increaseSizeMore.classList.add("videoIncreaseSizeMore");
                increaseSizeMore.innerHTML = `(<span style="font-size: 17px; position: relative; top: 2px">++</span>)`;
                let decreaseSizeMore = document.createElement("span");
                decreaseSizeMore.classList.add("videoDecreaseSizeMore");
                decreaseSizeMore.innerHTML = `(<span style="font-size: 24px; position: relative; top: 3.5px">--</span>)`;
                decreaseSizeMore.style.paddingRight = "4px";
                sizeSpan.classList.add("sizeSpan");
                increaseSize.innerText = "(++)";
                increaseSize.style.padding = "0px 4px";
                decreaseSize.innerText = "(--)";
                decreaseSize.style.padding = "0px 4px";
                sizeSpan.style.paddingLeft = "5px";
                sizeSpan.style.color = "#81a2be";
                let resetSpan = document.createElement("span");
                resetSpan.innerText = "Reset";
                resetSpan.classList.add("resetMediaSize");
                resetSpan.style.paddingLeft = "4px";
                resetSpan.style.position = "relative";
                resetSpan.style.top = "1px";
                sizeSpan.innerHTML = `[Size - ${decreaseSize.outerHTML} ${decreaseSizeMore.outerHTML} | ${increaseSize.outerHTML} ${increaseSizeMore.outerHTML} | ${resetSpan.outerHTML} ]`;
                fileRow.appendChild(sizeSpan);
                newVideoNode.addEventListener("click", function(e) {
                  if (e.target.paused) e.target.play();
                  else e.target.pause();
                }, false);
                newSpan.addEventListener("click", function(e) {
                  newVideoNode.remove();
                  node.style.display = "";
                  newSpan.remove();
                  sizeSpan.remove();
                });
                fileRow.querySelector(".resetMediaSize").addEventListener("click", function(e) {
                  newVideoNode.width = widthHeightArr[0];
                });
                fileRow.querySelector(".videoIncreaseSize").addEventListener("click", function(e) {
                  let numWidth = Number(newVideoNode.width);
                  newVideoNode.width = `${(numWidth + 10)}`;
                });
                fileRow.querySelector(".videoDecreaseSize").addEventListener("click", function(e) {
                  let numWidth = Number(newVideoNode.width);
                  newVideoNode.width = numWidth > 10 ? `${(numWidth - 10)}` : "0";
                });
                fileRow.querySelector(".videoIncreaseSizeMore").addEventListener("click", function(e) {
                  let numWidth = Number(newVideoNode.width);
                  newVideoNode.width = `${(numWidth + 100)}`;
                });
                fileRow.querySelector(".videoDecreaseSizeMore").addEventListener("click", function(e) {
                  let numWidth = Number(newVideoNode.width);
                  newVideoNode.width = numWidth > 100 ? `${(numWidth - 100)}` : "0";
                });
                return;
            }
            let fileExt = fileRow.children[1].href.split(".")[2];
            node.dataset.originalSrc = node.src;
            node.src = node.parentNode.href;
            node.style.width = widthHeightArr[0] + "px";
            node.style.height = widthHeightArr[1] + "px";
            let sizeSpan = document.createElement("span");
            sizeSpan.classList.add("mediaChangeSize");
            let increaseSize = document.createElement("span");
            increaseSize.classList.add("mediaIncreaseSize");
            increaseSize.style.padding = "0px 4px";
            let decreaseSize = document.createElement("span");
            decreaseSize.classList.add("mediaDecreaseSize");
            let increaseSizeMore = document.createElement("span");
            increaseSizeMore.classList.add("mediaIncreaseSizeMore");
            increaseSizeMore.innerHTML = `(<span style="font-size: 17px; position: relative; top: 2px">++</span>)`;
            let decreaseSizeMore = document.createElement("span");
            decreaseSizeMore.classList.add("mediaDecreaseSizeMore");
            decreaseSizeMore.innerHTML = `(<span style="font-size: 24px; position: relative; top: 3.5px">--</span>)`;
            decreaseSizeMore.style.padding = "0px 4px";
            decreaseSize.style.paddingLeft = "4px";
            increaseSize.innerText = "(++)";
            decreaseSize.innerText = "(--)";
            let resetSpan = document.createElement("span");
            resetSpan.innerText = "Reset";
            resetSpan.classList.add("resetMediaSize");
            resetSpan.style.paddingLeft = "4px";
            resetSpan.style.position = "relative";
            resetSpan.style.top = "1px";
            sizeSpan.innerHTML = `[Size - ${decreaseSize.outerHTML} ${decreaseSizeMore.outerHTML} | ${increaseSize.outerHTML} ${increaseSizeMore.outerHTML} | ${resetSpan.outerHTML} ]`;
            sizeSpan.style.paddingLeft = "5px";
            sizeSpan.style.color = "#81a2be";
            fileRow.appendChild(sizeSpan);
            fileRow.querySelector(".resetMediaSize").addEventListener("click", function(e) {
              node.style.width = widthHeightArr[0] + "px";
              node.style.height = widthHeightArr[1] + "px";
            });
            fileRow.querySelector(".mediaIncreaseSize").addEventListener("click", function(e) {
              let numWidth = Number(node.style.width.match(/(\d+)px/)[1]);
              let numHeight = Number(node.style.height.match(/(\d+)px/)[1]);
              node.style.width = `${numWidth + 10}px`;
              node.style.height = `${numHeight + 10}px`;
            });
            fileRow.querySelector(".mediaDecreaseSize").addEventListener("click", function(e) {
              let numWidth = Number(node.style.width.match(/(\d+)px/)[1]);
              node.style.width = numWidth > 10 ? `${numWidth - 10}px` : "0px";
              let numHeight = Number(node.style.height.match(/(\d+)px/)[1]);
              node.style.height = numHeight > 10 ? `${numHeight - 10}px` : "0px";
            });
            fileRow.querySelector(".mediaIncreaseSizeMore").addEventListener("click", function(e) {
              let numWidth = Number(node.style.width.match(/(\d+)px/)[1]);
              let numHeight = Number(node.style.height.match(/(\d+)px/)[1]);
              node.style.width = `${numWidth + 100}px`;
              node.style.height = `${numHeight + 100}px`;
            });
            fileRow.querySelector(".mediaDecreaseSizeMore").addEventListener("click", function(e) {
              let numWidth = Number(node.style.width.match(/(\d+)px/)[1]);
              node.style.width = numWidth > 100 ? `${numWidth - 100}px` : "0px";
              let numHeight = Number(node.style.height.match(/(\d+)px/)[1]);
              node.style.height = numHeight > 100 ? `${numHeight - 100}px` : "0px";
            });
        } else {
            node.src = node.dataset.originalSrc;
            node.style.width = "";
            node.style.height = "";
            node.parentNode.parentNode.parentNode.querySelector(".mediaChangeSize").remove();
        }
    }
}

Array.from(document.querySelectorAll(".backlink.op")).forEach(el => el.innerText += "  (OP)");

document.querySelector(".post_data").innerHTML += '<span class="removeExtras" style="font-size: 10px;position: relative;top: -2px;padding-left: 8px;color: #7fa5c6;opacity: 0.95;padding-right: 11px;" title="Remove extra options from all posts">[Remove Extras]</span>';

document.querySelector(".removeExtras").addEventListener("click", function(e) {
  if (e.target.style.opacity === "0.95") {
    e.target.style.opacity = "0.55";
    Array.from(document.querySelectorAll(".collapsible")).forEach(el => el.style.display = "none");
  } else {
    e.target.style.opacity = "0.95";
    Array.from(document.querySelectorAll(".collapsible")).forEach(el => el.style.display = "unset");
  }
});

document.querySelector(".post_data").innerHTML += `<span class="postsDraggableContainer" style="font-size: 10px;position: relative;top: -2px;padding-left: 8px;color: #7fa5c6;opacity: 0.95;padding-right: 11px;">[<span class="postsDraggableToggle" style="opacity: 0.95;">Posts Draggable</span> | <span class="postsDraggableReset">Reset</span>]</span>`;

let currentNode = null;
let startDragX = null;
let startDragY = null;
let currentZIndex = 1;

document.querySelector(".postsDraggableToggle").addEventListener("click", function(e) {
  if (e.target.style.opacity === "0.95") {
    e.target.style.opacity = "0.55";
    Array.from(document.querySelectorAll("article.post")).forEach(el => {
      el.draggable = true;
      el.ondragstart = function(e) {
        e.stopPropagation();
        e.dataTransfer.setData("postData", e.target.innerHTML);
        currentNode = e.target;
        startDragX = e.clientX;
        startDragY = window.scrollY + e.clientY;
        e.target.style.position = "relative";
        if (e.target.style.top === "") e.target.style.top = "0px";
        if (e.target.style.left === "") e.target.style.left = "0px";
      };
    });
    document.addEventListener("dragover", docDragOver);
    document.addEventListener("drop", postDrop);
  } else {
    e.target.style.opacity = "0.95";
    Array.from(document.querySelectorAll("article.post")).forEach(el => el.draggable = false);
    document.removeEventListener("dragover", docDragOver);
    document.removeEventListener("drop", postDrop);
  }
});

function docDragOver(e) {
  e.preventDefault();
}

function postDrop(e) {
  let currentX = e.clientX;
  let currentY = window.scrollY + e.clientY;
  let newX = currentX - startDragX;
  let newY = currentY - startDragY;
  currentNode.style.top = `${Number(currentNode.style.top.match(/(-?\d+)px/)[1]) + newY}px`;
  currentNode.style.left = `${Number(currentNode.style.left.match(/(-?\d+)px/)[1]) + newX}px`;
  currentNode.style.zIndex = `${currentZIndex++}`;
  currentNode = null;
  startDragX = null;
  startDragY = null;
}

document.querySelector(".postsDraggableReset").addEventListener("click", function(e) {
  Array.from(document.querySelectorAll("article.post")).forEach(el => {
    el.style.top = "0px";
    el.style.left = "0px";
    el.style.zIndex = "";
  });
});