SideTrackedStats

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

目前為 2019-07-27 提交的版本,檢視 最新版本

  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-2019, 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/(account|my|default|geocache|profile|seek/cache_details|p)/
  12. // @exclude /^https?://www\.geocaching\.com/(login|about|articles|myfriends)/
  13. // @version 0.1.1
  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;} a.sts-badge { background-color: white;} #ctl00_ContentBody_ProfilePanel1_pnlProfile div.sts-container {float: left}',
  25. currentPage,
  26. profileNameOld = document.getElementById("ctl00_ContentBody_ProfilePanel1_lblMemberName"),
  27. profileName = document.getElementById("ctl00_ProfileHead_ProfileHeader_lblMemberName"),
  28. userFieldOld = document.getElementsByClassName("li-user-info"),
  29. userField = document.getElementsByClassName("user-name"),
  30. userName = "",
  31. userNames = [],
  32. stats = [];
  33.  
  34. function displayStats(stats, page){
  35. function getHtml(uname, level, award, finds){
  36. return "<a class='sts-badge' href='https://www.sidetrackedseries.info' title='SideTracked stats.'><img src='https://img.sidetrackedseries.info/awards/st_F_award.php?name=" + uname + "&brand=jobs' /></a>";
  37. }
  38. var stsWidget = document.createElement("div"),
  39. html = "",
  40. i,
  41. target;
  42.  
  43. for(i = 0; i < stats.length; i++){
  44. var name = (stats[i].name + "")
  45. .replace(/;/g, ",")
  46. .replace(/'/g, "&apos;")
  47. .replace(/"/g, "&quot;");
  48. if(i === 0 || stats[i].name !== stats[0].name){
  49. html += getHtml(name);
  50. }
  51. }
  52.  
  53. switch(page){
  54. case "my":
  55. target = document.getElementById("ctl00_ContentBody_lnkProfile");
  56. break;
  57. case "account":
  58. target = document.getElementsByClassName('sidebar-right')[0];
  59. break;
  60. case "cache":
  61. target = document.getElementsByClassName('sidebar')[0];
  62. break;
  63. case "profile":
  64. if(profileName){
  65. target = document.getElementById("ctl00_ContentBody_ProfilePanel1_lblProfile");
  66. if (target) {
  67. target = target.parentNode;
  68. }
  69. }else if(profileNameOld){
  70. target = document.getElementById("HiddenProfileContent");
  71. }
  72. break;
  73. }
  74.  
  75. if(!target){
  76. console.warn("SideTracked Stats: Aborted - couldn't find where to insert widget. You might not be logged in.");
  77. return;
  78. }
  79.  
  80. if(html){
  81. stsWidget.className = "sts-container";
  82. stsWidget.innerHTML = html;
  83. switch(page){
  84. case "my":
  85. case "profile":
  86. target.parentNode.insertBefore(stsWidget, target.nextSibling);
  87. break;
  88. default:
  89. target.insertBefore(stsWidget, target.firstChild.nextSibling.nextSibling);
  90. break;
  91. }
  92. }else{
  93. console.warn("SideTracked Stats: didn't generate an award badge.");
  94. }
  95. }
  96. function getHiderName(){
  97. var i,
  98. links = document.getElementsByTagName("a"),
  99. pos;
  100. if(links){
  101. for(i = 0; i < links.length; i++){
  102. pos = links[i].href.indexOf("/seek/nearest.aspx?u=");
  103. if(pos !== -1){
  104. return decodeURIComponent(links[i].href.substr(pos + 21).replace(/\+/g, '%20'));
  105. }
  106. }
  107. }
  108. }
  109.  
  110. function parseNames(names){
  111. // Filter out null or undefined entries, convert commas to semicolons, then convert to a comma-separated string.
  112. return encodeURIComponent(names
  113. .filter(function (n){
  114. return n !== undefined;
  115. })
  116. .map(function (n){
  117. return (n + "").replace(/,/g, ";");
  118. })
  119. .join());
  120. }
  121.  
  122. // Don't run on frames or iframes
  123. if(window.top !== window.self){
  124. return false;
  125. }
  126.  
  127. if(/\/my\//.test(location.pathname)){
  128. // On a My Profile page
  129. currentPage = "my";
  130. }else if(/\/account\//.test(location.pathname)){
  131. // On a Profile page
  132. currentPage = "account";
  133. }else{
  134. if(cacheName){
  135. // On a Geocache page...
  136. if(!/SideTracked/i.test(cacheName.innerHTML) && !/side tracked/i.test(cacheName.innerHTML)){
  137. // ...but not a SideTracked cache
  138. return;
  139. }
  140. currentPage = "cache";
  141. }else{
  142. currentPage = "profile";
  143. }
  144. }
  145.  
  146. var hider;
  147. switch(currentPage){
  148. case "profile":
  149. if(profileName){
  150. userNames = [profileName.textContent.trim()];
  151. }else if(profileNameOld){
  152. userNames = [profileNameOld.textContent.trim()];
  153. }
  154. break;
  155. default:
  156. if(userField.length > 0){
  157. userNames.push(userField[0].innerHTML.trim());
  158. }
  159. hider = getHiderName();
  160. if(typeof hider !== 'undefined'){
  161. userNames.push(hider);
  162. }
  163. break;
  164. }
  165.  
  166. for(var i = 0; i < userNames.length; i++){
  167. stats[i] = {name: userNames[i]};
  168. }
  169.  
  170. userName = parseNames(userNames);
  171. if(!userName){
  172. console.error("SideTracked Stats: Aborted - couldn't work out user name");
  173. return;
  174. }
  175.  
  176. // Inject widget styling
  177. stsCSS.type = 'text/css';
  178. if(stsCSS.styleSheet){
  179. stsCSS.styleSheet.cssText = css;
  180. }else{
  181. stsCSS.appendChild(document.createTextNode(css));
  182. }
  183. document.head.appendChild(stsCSS);
  184. displayStats(stats, currentPage);
  185. }());