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; }