Portkey story export script

Display the whole story on one screen

  1. // ==UserScript==
  2. // @version 1.0
  3. // @name Portkey story export script
  4. // @namespace portkey
  5. // @description Display the whole story on one screen
  6. // @include *fanfiction.portkey.org/story/*
  7. // ==/UserScript==
  8.  
  9. function find(expr)
  10. {
  11. var posts = document.evaluate(expr, document, null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  12. var postsArray = new Array();
  13. for (var i = 0; i < posts.snapshotLength; ++i) {
  14. postsArray.push(posts.snapshotItem(i));
  15. }
  16. return postsArray;
  17. }
  18.  
  19. function addButtons(){
  20. // Adding buttons
  21. res = find("//div[@align=\"center\"]");
  22. insertNode = document.createElement("p");
  23. res[1].appendChild(insertNode);
  24. //creating links
  25. var addHeadersButton=document.createElement('a');
  26. addHeadersButton.href='javascript:';
  27. addHeadersButton.innerHTML='Headers';
  28. addHeadersButton.setAttribute('title','Add header to each chapter');
  29. var addIndexButton=document.createElement('a');
  30. addIndexButton.href='javascript:';
  31. addIndexButton.innerHTML='Index';
  32. addIndexButton.setAttribute('title','Create table of contents');
  33. var expAllButton=document.createElement('a');
  34. expAllButton.id='exportAllButton';
  35. expAllButton.href='javascript:';
  36. expAllButton.setAttribute('title','Show the whole story on one page');
  37. expAllButton.innerHTML='Story';
  38. var expButton=document.createElement('a');
  39. expButton.setAttribute('title','Show only text');
  40. expButton.href='javascript:';
  41. expButton.innerHTML='Text';
  42. var e = document.createElement('span');
  43. e.setAttribute('style','color:#cc0000');
  44. e.setAttribute('title','Export');
  45. e.innerHTML = "fE: ";
  46. var a = document.createElement('span');
  47. a.setAttribute('title','Add');
  48. a.setAttribute('style','color:#cc0000');
  49. a.innerHTML = "fA: ";
  50. // Adding listeners - that's the only way to do something after main code finsihed working;
  51. expAllButton.addEventListener('click',exportAll,false);
  52. expButton.addEventListener('click',exportCh,false);
  53. addHeadersButton.addEventListener('click',addHeaders,false);
  54.  
  55. insertNode.appendChild(e);
  56. insertNode.appendChild(expAllButton);
  57. insertNode.appendChild(document.createTextNode(' '));
  58. insertNode.appendChild(expButton);
  59. insertNode.appendChild(document.createTextNode(' '));
  60. insertNode.appendChild(a);
  61. insertNode.appendChild(addHeadersButton);
  62. insertNode.appendChild(document.createTextNode(' '));
  63. insertNode.appendChild(addIndexButton);
  64. insertNode.appendChild(document.createTextNode(' '));
  65.  
  66. }
  67.  
  68. //Adding buttons to page;
  69. addButtons();
  70.  
  71. //Adding table of contents
  72. function addIndex(){
  73. var storytext = document.getElementById('storytextp').firstChild; //Point of insert
  74. var chapters = document.getElementsByName('ffnee_chapter');
  75. //Creating base structure
  76. var index = document.createElement('div');
  77. index.innerHTML = '<h2>Table of contents</h2>';
  78. index.setAttribute('id','ffnee_index');
  79. var toC = document.createElement('ol');
  80. index.appendChild(toC);
  81. //Processing chapters
  82. for (var i=0;i<chapters.length;i++){
  83. var item = chapters.item(i); //chapter we are currently processing
  84. var id = item.getAttribute('id');
  85. var entry = document.createElement('li'); //Entry corresponding to the chapter in ToC
  86. entry.innerHTML = '<a href="#'+id+'">'+item.getAttribute('title')+'</a>';
  87. toC.appendChild(entry);
  88. }
  89. storytext.insertBefore(index,storytext.firstChild);
  90. }
  91. //adding headers, as entered by author
  92. function addHeaders(){
  93. var chapters = document.getElementsByName('ffnee_chapter');
  94. for (var i=0;i<chapters.length;i++){
  95. var item = chapters.item(i); //chapter to which we are adding a header
  96. var header = document.createElement('p');
  97. header.innerHTML = '<h2>Chapter '+(i+1)+': '+item.getAttribute('title')+'</h2>';
  98. item.insertBefore(header,item.firstChild);
  99. }
  100. }
  101.  
  102. function exportCh(){
  103. document.body.innerHTML='<div style=\'padding-left:2em;padding-right:2em;padding-top:1em;\'>'+document.getElementById('storytextp').innerHTML+'</div>';
  104. //Sadly, it is not possible to automatically copy text to clipboard in firefox without changing browser settings;
  105. }
  106. function exportAll(){
  107. // Main actions
  108. var expDiv = document.getElementById('exportAllButton');
  109. // Progress indicator
  110. var expText = expDiv.childNodes[0];
  111. var chapters = new Array();
  112. var chapterNumIndex=document.title.search(/Chapter:/)+8;
  113. //Getting number of chapters
  114. var hr=location.href.split(/\//);
  115. sturl="";
  116. getURL();
  117. var storyLength=getLength();
  118. if (storyLength == 1){
  119. expText.nodeValue = 'Oneshot';
  120. return;
  121. }
  122. var totalStoryLength = storyLength;//reference
  123. //launching retrieving of all chapters simultaneously
  124. for (var i=1;i<=storyLength;i++){
  125. loadChapter(i);
  126. }
  127. //Functions
  128.  
  129. function getURL(){
  130. for (var i=0;i<hr.length;i++){
  131. sturl+=hr[i];
  132. sturl+="/";
  133. if (hr[i]=="story"){
  134. sturl+=hr[i+1];
  135. return
  136. }
  137. }
  138. }
  139. // Converting chapters' array into a whole;
  140. function parseStory(){
  141. var numCh= chapters.length;
  142. //document.body.innerHTML=chapters[0];
  143. var appendNode=find("//td[@class=\"story\"]")[0];
  144. appendNode.parentNode.setAttribute("id","storytextp");
  145. appendNode.innerHTML= '';
  146. for (var i=0;i<numCh;i++){
  147. //findHeader(chapters[i]); //smart header search
  148. var st=chapters[i];
  149. st.setAttribute('name','ffnee_chapter');
  150. st.setAttribute('id','ffnee_ch'+i);
  151. if (i!=0){
  152. st.style.marginTop='10em';
  153. }
  154. appendNode.appendChild(st);
  155. }
  156. expText.nodeValue='story(re)';
  157. }
  158. // Getting number of chapters;
  159. function getLength(){
  160. var chNum=document.evaluate('//SELECT[@name=\"select5\"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  161. if (chNum.snapshotLength>0){
  162. var numChapters = chNum.snapshotItem(0).length;
  163. }else{
  164. numChapters = 1;
  165. }
  166. return (numChapters);
  167. }
  168. // This function loads chapters and extracts chapter's number and title
  169. function loadChapter(num){
  170. var currentURL=sturl+"/"+num;
  171. var xhr = new window.XMLHttpRequest();
  172. xhr.open("GET",currentURL);
  173. xhr.overrideMimeType("text/html; charset=ISO-8859-1");
  174. xhr.onreadystatechange = function(){
  175. if (xhr.readyState == 4){
  176. parseChapter(xhr.responseText, currentURL);
  177. storyLength--;
  178. if (storyLength==0){
  179. parseStory();
  180. }
  181. }
  182. }
  183. xhr.send("")
  184. }
  185. function parseChapter(chapterHtml, chapterURL){
  186. //getting chapter number
  187. var iChaptr = chapterURL.split(/\//);
  188. var chapterNumber=iChaptr[iChaptr.length-1];
  189. var t=document.createElement('div');
  190. t.innerHTML=chapterHtml;
  191. //extracting text only
  192. var ev='//td[@class=\"story\"]';
  193. var xpathResult = document.evaluate(ev,t,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  194. chapterContent=document.createElement('div');
  195.  
  196. chapterContent.setAttribute('title',getChapterName(t));
  197. chapterContent.innerHTML = xpathResult.snapshotItem(0).innerHTML;
  198. chapterContent.removeChild(chapterContent.firstChild);
  199. chapterContent.removeChild(chapterContent.lastChild);
  200. chapterContent.removeChild(chapterContent.lastChild);
  201. chapters[chapterNumber-1]=chapterContent;
  202. expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength;
  203. function getChapterName(obj){
  204. var select = obj.getElementsByTagName('select')[0].getElementsByTagName('option');
  205. for (var i=0;i<select.length;i++){
  206. if (select[i].getAttribute('selected')!=null){
  207. return(select[i].innerHTML);
  208. }
  209. }
  210. }
  211. }
  212. }