NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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;
}