On guide pages: adds a button to hide earend trophies, their description and links and uses a new style for earned trophies, On all pages: adds update button, On game pages: persist search string
// ==UserScript== // @name PSNprofiles.net enhancements // @author Barokai | www.loigistal.at // @icon http://psnprofiles.com/forums/favicon.ico // @namespace http://www.loigistal.at/userscripts/ // @license https://github.com/Barokai/psnprofiles-enhanced/blob/master/LICENSE // @homepageURL http://barokai.github.io/psnprofiles-enhanced/ // @supportURL https://github.com/Barokai/psnprofiles-enhanced/issues/new // @version 0.86 // @description On guide pages: adds a button to hide earend trophies, their description and links and uses a new style for earned trophies, On all pages: adds update button, On game pages: persist search string // @match http*://psnprofiles.com/* // @grant GM_addStyle // @require http://code.jquery.com/jquery-latest.js // @copyright 2016+, Barokai // ==/UserScript== // better visible green for earned trophies, used before: #57FF3B /*jshint multistr: true */ GM_addStyle("\ .tableofcontents li.earned { \ background: #bada55 !important; \ } \ .roadmap-trophies li.earned { \ background: #bada55 !important; \ } \ .roadmap-trophies .trophy.earned { \ background: #bada55 !important; \ } \ .section-holder.earned{ \ border: 3px solid #bada55; \ } \ #toggleEarned { \ background-color: #bada55; \ }\ .invisible.tags a.earned{\ text-shadow: 1px 1px 1px #bada55;\ }\ "); /* Guide enhancements ------------------------------------------------------- */ // TODO barokai: fix scrolling behavior when trophies are hidden and a trophy link is clicked in Guide Contens column (ID="TOCWrapper") function addToggleEarnedButton() { // add class earned to all links which match earned trophies in overview-info box $('.earned > a').each(function() { var trophyName = $(this).text().trim(); $('nobr > a:contains(' + trophyName + ')').addClass("earned"); }); // adds class "earned" to sections to hide them with the same toggle function $("img[class*='earned']").each(function() { // .closest('li').parent().closest('li') // TODO check if class of img isn't .unearned! $($(this).closest("div[class*='section-holder']").parent().closest("div[class*='section-holder']")).addClass("earned"); }); // workaround, above scripts adds earned to all secionts as img with class .unearned is matched too. $("img[class*='unearned']").each(function() { // .closest('li').parent().closest('li') $($(this).closest("div[class*='section-holder']").parent().closest("div[class*='section-holder']")).removeClass("earned"); }); // workaround to hide trophies in overview completely $(".trophy.earned").each(function(){ $($(this).closest(".col-xs-6")).addClass("earned"); $($(this).closest(".col-xs-12")).addClass("earned"); }); // adds button for toggling to overview info box $(".overview-info").append('<span class="tag" id="toggleEarned" title="click to toggle visiblity of earned trophies"><span class="typo-top">toggle</span><br/><span class="typo-bottom">earned</span>'); $(document).on("click", "#toggleEarned", toggleEarned); } // TODO: fix this, doesn't work in new version. function addToggleTypeButton() { // get trophy types (without spaces) - used as classes to toggle them later. var trophyTypes = $('table.invisible .tag').map(function(i, el) { var type = $(el); var typeName = type.text().replace(/\s+/g, ''); // add toggle visibility to type boxes type.click(function(e) { toggleClass(e, typeName); }); return typeName; }).get(); // get corresponding trophies - start with the ones in overview box $('table.invisible td small').each(function(index) { var typeClassName = trophyTypes[index]; var trophyHref = $("nobr a", $(this)); // add class to all found hrefs for this section trophyHref.addClass(typeClassName); trophyHref.each(function() { var trophyName = $(this).text(); // contents of roadmap $(".roadmap-trophies li:contains(" + trophyName + ")").addClass(typeClassName); // all the sections $("div[class*='element section-holder']:contains(" + trophyName + ")").addClass(typeClassName); // next the ones in the guide contents on the right $('#TOCList li:contains(' + trophyName + ')').addClass(typeClassName); // add class to trophies which are found in multible type sections $('table.invisible nobr a:contains(' + trophyName + ')').addClass(typeClassName); }); }); } function toggleEarned(e) { toggleClass(e, "earned"); } function toggleClass(e, className) { var element; // get correct element (togglebutton's layout would be destroyed otherwise) if (e.target.parentNode.id != "toggleEarned") { element = e.target; } else { element = e.target.parentNode; } if (element.innerHTML.indexOf(" *") >= 0) { element.innerHTML = element.innerHTML.slice(0, -2); } else { element.innerHTML += " *"; } $("." + className).toggle("slow", function(e) { /* Animation complete */ }); } /* Guide enhancements end --------------------------------------------------- */ /* Profile enhancements ----------------------------------------------------- */ // thanks to serverTimeout for sort by rank (his profile: http://psnprofiles.com/forums/user/80890-servertimeout/) // see his post here: http://psnprofiles.com/forums/topic/24324-sort-by-rank/?view=findpost&p=647509 function addSortByRank() { var dropdown = $('.dropdown-toggle.order'); var buttonNameAsc = "Rank E-S"; dropdown.next().append( $('<li><a href="">' + buttonNameAsc + '</a></li>').on('click', function(ev) { sort(ev, '+', buttonNameAsc); // + for ascending sort }) ); var buttonNameDesc = "Rank S-E"; dropdown.next().append( $('<li><a href="">' + buttonNameDesc + '</a></li>').on('click', function(ev) { sort(ev, '-', buttonNameDesc); // + for descending sort }) ); } function sort(e, order, buttonName) { e.preventDefault(); var trophyOrder = ['F', 'E', 'D', 'C', 'B', 'A', 'S']; var r; if (order === '+') { for (r = 0; r <= trophyOrder.length; r++) { // TODO: sort ranks by percent before $('.' + trophyOrder[r]).each(function() { $('.'+trophyOrder[r]).each(function() { $('#content table.zebra').eq(0).append(jQuery(this).closest('tr')); }); }); } } if (order === '-') { for (r = trophyOrder.length; r >= 0; r--) { // TODO: sort ranks by percent before $('.' + trophyOrder[r]).each(function() { $('.'+trophyOrder[r]).each(function() { $('#content table.zebra').eq(0).append(jQuery(this).closest('tr')); }); }); } } // set dropdown button name when new order was set $('.dropdown-toggle.order').text("Order (" + buttonName + ")"); } /* Profile enhancements end ------------------------------------------------- */ /* Global enhancements ------------------------------------------------------ */ function addUpdateButton() { $('.navigation > ul').append("<li><a href='/?update'>Update Profile</a></li>"); // TODO barokai: check if successfully updated and redirect to the last visited page (where update was clicked) } /* Global enhancements end ---------------------------------------------------*/ /* Games page enhancements -------------------------------------------------- */ // thanks to dernop for this searchFix (his profile: http://psnprofiles.com/forums/user/45256-dernop/) // see his post here: http://psnprofiles.com/forums/topic/32107-bugsoddities-in-the-games-search-feature/#entry777278 function gameSearchFix() { $('#searchGames').off('keyup'); $('#searchGames').keyup(function() { window.clearTimeout('searchInt'); var input = $(this); if (input.val().length > 1) { $('#loading').show(); $('#closeButton').hide(); var searchInt = window.setTimeout( function() { $('#pagination').hide(); var q = encodeURIComponent(input.val()); $.ajax({ url: "/php/liveSearch.php?t=g&q=" + q, success: function(html) { window.location.hash = '#!' + q; $('#game_list').html(html); $('#loading').hide(); $('#closeButton').show(); } }); }, 500); } else { $('#loading').hide(); } }); var query = decodeURIComponent(window.location.hash.replace('#!', '')); if (query.length > 0) { $('#searchGames').val(query).keyup(); } } // TODO barokai: integrate other func in psnp var psnp = { id: $('div.user-menu a.dropdown-toggle span').text(), _gamesTable: $('table#gamesTable'), // game table on user profile _gameList: $('table#game_list'), _profileBar: $('div.profile-bar') }; // add percentage on mouseover or integrate into game row // add mouse over information like percentage (last row), last played if available etc. // thanks to dernop (again) - http://psnprofiles.com/forums/topic/35583-add-possibility-to-hide-earned-trophies-in-guides-with-userscript/#entry932561 $(function() { // initialize psnp page/DOM information // psnp properties $.extend(psnp, { isProfile: psnp._gamesTable[0] !== undefined && psnp._profileBar[0] !== undefined, isOwnProfile: $(psnp._profileBar).find('div.info').text().indexOf(psnp.id) > -1, isGameList: psnp._gameList.length == 1, myGames: JSON.parse(localStorage.getItem('_mygames')) || {} }); psnp.updateMyGames = function(games) { var count = 0; $.each(games, function(i, e) { psnp.myGames[e.id] = e; count++; }); localStorage.setItem('_mygames', JSON.stringify(psnp.myGames)); console.log(count + " games added/updated to localstorage."); }; // PROFILE / GAME LIST psnp.gameList = (function() { if (!psnp.isProfile) return undefined; var _games = []; // register mutationobserver for gameList to handle 'load-on-scroll' var obs = new MutationObserver(function(mutations) { parseGames(); // just re-parse all games if list has changed. }); obs.observe(psnp._gamesTable[0], { childList: true, subtree: true }); // parse PSNP games table (id, name, completion, # of trophies) function parseGames() { _games = []; psnp._gamesTable.find('tr:has(a.bold)').each(function(i, row) { var title = $(row).find('a.bold')[0]; var game = { id: title.href.match(/\/trophies\/([^\/]+)/)[1], name: title.innerText, progress: $(row).find('div.progress_outer span').text(), completed: $(row).hasClass('completed'), platinum: $(row).hasClass('platinum'), gold: $(row).find('li.gold').text(), silver: $(row).find('li.silver').text(), bronze: $(row).find('li.bronze').text(), }; if (!psnp.isOwnProfile && psnp.myGames[game.id]) { var img = $(row).find('img.trophy_image'); img.removeClass('no-border').addClass('earned'); // mark owned games } _games.push(game); }); // if this is our own profile, save the games list. if (psnp.isOwnProfile) { psnp.updateMyGames(_games); } } // parse game list initially parseGames(); return { games: _games }; })(); // #GAMELIST# global list of games (psnprofiles.com/games) // Mark owned game in "Games" list if (psnp.isGameList) { psnp._gameList.find('tr:has(a.bold)').each(function(i, row) { var title = $(row).find('a.bold')[0]; var id = title.href.match(/\/trophies\/([^\/"]+)/)[1]; var img = $(row).find('img.trophy_image'); // mark owned games if (psnp.myGames[id]) { if (psnp.myGames[id].platinum) $(row).addClass('platinum'); // add platinum row style if (psnp.myGames[id].completed) $(row).addClass('completed'); // add completed row style img.removeClass('no-border').addClass('earned'); if (psnp.myGames[id].progress != '100%') img.css('border-color', 'yellow'); // // add completion percentage var avgProgress = $(row).children('td:eq(4)').find('span.typo-top'); console.log(avgProgress); avgProgress.text(psnp.myGames[id].progress + " / " + avgProgress.text()); } }); } }); /* Games page enhancements end -----------------------------------------------*/ // helperfunction to determine if the url matches a certain segment function match###rl(urlSegment) { return document.location.pathname.indexOf(urlSegment) === 0; } /* -------------------------------------------------------------------------- */ /* Apply enhancements to correct pages -------------------------------------- */ /* -------------------------------------------------------------------------- */ // add toggle button functionality to all guides (if any earned trophies were found //match###rl("/guide/") && addToggleTypeButton(); //TODO: re-enable after fix match###rl("/guide/") && $('.earned > a').length > 0 && addToggleEarnedButton(); // add searchFix to games page match###rl("/games") && gameSearchFix(); // add update button to navigation on all psnprofile pages (if logged in) psnp.id && addUpdateButton(); // add only on profile pages and others where a sort dropdown is match###rl("/" + psnp.id) && addSortByRank(); // http://stackoverflow.com/a/27363569 (function() { var origOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function() { // console.log('request started!'); this.addEventListener('load', function() { if (~this.responseURL.indexOf("status?user=")){ // console.log('request completed!'); //console.log(this.readyState); //will always be 4 (ajax is completed successfully) //console.log(this.responseText); //whatever the response was var obj = jQuery.parseJSON(this.responseText); var requestName = this.responseURL.substr(this.responseURL.lastIndexOf('/') + 1).replace(psnp.id, ""); var status = obj.status.replace(psnp.id, ""); if(requestName == "status?user=" && status === " has been updated"){ window.location.href = "https://psnprofiles.com/" + psnp.id; } } }); origOpen.apply(this, arguments); }; })();