// ==UserScript== // @version 1.0 // @include *.fictionpress.com/s/* // @namespace ffnet // @name FictionPress story export script. // @author Alssn // @description Writes all chapters of the story on one page. // @downloadURL https://update.greasyfork.icu/scripts/16076/FictionPress%20story%20export%20script.user.js // @updateURL https://update.greasyfork.icu/scripts/16076/FictionPress%20story%20export%20script.meta.js // ==/UserScript== function find(expr) { var posts = document.evaluate(expr, document, null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); var postsArray = new Array(); for (var i = 0; i < posts.snapshotLength; ++i) { postsArray.push(posts.snapshotItem(i)); } return postsArray; } function addButtons(){ // Adding buttons // res = find("//f[@id='f_size']"); res = document.getElementById("f_size").parentNode; //creating links var addHeadersButton=document.createElement('a'); addHeadersButton.href='javascript:'; addHeadersButton.innerHTML='Headers'; addHeadersButton.setAttribute('title','Add header to each chapter'); var addIndexButton=document.createElement('a'); addIndexButton.href='javascript:'; addIndexButton.innerHTML='Index'; addIndexButton.setAttribute('title','Create table of contents'); var expAllButton=document.createElement('a'); expAllButton.id='exportAllButton'; expAllButton.href='javascript:'; expAllButton.setAttribute('title','Show the whole story on one page'); expAllButton.innerHTML='Story'; var expButton=document.createElement('a'); expButton.setAttribute('title','Show only text'); expButton.href='javascript:'; expButton.innerHTML='Text'; // Adding listeners - that's the only way to do something after main code finsihed working; expAllButton.addEventListener('click',exportAll,false); expButton.addEventListener('click',exportCh,false); addHeadersButton.addEventListener('click',addHeaders,false); addIndexButton.addEventListener('click',addIndex,false); //fE and fA var e = document.createElement('span'); e.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4'); e.setAttribute('title','Export'); e.innerHTML = "fE: "; var a = document.createElement('span'); a.setAttribute('title','Add'); a.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4'); a.innerHTML = "fA: "; res.insertBefore(document.createTextNode(' '),res.firstChild); res.insertBefore(addIndexButton,res.firstChild); res.insertBefore(document.createTextNode(' '),res.firstChild); res.insertBefore(addHeadersButton,res.firstChild); res.insertBefore(a,res.firstChild); res.insertBefore(document.createTextNode(' '),res.firstChild); res.insertBefore(expButton,res.firstChild); res.insertBefore(document.createTextNode(' '),res.firstChild); res.insertBefore(expAllButton,res.firstChild); res.insertBefore(e,res.firstChild); } //Adding buttons to page; addButtons(); //Adding table of contents function addIndex(){ var storytext = document.getElementById('storytext'); //Point of insert var chapters = document.getElementsByName('ffnee_chapter'); //Creating base structure var index = document.createElement('div'); index.innerHTML = '

Table of contents

'; index.setAttribute('id','ffnee_index'); var toC = document.createElement('ol'); index.appendChild(toC); //Processing chapters for (var i=0;i'+item.getAttribute('title')+''; toC.appendChild(entry); } storytext.insertBefore(index,storytext.firstChild); } //adding headers, as entered by author function addHeaders(){ var chapters = document.getElementsByName('ffnee_chapter'); for (var i=0;i'; item.insertBefore(header,item.firstChild); } } function exportCh(){ document.body.innerHTML='
'+document.getElementById('storytext').innerHTML+'
'; //Sadly, it is not possible to automatically copy text to clipboard in firefox without changing browser settings; } function exportAll(){ // Main actions var expDiv = document.getElementById('exportAllButton'); // Progress indicator var expText = expDiv.childNodes[0]; var chapters = new Array(); var hr=location.href; var chapterNumIndex=hr.search(/\/\d{1,3}\//); //Getting number of chapters var storyLength=getLength(); if (storyLength == 1){ expText.nodeValue = 'Oneshot'; return; } var totalStoryLength = storyLength;//reference //launching retrieving of all chapters simultaneously for (var i=1;i<=storyLength;i++){ loadChapter(i, function(chapterHtml, chapterUrl){ parseChapter(chapterHtml,chapterUrl); storyLength--; console.log(storyLength); if (storyLength == 0){ parseStory(); } }); } //Functions // Converting chapters' array into a whole; function parseStory(){ console.log('parsing story'); var numCh= chapters.length; //document.body.innerHTML=chapters[0]; var appendNode=document.getElementById('storytext'); appendNode.innerHTML= ''; for (var i=0;i0){ var numChapters = chNum.snapshotItem(0).length; }else{ numChapters = 1; } return (numChapters); } // This function loads chapters and extracts chapter's number and title function loadChapter(num, callback){ var replStr='\/'+String(num)+'\/'; var currentURL=hr.replace(/\/\d{1,3}\//,replStr); try{ var req = new XMLHttpRequest(); req.open('get',currentURL,true); req.onload= function(){ callback(req.responseText,currentURL); }; req.send(); }catch (e) { console.log(e); } } function parseChapter(chapterHtml, chapterURL){ //getting chapter number var iChaptr = String(chapterURL.match(/\/\d{1,3}\//)); var chapterNumber=iChaptr.substring(1,iChaptr.length-1); var t=document.createElement('div'); t.innerHTML=chapterHtml; //extracting text only var ev='//div[@id=\'storytext\']'; var xpathResult = document.evaluate(ev,t,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); chapterContent=document.createElement('div'); chapterContent.setAttribute('title',getChapterName(t)); chapterContent.innerHTML = xpathResult.snapshotItem(0).innerHTML; chapters[chapterNumber-1]=chapterContent; expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength; function getChapterName(obj){ var select = obj.getElementsByTagName('select')[1].getElementsByTagName('option'); for (var i=0;i