TCGM / Fanfiction.net Review Reply in Page

// ==UserScript==
// @name         Fanfiction.net Review Reply in Page
// @namespace default
// @version      1.0
// @description  Makes review reply buttons open inside the page on Fanfiction.net.
// @author       TCGM
// @match        https://www.fanfiction.net/r/*
// @grant        none
// @copyright 2018, TCGM (https://openuserjs.org//users/TCGM)
// @license MIT
// @updateURL https://openuserjs.org/meta/TCGM/Fanfiction.net_Review_Reply_in_Page.meta.js
// ==/UserScript==

var primaryThemeColor;
var secondaryThemeColor;
var buttonThemeColor;
var buttonBackgroundThemeColor;
var backgroundThemeColor;

var replyButtonElements;
var replyIframeElement;
var reviewWrapperElement;
var reviewListElement;

//Start Function
(function() {
    'use strict';

    // Your code here...
    findElements();
    injectCSS();
    fixReplyButtons();
})();

//Find all elements we will be working with.
function findElements() {
    replyButtonElements = getAllElementsWithAttributeValue("title", "Reply to Review");
    reviewListElement = document.getElementById("gui_table1i");
    reviewWrapperElement = reviewListElement.parentNode;

    var ffnNameElement = document.querySelector("#top > div.menulink > a");
    primaryThemeColor = $(ffnNameElement).css("color");

    var ffnBrowseButtonElement = document.querySelector("#zmenu > span > table > tbody > tr > td:nth-child(1) > div:nth-child(1) > a");
    buttonThemeColor = $(ffnBrowseButtonElement).css("color");
    buttonBackgroundThemeColor = $(ffnBrowseButtonElement).css("background");
}

//CSS Injection function
function injectCSS() {
    //Custom Review Reply button CSS.
    var css = 'a[title="Reply to Review"] { width:100px; height:30px; cursor: pointer; background:';
    css += buttonBackgroundThemeColor;
    css += '; display:block; border-radius:2px; margin:3px; }';
    css += 'a[title="Reply to Review"] img { width:32px; }';
    css += 'a[title="Reply to Review"]:after { content:"Reply"; color:'
    css += buttonThemeColor;
    css += '; }';
    //Reply Iframe CSS
    css += '#replyIframe { float:right; width:45%; overflow-x:hidden; }';
    //Main Review List CSS
    css += '#gui_table1i { -webkit-transition: all .3s ease; -moz-transition: all .3s ease; -ms-transition: all .3s ease; -o-transition: all .3s ease; transition: all .3s ease; }';
    //Main Review List CSS when Reply Iframe open
    css += '#gui_table1i.replyIframeOpen { width:50%; }';

    var head = document.head || document.getElementsByTagName('head')[0];
    var style = document.createElement('style');

    style.type = 'text/css';
    if (style.styleSheet){
        // This is required for IE8 and below.
        style.styleSheet.cssText = css;
    } else {
        style.appendChild(document.createTextNode(css));
    }

    head.appendChild(style);
}

//Fix the Review Reply buttons.
function fixReplyButtons() {
    for(var i=0; i<replyButtonElements.length; i++) {
        var replyButton = replyButtonElements[i];
        let replyButtonURL = replyButton.href;
        replyButton.onclick = function() { openReplyIframe(replyButtonURL); };
        replyButton.removeAttribute("href");
        replyButton.removeAttribute("target");
    }
}

//Opens reply iframe to the given webpage.
function openReplyIframe(url) {
    if(replyIframeElement == null) {
        replyIframeElement = document.createElement("iframe");
        reviewWrapperElement.insertBefore(replyIframeElement, reviewWrapperElement.firstChild);
        replyIframeElement.setAttribute("id", "replyIframe");
        replyIframeElement.onload = function() { replyIframeLoaded(); };
    }

    replyIframeElement.style.display = "none";
    replyIframeElement.src = url;
    reviewListElement.classList.add('replyIframeOpen');
    replyIframeElement.style.height = reviewWrapperElement.clientHeight+"px";
}

//Reply iframe loaded callback function.
function replyIframeLoaded() {
    injectIframeCSS();

    replyIframeElement.style.display = "block";

    const y = replyIframeElement.getBoundingClientRect().top + window.scrollY;
    window.scroll({
        top: y,
        behavior: 'smooth'
    });
}

//Iframe CSS Injection function
function injectIframeCSS() {
    //Custom Review Reply button CSS.
    var css = "";
    //CSS for overriding Iframe uneeded FFN website elements.
    css += '#top > div, body > div.zmenu, #content_wrapper_inner > table > tbody > tr:nth-child(2) > td:nth-child(1), #content_wrapper_inner > table > tbody > tr:nth-child(2) > td:nth-child(2) > div:nth-child(1), #content_wrapper_inner > table > tbody > tr:nth-child(1) > td, #p_footer { display: none; }';
    css += 'html, div, body { min-width:95%!important; overflow-y: auto; overflow-x: hidden; background-color:'
    css += $(document.getElementById("content_wrapper_inner")).css("background-color");
    css += ';}';
    var head = replyIframeElement.contentDocument.head || replyIframeElement.contentDocument.getElementsByTagName('head')[0];
    var style = replyIframeElement.contentDocument.createElement('style');

    style.type = 'text/css';
    if (style.styleSheet){
        // This is required for IE8 and below.
        style.styleSheet.cssText = css;
    } else {
        style.appendChild(replyIframeElement.contentDocument.createTextNode(css));
    }

    head.appendChild(style);
}

//Custom Element Attribute Finding function
function getAllElementsWithAttributeValue(attribute, value)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName('*');
  for (var i = 0, n = allElements.length; i < n; i++)
  {
    if (allElements[i].getAttribute(attribute) !== null)
    {
        if(allElements[i].getAttribute(attribute) == value) {
            // Element exists with attribute. Add to array.
            matchingElements.push(allElements[i]);
        }
    }
  }
  return matchingElements;
}