SideTrackedStats

Adds your SideTracked stats badge onto your profile page and SideTracked cache pages on geocaching.com.

目前为 2015-05-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name SideTrackedStats
  3. // @namespace http://www.cryotest.com/
  4. // @description Adds your SideTracked stats badge onto your profile page and SideTracked cache pages on geocaching.com.
  5. // @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
  6. // @copyright 2015, Cryo99
  7. // @attribution SideTracked stats provided by Chris AKA Bus.Stop (http://www.sidetrackedseries.info/)
  8. // @attribution Icon image extracted from the SideTracked banner by Chris AKA Bus.Stop
  9. // @icon https://raw.githubusercontent.com/Cryo99/SideTrackedStats/master/icon48.png
  10. // @icon64 https://raw.githubusercontent.com/Cryo99/SideTrackedStats/master/icon64.png
  11. // @include /^https?://www\.geocaching\.com/(my|default|geocache|profile|seek/cache_details)/
  12. // @exclude /^https?://www\.geocaching\.com/(login|about|articles|myfriends)/
  13. // @version 0.0.2
  14. // @supportURL https://github.com/Cryo99/SideTrackedStats
  15. // @grant GM_xmlhttpRequest
  16. // ==/UserScript==
  17.  
  18.  
  19. (function (){
  20. "use strict";
  21. var cacheName = document.getElementById("ctl00_ContentBody_CacheName"),
  22. stsCSS = document.createElement("style"),
  23. // ST images can be wider when level names are long. overflow: hidden; on sts-container prevents images from overlaying the div border.
  24. css = 'div.sts-container { border: 1px solid #b0b0b0; margin-top: 1.5em; padding: 0; text-align: center; overflow: hidden;} .WidgetBody div.sts-container { border: none; } #ctl00_ContentBody_ProfilePanel1_pnlProfile div.sts-container { border: none; text-align: inherit;}',
  25. currentPage,
  26. profileName = document.getElementById("ctl00_ContentBody_ProfilePanel1_lblMemberName"),
  27. userField = document.getElementsByClassName("li-user-info"),
  28. userName = "",
  29. userNames = [],
  30. stats = [];
  31.  
  32. function displayStats(stats, page){
  33. function getHtml(uname, level, award, finds){
  34. return "<a class='sts-badge' href='http://www.sidetrackedseries.info' title='SideTracked stats.'><img src='http://img.sidetrackedseries.info/awards/st_F_award.php?name=" + uname + "&brand=jobs' /></a>";
  35. }
  36. var stsWidget = document.createElement("div"),
  37. html = "",
  38. i,
  39. images,
  40. loop,
  41. target,
  42. target2;
  43.  
  44. for(i = 0; i < stats.length; i++){
  45. name = (stats[i].name + "")
  46. .replace(/;/g, ",")
  47. .replace(/'/g, "&apos;")
  48. .replace(/"/g, "&quot;");
  49. if(i === 0 || stats[i].name !== stats[0].name){
  50. html += getHtml(name);
  51. }
  52. }
  53.  
  54. switch(page){
  55. case "my":
  56. target = document.getElementById("ctl00_ContentBody_lnkProfile");
  57. break;
  58. case "cache":
  59. target = document.getElementById("map_preview_canvas");
  60. break;
  61. case "profile":
  62. // Abort if award badge already on profile page
  63. images = document.getElementsByTagName("IMG");
  64. for(loop = 0; loop < images.length; loop++){
  65. if(/img.sidetrackedseries.info\/awards\/st_F_award.php/.test(images[loop].src)){
  66. console.info("SideTracked badge not inserted: already on profile of " + userName);
  67. return;
  68. }
  69. }
  70. target = document.getElementById("ctl00_ContentBody_ProfilePanel1_lblProfile");
  71. if(target){
  72. target = target.parentNode;
  73. }
  74. break;
  75. }
  76.  
  77. if(!target && !target2){
  78. console.warn("SideTracked Stats: Aborted - couldn't find where to insert widget. You might not be logged in.");
  79. return;
  80. }
  81.  
  82. if(html){
  83. stsWidget.className = "sts-container";
  84. stsWidget.innerHTML = html;
  85. target.parentNode.insertBefore(stsWidget, target.nextSibling);
  86. }else{
  87. console.warn("SideTracked Stats: didn't generate an award badge.");
  88. }
  89. }
  90. function getHiderName(){
  91. var i,
  92. links = document.getElementsByTagName("a"),
  93. pos;
  94. if(links){
  95. for(i = 0; i < links.length; i++){
  96. pos = links[i].href.indexOf("/seek/nearest.aspx?u=");
  97. if(pos !== -1){
  98. return decodeURIComponent(links[i].href.substr(pos + 21).replace(/\+/g, '%20'));
  99. }
  100. }
  101. }
  102. }
  103.  
  104. function parseNames(names){
  105. // Filter out null or undefined entries, convert commas to semicolons, then convert to a comma-separated string.
  106. return encodeURIComponent(names
  107. .filter(function (n){
  108. return n !== undefined;
  109. })
  110. .map(function (n){
  111. return (n + "").replace(/,/g, ";");
  112. })
  113. .join());
  114. }
  115.  
  116. // Don't run on frames or iframes
  117. if(window.top !== window.self){
  118. return false;
  119. }
  120.  
  121. if(/\/my\//.test(location.pathname)){
  122. // On a My Profile page
  123. currentPage = "my";
  124. }else{
  125. if(cacheName){
  126. // On a Geocache page...
  127. if(!/SideTracked/i.test(cacheName.innerHTML) && !/side tracked/i.test(cacheName.innerHTML)){
  128. // ...but not a SideTracked cache
  129. return;
  130. }
  131. currentPage = "cache";
  132. }else{
  133. currentPage = "profile";
  134. }
  135. }
  136.  
  137. switch(currentPage){
  138. case "profile":
  139. if(profileName){
  140. userNames = [profileName.textContent.trim()];
  141. }
  142. console.log(profileName);
  143. break;
  144. default:
  145. if(userField.length > 0 && userField[0].children && userField[0].children.length > 0){
  146. userNames.push(userField[0].children[0].innerHTML.trim());
  147. }
  148. var hider = getHiderName();
  149. if(typeof hider !== 'undefined'){
  150. userNames.push(hider);
  151. }
  152. break;
  153. }
  154.  
  155. for(var i = 0; i < userNames.length; i++){
  156. stats[i] = {name: userNames[i]}
  157. }
  158.  
  159. userName = parseNames(userNames);
  160. if(!userName){
  161. console.error("SideTracked Stats: Aborted - couldn't work out user name");
  162. return;
  163. }
  164.  
  165. // Inject widget styling
  166. stsCSS.type = 'text/css';
  167. if(stsCSS.styleSheet){
  168. stsCSS.styleSheet.cssText = css;
  169. }else{
  170. stsCSS.appendChild(document.createTextNode(css));
  171. }
  172. document.documentElement.firstChild.appendChild(stsCSS);
  173. displayStats(stats.reverse(), currentPage);
  174. }());