PSNprofiles.net enhancements

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

目前為 2016-10-29 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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.85
// @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; \
} \
#toggleEarned { \
background-color: #bada55; \
} \
#toggleEarnedOld { \
height: 25px; \
background: none;\
border: none;\
color: white;\
margin: 0; \
padding: 0;\
}");


/* 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() {
    $($(this).closest("div[class*='section-holder']")).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>toggle</span>earned</span>');
  $(document).on("click", "#toggleEarned", toggleEarned);
}

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').eq(2).find('.dropdown-menu');
  var buttonNameAsc = "Rank E-S";
  dropdown.append(
    $('<li><a href="">' + buttonNameAsc + '</a></li>').click(function(e) {
      sort(e, '+', buttonNameAsc); // + for ascending sort
    })
  );
  var buttonNameDesc = "Rank S-E";
  dropdown.append(
    $('<li><a href="">' + buttonNameDesc + '</a></li>').click(function(e) {
      sort(e, '-', 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() {
        $('#gamesTable').append($(this).closest('tr'));
      });
    }
  }
  if (order === '-') {
    for (r = trophyOrder.length; r >= 0; r--) {
      // TODO: sort ranks by percent before
      $('.' + trophyOrder[r]).each(function() {
        $('#gamesTable').append($(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</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 matchesUrl(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
matchesUrl("/guide/") && addToggleTypeButton();
matchesUrl("/guide/") && $('.earned > a').length > 0 && addToggleEarnedButton();
// add searchFix to games page
matchesUrl("/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
matchesUrl("/" + psnp.id) && addSortByRank();