// ==UserScript== // @name AO3: Kudos/hits ratio // @description Replace hitcount with kudos/hits percentage. Sort works on the page by this ratio. // @namespace // @author Min // @version 1.0 // @grant none // @include http://archiveofourown.org/* // @include https://archiveofourown.org/* // @downloadURL none // ==/UserScript== // ~~ OPTIONS ~~ // // change hitcount to kudos/hits: 1 - automatically; 0 - after clicking the option in the menu var alwayscount = 0; // sort works on this page by kudos/hits ratio in descending order: 1 - automatically; 0 - after clicking the option in the menu var alwayssort = 0; // colour background depending on percentage: 1 - yes; 0 - no var colourbg = 1; // lvl1 & lvl2 - percentage levels separating red, yellow and green background; ratio_red, ratio_yellow, ratio_green - background colours var ratio_red = '#ffdede'; var lvl1 = 4; var ratio_yellow = '#fdf2a3'; var lvl2 = 7; var ratio_green = '#c4eac3'; // ~~ END OF OPTIONS ~~ // // STUFF HAPPENS BELOW // //check user settings if (typeof(Storage) !== 'undefined') { var alwayscountset = localStorage.getItem('alwayscountlocal'); var alwayssortset = localStorage.getItem('alwayssortlocal'); if (alwayscountset == 'yes') { alwayscount = 1; } if (alwayssortset == 'yes') { alwayssort = 1; } } //set defaults for countableness and sortableness var countable = 0; var sortable = 0; //check if it's a list of works or bookmarks, or header on work page, and attach the right menu whatDo(); if (alwayscount == 1) { countRatio(); if (alwayssort == 1) { sortWorks(); } } function whatDo() { var allstats1 = document.querySelectorAll('dl.stats'); if (allstats1.length > 0) { //check if it's a list of works or bookmarks, or header on work page var blurbclass = allstats1[0].parentNode.className; if (blurbclass.indexOf('work') > -1 || blurbclass.indexOf('bookmark') > -1) { countable = 1; sortable = 1; addRatioMenu('sort'); } else if (blurbclass.indexOf('stats') > -1) { countable = 1; addRatioMenu('count'); } } } function addRatioMenu(type) { //get the header menu var navMenuButtons = document.querySelector('ul.primary.navigation.actions'); //create button parts var liMenuButton = document.createElement('li'); liMenuButton.className = 'dropdown'; var aMenuButton = document.createElement('a'); var textMenuButton = document.createTextNode('Kudos/hits'); //append button to menu aMenuButton.appendChild(textMenuButton); liMenuButton.appendChild(aMenuButton); navMenuButtons.appendChild(liMenuButton); //create and append dropdown menu var dropMenu = document.createElement('ul'); dropMenu.className = 'menu dropdown-menu'; liMenuButton.appendChild(dropMenu); //create button - count var liButtonCount = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Count on this page'); aButton.appendChild(textButton); liButtonCount.appendChild(aButton); liButtonCount.onclick = function(){countRatio();}; //create button - sort var liButtonSort = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Sort on this page'); aButton.appendChild(textButton); liButtonSort.appendChild(aButton); liButtonSort.onclick = function(){sortWorks();}; //create button - settings var liButtonSettings = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('== Settings (click to change): =='); aButton.appendChild(textButton); liButtonSettings.appendChild(aButton); //create button - always count var liButtonAlwaysCount = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Count on every page: YES'); aButton.appendChild(textButton); liButtonAlwaysCount.appendChild(aButton); liButtonAlwaysCount.onclick = function(){localStorage.setItem('alwayscountlocal', 'no'); dropMenu.replaceChild(liButtonNotAlwaysCount, liButtonAlwaysCount);}; //create button - not always count var liButtonNotAlwaysCount = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Count on every page: NO'); aButton.appendChild(textButton); liButtonNotAlwaysCount.appendChild(aButton); liButtonNotAlwaysCount.onclick = function(){localStorage.setItem('alwayscountlocal', 'yes'); dropMenu.replaceChild(liButtonAlwaysCount, liButtonNotAlwaysCount);}; //create button - always sort var liButtonAlwaysSort = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Sort on every page: YES'); aButton.appendChild(textButton); liButtonAlwaysSort.appendChild(aButton); liButtonAlwaysSort.onclick = function(){localStorage.setItem('alwayssortlocal', 'no'); dropMenu.replaceChild(liButtonNotAlwaysSort, liButtonAlwaysSort);}; //create button - not always sort var liButtonNotAlwaysSort = document.createElement('li'); var aButton = document.createElement('a'); var textButton = document.createTextNode('Sort on every page: NO'); aButton.appendChild(textButton); liButtonNotAlwaysSort.appendChild(aButton); liButtonNotAlwaysSort.onclick = function(){localStorage.setItem('alwayssortlocal', 'yes'); dropMenu.replaceChild(liButtonAlwaysSort, liButtonNotAlwaysSort);}; //append buttons to the dropdown menu dropMenu.appendChild(liButtonCount); if (type == 'sort') { dropMenu.appendChild(liButtonSort); } if (typeof(Storage) !== 'undefined') { dropMenu.appendChild(liButtonSettings); if (alwayscountset == 'yes') { dropMenu.appendChild(liButtonAlwaysCount); } else { dropMenu.appendChild(liButtonNotAlwaysCount); } if (alwayssortset == 'yes') { dropMenu.appendChild(liButtonAlwaysSort); } else { dropMenu.appendChild(liButtonNotAlwaysSort); } } } function countRatio() { if (countable == 1) { //get elements with all stats var allstats = document.querySelectorAll('dl.stats'); for (var i = 0; i < allstats.length; i++) { var orderhits = 1000; var orderkudos = 1000; //get all label elements var statlabels = allstats[i].querySelectorAll('dt'); //search labels for hits and kudos for (var j = 0; j < statlabels.length; j++) { if (statlabels[j].innerHTML == 'Hits:') { orderhits = j; } else if (statlabels[j].innerHTML == 'Kudos:') { orderkudos = j; } } //if hits and kudos were found if (orderhits !== 1000 && orderkudos !== 1000) { //get all value elements var statvalues = allstats[i].querySelectorAll('dd'); //get kudos count var kudosvalue = statvalues[orderkudos].innerHTML; kudosvalue = kudosvalue.replace(/<.+?>/g,''); var kudoscount = parseFloat(kudosvalue); //get hits count var hitsvalue = statvalues[orderhits]; var hitscount = parseFloat(hitsvalue.innerHTML); //count percentage var percents = 100*kudoscount/hitscount; //get percentage with one decimal point var percentsprint = percents.toFixed(1); percentsprint = percentsprint.replace('.',','); //replace percentage and label on page hitsvalue.innerHTML = percentsprint + '%'; statlabels[orderhits].innerHTML = 'Kudos/Hits:'; if (colourbg == 1) { //colour background depending on percentage if (percents > lvl2) {hitsvalue.style.backgroundColor = ratio_green;} else if (percents < lvl1) {hitsvalue.style.backgroundColor = ratio_red;} else {hitsvalue.style.backgroundColor = ratio_yellow;} } //add attribute to the blurb for sorting var blurb = allstats[i].parentNode; blurb.setAttribute('kudospercent',percents); } else { //add attribute to the blurb for sorting var blurb = allstats[i].parentNode; blurb.setAttribute('kudospercent',0); } } } } function sortWorks() { if (sortable == 1) { var blurb1 = document.querySelector('dl.stats').parentNode; var worklist = blurb1.parentNode; var new_worklist = worklist.cloneNode(false); //add all blurbs to an array var blurbs = []; for (var i = 0; i < worklist.childNodes.length; i++) { if (worklist.childNodes[i].nodeName == 'LI') blurbs.push(worklist.childNodes[i]); } //sort the blurbs by kudos/hits ratio in descending order blurbs.sort(function(a, b){ return parseFloat(b.getAttribute('kudospercent')) - parseFloat(a.getAttribute('kudospercent')); }); //add them into the new worklist in order for (var i = 0; i < blurbs.length; i++) new_worklist.appendChild(blurbs[i]); worklist.parentNode.replaceChild(new_worklist, worklist); } }