Greasy Fork is available in English.

Geocaching.com + Project-GC

Adds links and data to Geocaching.com to make it collaborate with PGC

Verze ze dne 06. 05. 2015. Zobrazit nejnovější verzi.

  1. /* global $: true */
  2. /* global waitForKeyElements: true */
  3. /* global GM_xmlhttpRequest: true */
  4. /* global GM_getValue: true */
  5.  
  6. // ==UserScript==
  7. // @name Geocaching.com + Project-GC
  8. // @namespace PGC
  9. // @description Adds links and data to Geocaching.com to make it collaborate with PGC
  10. // @include http://www.geocaching.com/*
  11. // @include https://www.geocaching.com/*
  12. // @version 1.1.1
  13. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js
  14. // @require https://greatest.deepsurf.us/scripts/5392-waitforkeyelements/code/WaitForKeyElements.js?version=19641
  15. // @grant GM_xmlhttpRequest
  16. // @grant GM_setValue
  17. // @grant GM_getValue
  18. // ==/UserScript==
  19.  
  20. 'use strict';
  21.  
  22. (function() {
  23.  
  24. var pgcUrl = 'http://project-gc.com/',
  25. pgcApiUrl = pgcUrl + 'api/gm/v1/',
  26. externalLinkIcon = 'http://maxcdn.project-gc.com/images/external_small.png',
  27. loggedIn = GM_getValue('loggedIn'),
  28. subscription = GM_getValue('subscription'),
  29. pgcUsername = GM_getValue('pgcUsername'),
  30. gccomUsername = GM_getValue('gccomUsername'),
  31. latestLogs = [],
  32. path = window.location.pathname;
  33.  
  34. // Don't run the script for iframes
  35. if (window.top == window.self) {
  36. Main();
  37. }
  38.  
  39. /**
  40. * Router
  41. */
  42. function Main() {
  43.  
  44. CheckPGCLogin();
  45.  
  46. if (path.match(/^\/geocache\/.*/) !== null) {
  47. CachePage();
  48. } else if (path.match(/^\/seek\/cache_logbook\.aspx.*/) !== null) {
  49. Logbook();
  50. }
  51.  
  52. }
  53.  
  54. /**
  55. * Check that we are logged in at PGC, and that it's with the same username
  56. */
  57. function CheckPGCLogin() {
  58.  
  59. gccomUsername = $('#ctl00_divSignedIn .li-user-info span').html();
  60. GM_setValue('gccomUsername', gccomUsername);
  61.  
  62. GM_xmlhttpRequest({
  63. method: "GET",
  64. url: pgcApiUrl + 'GetMyUsername',
  65. onload: function(response) {
  66. var result = JSON.parse(response.responseText),
  67. html, loggedInContent, subscriptionContent = '';
  68. if (result.status !== 'OK') {
  69. alert(response.responseText);
  70. return false;
  71. }
  72.  
  73. pgcUsername = result.data.username;
  74. loggedIn = !!result.data.loggedIn;
  75. subscription = !!result.data.subscription;
  76.  
  77. if (loggedIn === false) {
  78. loggedInContent = 'Not logged in';
  79. } else if (pgcUsername == gccomUsername) {
  80. loggedInContent = '<strong>' + pgcUsername + '</strong>';
  81. } else {
  82. loggedInContent = '<strong><font color="red">' + pgcUsername + '</font></strong>';
  83. }
  84.  
  85. if (subscription) {
  86. subscriptionContent = 'Premium';
  87. }
  88.  
  89. html = '<a class="SignedInProfileLink" href="' + pgcUrl + '" title="Project-GC">\
  90. <span class="avatar">\
  91. <img src="http://project-gc.com/favicon.ico" alt="Logo" width="30" height="30" style="border-radius:100%border-width:0px;">\
  92. </span>\
  93. <span class="li-user-info">\
  94. <span>' + loggedInContent + '</span>\
  95. <span class="cache-count">' + subscriptionContent + '</span>\
  96. </span>\
  97. </a>';
  98.  
  99. if ($('#ctl00_divSignedIn ul')) {
  100. $('#ctl00_divSignedIn ul').prepend('<li class="li-user">' + html + '</li>');
  101. } else {
  102. $('#ctl00_divNotSignedIn').append('<div>' + html + '</div>'); // FIXME - Not working
  103. }
  104.  
  105. // Save the login value
  106. GM_setValue('loggedIn', loggedIn);
  107. GM_setValue('subscription', subscription);
  108. GM_setValue('pgcUsername', pgcUsername);
  109. },
  110. onerror: function(response) {
  111. alert(response);
  112. return false;
  113. }
  114. });
  115. }
  116.  
  117. /**
  118. * getGcCodeFromPage
  119. * @return string
  120. */
  121. function getGcCodeFromPage() {
  122. return $('#ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoCode').html();
  123. }
  124.  
  125. /**
  126. * addToVGPS
  127. */
  128. function addToVGPS() {
  129. var gccode = GM_getValue('gccode'),
  130. listId = $('#comboVGPS').val(),
  131. msg,
  132. url = pgcApiUrl + 'AddToVGPSList?listId=' + listId + '&gccode=' + gccode + '&sectionName=GM-script';
  133. GM_xmlhttpRequest({
  134. method: "GET",
  135. url: url,
  136. onload: function(response) {
  137. var result = JSON.parse(response.responseText);
  138. msg = 'Geocache not added to Virtual-GPS :(';
  139. if (result.status === 'OK') {
  140. msg = 'Geocache added to Virtual-GPS!';
  141. }
  142. alert(msg);
  143. return true;
  144. },
  145. onerror: function(response) {
  146. console.log(response);
  147. return false;
  148. }
  149. });
  150. }
  151.  
  152. /**
  153. * CachePage
  154. */
  155. function CachePage() {
  156. var gccode = getGcCodeFromPage(),
  157. cacheOwnerDiv = $('#ctl00_ContentBody_mcd1'),
  158. placedBy = $('#ctl00_ContentBody_mcd1 a').html()
  159. ;
  160.  
  161. GM_setValue('gccode', gccode);
  162.  
  163. // Append links to Profile Stats for every geocacher who has logged the cache as well
  164. cacheOwnerDiv.append('<a href="' + pgcUrl + 'ProfileStats/' + encodeURIComponent(placedBy) + '"><img src="' + externalLinkIcon + '" title="PGC Profile Stats"></a>');
  165.  
  166. // Though this is ajax, so we need some magic
  167. waitForKeyElements('#cache_logs_table tr', CachePage_Logbook);
  168.  
  169. // Get cache data from PGC
  170. if (GM_getValue('subscription')) {
  171. GM_xmlhttpRequest({
  172. method: "GET",
  173. url: pgcApiUrl + 'GetCacheDataFromGccode?gccode=' + encodeURIComponent(gccode),
  174. onload: function(response) {
  175. var result = JSON.parse(response.responseText),
  176. cacheData = result.data.cacheData,
  177. challengeCheckerTagIds = result.data.challengeCheckerTagIds,
  178. location = [],
  179. fp = 0,
  180. fpp = 0,
  181. fpw = 0;
  182.  
  183. // Add FP/FP%/FPW below the current FP
  184. if (result.status === 'OK' && cacheData !== false) {
  185. fp = parseInt(+cacheData.favorite_points, 10),
  186. fpp = parseInt(+cacheData.favorite_points_pct, 10),
  187. fpw = parseInt(+cacheData.favorite_points_wilson, 10);
  188.  
  189. // Add PGC location
  190. if (cacheData.country.length > 0) {
  191. location.push(cacheData.country);
  192. }
  193. if (cacheData.region.length > 0) {
  194. location.push(cacheData.region);
  195. }
  196. if (cacheData.county.length > 0) {
  197. location.push(cacheData.county);
  198. }
  199. location = location.join(' / ');
  200. $('#ctl00_ContentBody_Location').html('<span>' + location + '</span>');
  201. }
  202.  
  203. $('#ctl00_divContentMain div.span-17 div.span-6.right.last div.favorite.right').append('<p>(' + fp + ' FP, ' + fpp + '%, ' + fpw + 'W)</p>');
  204.  
  205. // Add challenge checkers
  206. if(challengeCheckerTagIds.length > 0) {
  207. var html = '';
  208.  
  209. html += '<div id="PGC_ChallengeCheckers">';
  210. for(var i = 0 ; i < challengeCheckerTagIds.length ; i++) {
  211. html += '<a href="http://project-gc.com/Challenges//' + challengeCheckerTagIds[i] + '"><img src="http://maxcdn.project-gc.com/Images/Checker/' + challengeCheckerTagIds[i] + '" title="Project-GC Challenge checker" alt="PGC Checker"></a>';
  212. }
  213. html += '</div>';
  214. $('#ctl00_ContentBody_CacheInformationTable').append(html)
  215. }
  216.  
  217. }
  218. });
  219. }
  220.  
  221.  
  222. // Make it easier to copy the gccode
  223. $('#ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoLinkPanel').
  224. html('<div style="margin-right: 15px; margin-bottom: 10px;"><p style="font-size: 125%; margin-bottom: 0">' + gccode + '</p>' +
  225. '<input size="25" type="text" value="http://coord.info/' + encodeURIComponent(gccode) + '" onclick="this.setSelectionRange(0, this.value.length);"></div>');
  226.  
  227.  
  228. // Remove the UTM coordinates
  229. // $('#ctl00_ContentBody_CacheInformationTable div.LocationData div.span-9 p.NoBottomSpacing br').remove();
  230. $('#ctl00_ContentBody_LocationSubPanel').html();
  231.  
  232. // Remove ads
  233. // PGC can't really do this officially
  234. // $('#ctl00_ContentBody_uxBanManWidget').remove();
  235.  
  236. // Remove disclaimer
  237. // PGC can't really do this officially
  238. // $('#ctl00_divContentMain div.span-17 div.Note.Disclaimer').remove();
  239.  
  240. // Remove the useless "Geocache Description"
  241. $('h3.CacheDescriptionHeader').remove();
  242.  
  243. // Hide download links
  244. $('<p style="cursor: pointer;" onclick="$(\'#ctl00_divContentMain div.DownloadLinks\').toggle();"><span class="arrow">▼</span>Print and Downloads</p>').insertAfter('#ctl00_ContentBody_CacheInformationTable div.LocationData');
  245. $('#ctl00_divContentMain div.DownloadLinks').hide();
  246.  
  247.  
  248. // Turn the coordinates into an address
  249. var coordinates = $('#ctl00_ContentBody_lnkConversions').attr('href'),
  250. latitude = coordinates.replace(/.*lat=([^&]*)&lon=.*/, "$1"),
  251. longitude = coordinates.replace(/.*&lon=([^&]*)&.*/, "$1"),
  252. url = 'http://maps.googleapis.com/maps/api/geocode/json?latlng=' + latitude + ',' + longitude + '&sensor=false';
  253. GM_xmlhttpRequest({
  254. method: "GET",
  255. url: url,
  256. onload: function(response) {
  257. var result = JSON.parse(response.responseText);
  258. if (result.status !== 'OK') {
  259. return false;
  260. }
  261. var formattedAddress = result.results[0].formatted_address;
  262. $('#ctl00_ContentBody_LocationSubPanel').html(formattedAddress + '<br />');
  263. }
  264. });
  265.  
  266.  
  267. // Add number of finds to the top
  268. // $('#ctl00_ContentBody_lblFindCounts').find('img').each(function() {
  269. // if($(this).attr('src') == '/images/logtypes/2.png') { // Found
  270. // }
  271. // });
  272. $('#cacheDetails').append('<div>' + $('#ctl00_ContentBody_lblFindCounts').html() + '</div>');
  273.  
  274.  
  275. // Add link to PGC gallery
  276. if (subscription) {
  277. var html = '<a href="' + pgcUrl + 'Tools/Gallery?gccode=' + gccode + '&submit=Filter"><img src="' + externalLinkIcon + '" title="Project-GC"></a> ';
  278. $('.CacheDetailNavigation ul li:first').append(html);
  279. }
  280.  
  281.  
  282.  
  283. var gccomUsername = GM_getValue('gccomUsername'),
  284. mapUrl = pgcUrl + 'Maps/mapcompare/?profile_name=' + gccomUsername +
  285. '&nonefound=on&ownfound=on&location=' + latitude + ',' + longitude +
  286. '&max_distance=5&submit=Filter';
  287.  
  288. $('#ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoLinkPanel').append(
  289. ' <a target="_blank" href="' + mapUrl + '">Project-GC Map</a>');
  290.  
  291. $('#ctl00_ContentBody_CoordInfoLinkControl1_uxCoordInfoLinkPanel').append(
  292. '<a target="_blank" href="' + mapUrl + '&onefound=on">(incl found)</a>');
  293.  
  294. GM_xmlhttpRequest({
  295. method: "GET",
  296. url: pgcApiUrl + 'GetExistingVGPSLists',
  297. onload: function(response) {
  298. var result = JSON.parse(response.responseText),
  299. vgpsLists = result.data.lists,
  300. selected = result.data.selected,
  301. selectedContent,
  302. html = '<li><img width="16" height="16" src="http://maxcdn.project-gc.com/images/mobile_telephone_32.png"> Add to V-GPS <br />',
  303. listId, list;
  304.  
  305. html += '<select id="comboVGPS">';
  306. for (listId in vgpsLists) {
  307. selectedContent = '';
  308. if (+selected === +listId) {
  309. selectedContent = ' selected="selected"';
  310. }
  311. html += '<option value="' + listId + '"' + selectedContent + '>' + vgpsLists[listId].name + '</option>';
  312. }
  313. html += '</select>';
  314. html += '&nbsp;<button id="btnaddToVGPS">+</button>';
  315. html += '</li>';
  316.  
  317. $('div.CacheDetailNavigation ul:first').append(html);
  318.  
  319. $('#btnaddToVGPS').click(function(event) {
  320. event.preventDefault();
  321. addToVGPS();
  322. });
  323. }
  324. });
  325. }
  326.  
  327. function CachePage_Logbook(jNode) {
  328.  
  329. // Add Profile stats link after each user
  330. var profileNameElm = $(jNode).find('p.logOwnerProfileName strong a');
  331. var profileName = profileNameElm.html();
  332.  
  333. if (typeof profileName !== 'undefined') {
  334. profileName = profileNameElm.append('<a href="' + pgcUrl + 'ProfileStats/' + encodeURIComponent(profileName) + '"><img src="' + externalLinkIcon + '" title="PGC Profile Stats"></a>');
  335. }
  336.  
  337. // Save to latest logs
  338. if (latestLogs.length < 5) {
  339. var logType = $(jNode).find('div.LogType strong img').attr('src');
  340. if (logType == '/images/logtypes/3.png') { // dnf
  341. latestLogs.push('<img src="' + logType + '">');
  342. } else if (logType == '/images/logtypes/2.png') { // found
  343. latestLogs.push('<img src="' + logType + '">');
  344. }
  345.  
  346. // Show them
  347. if (latestLogs.length == 5) {
  348. var images = latestLogs.join('');
  349. // $('#ctl00_ContentBody_diffTerr').append('<dl><dt> Latest logs:</dt><dd><span>' + images + '</span></dd></dl>');
  350. $('#ctl00_ContentBody_size p').addClass('NoBottomSpacing');
  351. $('#ctl00_ContentBody_size').append('<p class="AlignCenter NoBottomSpacing">Latest logs: <span>' + images + '</span></p>');
  352.  
  353. }
  354. }
  355. }
  356.  
  357.  
  358. function Logbook() {
  359. waitForKeyElements('#AllLogs tr', CachePage_Logbook);
  360. }
  361.  
  362. // Not used?
  363. // function Logbook_Logbook(jNode) {
  364. // CachePage_Logbook(jNode);
  365. // }
  366.  
  367. }());