您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Display the whole story on one screen
- // ==UserScript==
- // @version 1.0
- // @name Portkey story export script
- // @namespace portkey
- // @description Display the whole story on one screen
- // @include *fanfiction.portkey.org/story/*
- // ==/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("//div[@align=\"center\"]");
- insertNode = document.createElement("p");
- res[1].appendChild(insertNode);
- //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';
- var e = document.createElement('span');
- e.setAttribute('style','color:#cc0000');
- e.setAttribute('title','Export');
- e.innerHTML = "fE: ";
- var a = document.createElement('span');
- a.setAttribute('title','Add');
- a.setAttribute('style','color:#cc0000');
- a.innerHTML = "fA: ";
- // 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);
- insertNode.appendChild(e);
- insertNode.appendChild(expAllButton);
- insertNode.appendChild(document.createTextNode(' '));
- insertNode.appendChild(expButton);
- insertNode.appendChild(document.createTextNode(' '));
- insertNode.appendChild(a);
- insertNode.appendChild(addHeadersButton);
- insertNode.appendChild(document.createTextNode(' '));
- insertNode.appendChild(addIndexButton);
- insertNode.appendChild(document.createTextNode(' '));
- }
- //Adding buttons to page;
- addButtons();
- //Adding table of contents
- function addIndex(){
- var storytext = document.getElementById('storytextp').firstChild; //Point of insert
- var chapters = document.getElementsByName('ffnee_chapter');
- //Creating base structure
- var index = document.createElement('div');
- index.innerHTML = '<h2>Table of contents</h2>';
- index.setAttribute('id','ffnee_index');
- var toC = document.createElement('ol');
- index.appendChild(toC);
- //Processing chapters
- for (var i=0;i<chapters.length;i++){
- var item = chapters.item(i); //chapter we are currently processing
- var id = item.getAttribute('id');
- var entry = document.createElement('li'); //Entry corresponding to the chapter in ToC
- entry.innerHTML = '<a href="#'+id+'">'+item.getAttribute('title')+'</a>';
- 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<chapters.length;i++){
- var item = chapters.item(i); //chapter to which we are adding a header
- var header = document.createElement('p');
- header.innerHTML = '<h2>Chapter '+(i+1)+': '+item.getAttribute('title')+'</h2>';
- item.insertBefore(header,item.firstChild);
- }
- }
- function exportCh(){
- document.body.innerHTML='<div style=\'padding-left:2em;padding-right:2em;padding-top:1em;\'>'+document.getElementById('storytextp').innerHTML+'</div>';
- //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 chapterNumIndex=document.title.search(/Chapter:/)+8;
- //Getting number of chapters
- var hr=location.href.split(/\//);
- sturl="";
- getURL();
- 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);
- }
- //Functions
- function getURL(){
- for (var i=0;i<hr.length;i++){
- sturl+=hr[i];
- sturl+="/";
- if (hr[i]=="story"){
- sturl+=hr[i+1];
- return
- }
- }
- }
- // Converting chapters' array into a whole;
- function parseStory(){
- var numCh= chapters.length;
- //document.body.innerHTML=chapters[0];
- var appendNode=find("//td[@class=\"story\"]")[0];
- appendNode.parentNode.setAttribute("id","storytextp");
- appendNode.innerHTML= '';
- for (var i=0;i<numCh;i++){
- //findHeader(chapters[i]); //smart header search
- var st=chapters[i];
- st.setAttribute('name','ffnee_chapter');
- st.setAttribute('id','ffnee_ch'+i);
- if (i!=0){
- st.style.marginTop='10em';
- }
- appendNode.appendChild(st);
- }
- expText.nodeValue='story(re)';
- }
- // Getting number of chapters;
- function getLength(){
- var chNum=document.evaluate('//SELECT[@name=\"select5\"]',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- if (chNum.snapshotLength>0){
- 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){
- var currentURL=sturl+"/"+num;
- var xhr = new window.XMLHttpRequest();
- xhr.open("GET",currentURL);
- xhr.overrideMimeType("text/html; charset=ISO-8859-1");
- xhr.onreadystatechange = function(){
- if (xhr.readyState == 4){
- parseChapter(xhr.responseText, currentURL);
- storyLength--;
- if (storyLength==0){
- parseStory();
- }
- }
- }
- xhr.send("")
- }
- function parseChapter(chapterHtml, chapterURL){
- //getting chapter number
- var iChaptr = chapterURL.split(/\//);
- var chapterNumber=iChaptr[iChaptr.length-1];
- var t=document.createElement('div');
- t.innerHTML=chapterHtml;
- //extracting text only
- var ev='//td[@class=\"story\"]';
- 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;
- chapterContent.removeChild(chapterContent.firstChild);
- chapterContent.removeChild(chapterContent.lastChild);
- chapterContent.removeChild(chapterContent.lastChild);
- chapters[chapterNumber-1]=chapterContent;
- expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength;
- function getChapterName(obj){
- var select = obj.getElementsByTagName('select')[0].getElementsByTagName('option');
- for (var i=0;i<select.length;i++){
- if (select[i].getAttribute('selected')!=null){
- return(select[i].innerHTML);
- }
- }
- }
- }
- }