NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Geocaching TB auto-visit // @namespace https://openuserjs.org/scripts/dfxdfx.at/Geocaching_TB_auto-visit // @version 3.4 // @description Adds TB auto-visit functionality to geocaching.com // @author dfx // @match http*://*.geocaching.com/seek/log.asp* // @match http*://*.geocaching.com/play/geocache/*/log* // @grant none // @require http://code.jquery.com/jquery-3.2.1.min.js // @license MIT // ==/UserScript== /* jshint -W097 */ 'use strict'; var maxLogLen = 4000; var jq = jQuery.noConflict(true); /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts, that detects and handles AJAXed content. Usage example: waitForKeyElements ( "div.comments" , commentCallbackFunction ); //--- Page-specific function to do what we want when the node is found. function commentCallbackFunction (jNode) { jNode.text ("This comment changed by waitForKeyElements()."); } IMPORTANT: This function requires your script to have loaded jQuery. */ function waitForKeyElements( selectorTxt, /* Required: The jQuery selector string that specifies the desired element(s). */ actionFunction, /* Required: The code to run when elements are found. It is passed a jNode to the matched element. */ bWaitOnce, /* Optional: If false, will continue to scan for new elements even after the first match is found. */ iframeSelector /* Optional: If set, identifies the iframe to search. */ ) { var targetNodes, btargetsFound; if (typeof iframeSelector == "undefined") targetNodes = jq(selectorTxt); else targetNodes = jq(iframeSelector).contents() .find(selectorTxt); if (targetNodes && targetNodes.length > 0) { btargetsFound = true; /*--- Found target node(s). Go through each and act if they are new. */ targetNodes.each(function () { var jThis = jq(this); var alreadyFound = jThis.data('alreadyFound') || false; if (!alreadyFound) { //--- Call the payload function. var cancelFound = actionFunction(jThis); if (cancelFound) btargetsFound = false; else jThis.data('alreadyFound', true); } }); } else { btargetsFound = false; } //--- Get the timer-control variable for this selector. var controlObj = waitForKeyElements.controlObj || {}; var controlKey = selectorTxt.replace(/[^\w]/g, "_"); var timeControl = controlObj[controlKey]; //--- Now set or clear the timer as appropriate. if (btargetsFound && bWaitOnce && timeControl) { //--- The only condition where we need to clear the timer. clearInterval(timeControl); delete controlObj[controlKey]; } else { //--- Set a timer, if needed. if (!timeControl) { timeControl = setInterval(function () { waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector ); }, 300 ); controlObj[controlKey] = timeControl; } } waitForKeyElements.controlObj = controlObj; } if (typeof GM_deleteValue == 'undefined') { var GM_addStyle = function (css) { var style = document.createElement('style'); style.textContent = css; document.getElementsByTagName('head')[0].appendChild(style); }; var GM_deleteValue = function (name) { localStorage.removeItem(name); }; var GM_getValue = function (name, defaultValue) { var value = localStorage.getItem(name); if (!value) return defaultValue; var type = value[0]; value = value.substring(1); switch (type) { case 'b': return value == 'true'; case 'n': return Number(value); default: return value; } }; var GM_log = function (message) { console.log(message); }; var GM_openInTab = function (url) { return window.open(url, "_blank"); }; var GM_registerMenuCommand = function (name, funk) { //todo }; var GM_setValue = function (name, value) { value = (typeof value)[0] + value; localStorage.setItem(name, value); }; } var SignedInAs = serverParameters["user:info"].username; SignedInAs = SignedInAs.replace(/<\&>/g, '&'); GM_log("signed in as " + SignedInAs); var bShowInventory = false; // default // Get handle to page's form. var e_LogTextArea = document.getElementById("ctl00_ContentBody_LogBookPanel1_uxLogInfo"); if (!e_LogTextArea) { // new log page e_LogTextArea = jq("#LogText")[0]; if (!e_LogTextArea) return; } var e_LogBookPanel1_LogButton = document.getElementById("ctl00_ContentBody_LogBookPanel1_btnSubmitLog"); if (e_LogBookPanel1_LogButton) { // old log page // Move submit button to the right. e_LogBookPanel1_LogButton.parentNode.style.textAlign = 'right'; // Create duplicate Submit button. var LogButtonTop = e_LogBookPanel1_LogButton.cloneNode(false); //var tmpDD = document.getElementById("ctl00_ContentBody_LogBookPanel1_uxDateFormatHint").parentNode.parentNode; var tmpDD = document.getElementById("uxDateVisited").parentNode; tmpDD.appendChild(LogButtonTop); } else { //e_LogBookPanel1_LogButton = jq('.btn-submit')[0]; } // Add column to trackable table, if present. var arTrackers = []; // Needs to be a global variable, so it can be used in functions. var e_tblTravelBugs = document.getElementById("tblTravelBugs"); var cp = 1; if (e_tblTravelBugs) { var e_headTravelBugs = e_tblTravelBugs.childNodes[1].childNodes[1]; var avHead = document.createElement('th'); avHead.style.width = '100px'; avHead.appendChild(document.createTextNode('Auto-Visit')); insertAfter(avHead, e_headTravelBugs.cells[cp]); var e_bodyTravelBugs = e_tblTravelBugs.childNodes[3]; for (var r = 0; r < e_bodyTravelBugs.rows.length; r++) { if (r == e_bodyTravelBugs.rows.length - 1) { e_bodyTravelBugs.rows[r].cells[0].setAttribute('colspan', 4); } else { var avTracker = e_bodyTravelBugs.rows[r].cells[0].firstChild.firstChild.data; var avDrpDwn = e_bodyTravelBugs.rows[r].cells[2].childNodes[1].id; arTrackers.push(avTracker); var avCol = document.createElement('td'); insertAfter(avCol, e_bodyTravelBugs.rows[r].cells[cp]); var avChkBox = document.createElement('input'); avChkBox.type = 'Checkbox'; avChkBox.id = 'chkbox_' + avTracker; avChkBox.setAttribute('tracker', avTracker); avChkBox.setAttribute('row', r); avChkBox.setAttribute('drpdwnctl', avDrpDwn); avChkBox.addEventListener("click", fAutoVisitChanged, true); var avCbLbl = document.createElement('label'); avCbLbl.setAttribute('for', 'chkbox_' + avTracker); avCbLbl.appendChild(document.createTextNode('Auto-Visit')); avCol.appendChild(avChkBox); avCol.appendChild(avCbLbl); } } fUpdateAutoVisit(false); } else { // new log page GM_log("new log page!"); waitForKeyElements('div.gameplay-list-item', new_page_trackables); } // Update checkboxs whenever window gets focus, so changes in other tabs are recognized. window.document.addEventListener("focus", fWinFocus, true); var vsdt = document.getElementById("ctl00_ContentBody_LogBookPanel1_valLogInfoMaxLength"); if (vsdt) { // Create span to hold new controls. var spanCtrls = document.createElement("span"); spanCtrls.id = 'spanCtrls'; spanCtrls.style.whiteSpace = 'nowrap'; spanCtrls.style.fontSize = '20px'; // vsdt.appendChild(spanCtrls); insertAheadOf(spanCtrls, vsdt); // Create span to hold Character counter control. var spanCounter = document.createElement("span"); spanCounter.id = 'spanCounter'; // Character counter and add to span. //var spanCharsLeft = document.createElement("span"); //spanCharsLeft.id = 'spanCharsLeft'; //spanCharsLeft.style.fontSize = '12px'; //spanCharsLeft.appendChild(document.createTextNode(' \u00A0 Chars Left: ')); //spanCharsLeft.title = 'Characters remaining before reaching maximum limit'; //spanCharsLeft.style.fontWeight = 'bold'; //spanCharsLeft.style.display = 'none'; //var txtCharsLeft = (document.createTextNode(maxLogLen)); //txtCharsLeft.id = 'txtCharsLeft'; //spanCharsLeft.appendChild(txtCharsLeft); //spanCounter.appendChild(spanCharsLeft); //SetCntBtn(); spanCtrls.appendChild(spanCounter); var commentstxt = document.getElementById("litDescrCharCount"); var lnkSmileys = document.createElement("p"); insertAfter(lnkSmileys, commentstxt); // Change smiley button to open smiley bar. lnkSmileys.href = 'javascript:void(0)'; //lnkSmileys.addEventListener("click", fSmileyBarOnOff, true); //lnkSmileys.title = 'Open/Close the Smiley Bar'; // Create smiley bar. var sbTable = document.createElement('table'); sbTable.style.visibility = 'none'; var sbRow = document.createElement('tr'); var sbCol = document.createElement('td'); sbTable.appendChild(sbRow); sbRow.appendChild(sbCol); sbCol.id = 'sbCol'; sbTable.style.width = '118px'; sbTable.style.border = 'solid 1px rgb(68, 142, 53)'; sbTable.style.marginTop = '10px'; sbTable.style.MozBorderRadius = '5px'; sbTable.style.backgroundColor = 'rgb(239, 239, 239)'; var arSbImgs = ['icon_smile.gif', 'icon_smile_big.gif', 'icon_smile_cool.gif', 'icon_smile_blush.gif', 'icon_smile_tongue.gif', 'icon_smile_evil.gif', 'icon_smile_wink.gif', 'icon_smile_clown.gif', 'icon_smile_blackeye.gif', 'icon_smile_8ball.gif', 'icon_smile_sad.gif', 'icon_smile_shy.gif', 'icon_smile_shock.gif', 'icon_smile_angry.gif', 'icon_smile_dead.gif', 'icon_smile_sleepy.gif', 'icon_smile_kisses.gif', 'icon_smile_approve.gif', 'icon_smile_dissapprove.gif', 'icon_smile_question.gif' ]; var arSbTitles = ['smile', 'big smile', 'cool', 'blush', 'tongue', 'evil', 'wink', 'clown', 'black eye', 'eightball', 'frown', 'shy', 'shocked', 'angry', 'dead', 'sleepy', 'kisses', 'approve', 'disapprove', 'question' ]; var arSbCodes = ['[:)]', '[:D]', '[8D]', '[:I]', '[:P]', '[}:)]', '[;)]', '[:o)]', '[B)]', '[8]', '[:(]', '[8)]', '[:O]', '[:(!]', '[xx(]', '[|)]', '[:X]', '[^]', '[V]', '[?]' ]; for (var c = 0; c < arSbImgs.length; c++) { var sbLink = document.createElement("a"); var sbImg = document.createElement("img"); sbImg.src = '../images/icons/' + arSbImgs[c]; sbImg.border = 0; if (NewRel) { sbLink.style.marginLeft = '5px'; sbLink.style.marginRight = '5px'; } else { sbLink.style.marginLeft = '6px'; sbLink.style.marginRight = '6px'; } sbLink.appendChild(sbImg); sbLink.title = arSbTitles[c]; sbLink.setAttribute('code', arSbCodes[c]); sbLink.href = 'javascript:void(0)'; sbLink.addEventListener("click", fSmileyClicked, true); sbCol.appendChild(sbLink); } var ctBreak = document.createElement('br'); insertAfter(ctBreak, lnkSmileys); insertAfter(sbTable, ctBreak); lnkSmileys.setAttribute('status', true); sbTable.style.visibility = 'visible'; } // Insert element after an existing element. function insertAfter(newElement, anchorElement) { anchorElement.parentNode.insertBefore(newElement, anchorElement.nextSibling); } // Insert element aheadd of an existing element. function insertAheadOf(newElement, anchorElement) { anchorElement.parentNode.insertBefore(newElement, anchorElement); } function removeNode(node) { node.parentNode.removeChild(node); } // Update checkmark whenever this tab gets focus, to keep all tabs in sync. function fWinFocus() { fUpdateAutoVisit(false); } // Change checkmarks and visit action based on stored trackers. function fUpdateAutoVisit(UpdateDropdown) { // Counter for number of auto-trackers checked. var atc = 0; var new_page = false; // Get list of auto-visiting trackers, and put in array. var arAutoTrackers = GM_getValue('AutoTrackers' + SignedInAs, '').split(','); for (var idx in arTrackers) { var cbox = document.getElementById('chkbox_' + arTrackers[idx]); var radios = jq("input[name=actions-" + arTrackers[idx] + "]:radio"); var drop = document.getElementById(cbox.getAttribute('drpdwnctl', '')); var label = document.getElementById(cbox.getAttribute('for', '')); var span = document.getElementById(cbox.getAttribute('for_span', '')); var bSetToAuto = (arAutoTrackers.indexOf(arTrackers[idx]) >= 0); cbox.checked = bSetToAuto; if (bSetToAuto) { ++atc; if (label && span) { // new page span.style.backgroundColor = '#3d76c5'; span.style.color = '#ffffff'; new_page = true; } if (UpdateDropdown) { var ev = document.createEvent('Events'); ev.initEvent('change', true, true); if (drop) { // old page drop.value = drop.options[drop.options.length - 1].value; drop.dispatchEvent(ev); } else if (radios) { // new page var radio_select = radios.filter('[value=75]'); radio_select.prop('checked', true); radio_select[0].dispatchEvent(ev); } } } else { if (label && span) { // new page span.style.backgroundColor = '#ffffff'; span.style.color = '#3d76c5'; } } } // Create Visit & Submit button. var e_VisSubBtn = document.getElementById("VisSubBtn"); if (e_VisSubBtn) { if (atc === 0) { removeNode(e_VisSubBtn); } else { e_VisSubBtn.innerHTML = '<span>Visit ' + atc + ' trackables & Post</span>'; e_VisSubBtn.value = 'Visit ' + atc + ' & Submit'; } } else { if (atc > 0) { var log_button = get_log_button(); var log_button_parent = log_button.parentNode; if (new_page) { e_VisSubBtn = document.createElement("button"); e_VisSubBtn.className = 'btn btn-primary'; } else { e_VisSubBtn = document.createElement("input"); e_VisSubBtn.className = 'Button'; } e_VisSubBtn.type = 'button'; e_VisSubBtn.id = "VisSubBtn"; e_VisSubBtn.style.marginRight = '20px'; e_VisSubBtn.innerHTML = '<span>Visit ' + atc + ' trackables & Post</span>'; e_VisSubBtn.value = 'Visit ' + atc + ' & Submit'; e_VisSubBtn.disabled = log_button.disabled; log_button_parent.insertBefore(e_VisSubBtn, log_button); e_VisSubBtn.addEventListener("mousedown", fVisSubBtnClicked, true); } } } // If travel bugs, hide, and add link to show. var e_LogBookPanel1_TBPanel = document.getElementById("ctl00_ContentBody_LogBookPanel1_TBPanel"); if (e_LogBookPanel1_TBPanel) { if (!bShowInventory) { e_LogBookPanel1_TBPanel.style.display = 'none'; } e_tblTravelBugs = document.getElementById("tblTravelBugs"); if (e_tblTravelBugs) { var s1 = ''; var BugCount = (e_tblTravelBugs.rows.length - 2); if (BugCount != 1) { s1 = 's'; } var e_BugCountSpan = document.createElement("span"); e_BugCountSpan.style.color = 'rgb(255, 0, 0)'; e_BugCountSpan.style.fontWeight = 'bold'; e_BugCountSpan.style.paddingRight = '40px'; var e_BugCountLink = document.createElement("a"); e_BugCountLink.href = 'javascript:void(0)'; e_BugCountLink.title = 'Click to show/hide inventory'; e_BugCountLink.addEventListener("click", ToggleInventory, true); e_BugCountLink.appendChild(document.createTextNode(BugCount + ' item' + s1 + ' in inventory')); e_BugCountSpan.appendChild(e_BugCountLink); get_log_button().parentNode.insertBefore(e_BugCountSpan, get_log_button().parentNode.firstChild); } } // Handler for Visit & Submit button. Update dropdowns and click submit button. function fVisSubBtnClicked() { var log_button = get_log_button(); log_button.focus(); fUpdateAutoVisit(true); log_button.click(); } function get_log_button() { var log_button = e_LogBookPanel1_LogButton; if (!log_button) // new page log_button = jq('.btn-submit')[0]; return log_button; } // When checkmarks changed, update list of stored trackers, and execute function to // update display. function fAutoVisitChanged() { var arAutoTrackers = GM_getValue('AutoTrackers' + SignedInAs, '').split(','); var cbTracker = this.getAttribute('tracker'); var idx = arAutoTrackers.indexOf(cbTracker); var bInList = (idx >= 0); if (this.checked) { if (!bInList) { arAutoTrackers.push(cbTracker); } } else { if (bInList) { arAutoTrackers.splice(idx, 1); } } GM_setValue('AutoTrackers' + SignedInAs, arAutoTrackers.join(',')); fUpdateAutoVisit(false); } // Show/hide inventory. function ToggleInventory() { bShowInventory = (!bShowInventory); if (bShowInventory) { e_LogBookPanel1_TBPanel.style.display = ''; } else { e_LogBookPanel1_TBPanel.style.display = 'none'; } } function fSmileyClicked() { var sCode = this.getAttribute('code'); // Autotrim selection; //fAutoTrim(); // Reset work fields. var nTxt = ''; // Save original text value and scroll position. var oTxt = e_LogTextArea.value; var txtTop = e_LogTextArea.scrollTop; // If portion of the text selected, save that text. var selStart = e_LogTextArea.selectionStart; var selEnd = e_LogTextArea.selectionEnd; // Get text on each side of the selection/carat; var txt1 = oTxt.substr(0, selStart); var txt2 = oTxt.substr(selEnd); // Create new text and insert into text area. nTxt = txt1 + sCode + txt2; e_LogTextArea.value = nTxt; // Position carot, based on if any text was selected. var newCaretPos = selStart + sCode.length; e_LogTextArea.focus(); e_LogTextArea.selectionStart = newCaretPos; e_LogTextArea.selectionEnd = newCaretPos; e_LogTextArea.scrollTop = txtTop; // TextChg(); } function new_page_trackables(node) { var button_groups = node.find('div.actions'); //GM_log("groups found: " + button_groups.length); if (!button_groups.length) return false; var button_group = button_groups[0]; var tb_code = button_group.firstChild.nextSibling.firstChild.nextSibling.name.replace('actions-', ''); var avTracker = tb_code; //var avDrpDwn = e_bodyTravelBugs.rows[r].cells[2].childNodes[1].id; arTrackers.push(avTracker); //var avCol = document.createElement('td'); avCol = button_group; //insertAfter(avCol, e_bodyTravelBugs.rows[r].cells[cp]); var avChkBox = document.createElement('input'); avChkBox.type = 'checkbox'; avChkBox.id = 'chkbox_' + avTracker; avChkBox.setAttribute('tracker', avTracker); avChkBox.setAttribute('for', 'label_' + avTracker); avChkBox.setAttribute('for_span', 'span_' + avTracker); //avChkBox.setAttribute('row', r); //avChkBox.setAttribute('drpdwnctl', avDrpDwn); avChkBox.addEventListener("click", fAutoVisitChanged, true); avChkBox.style.height = '1px'; avChkBox.style.width = '1px'; avChkBox.style.margin = '-1px'; avChkBox.style.padding = 0; avChkBox.style.border = 0; avChkBox.style.overflow = 'hidden'; var avCbLbl = document.createElement('label'); avCbLbl.setAttribute('for', 'chkbox_' + avTracker); avCbLbl.id = 'label_' + avTracker; //avCbLbl.appendChild(document.createTextNode('Auto-Visit')); var new_span = document.createElement('span'); new_span.setAttribute('class', 'label'); new_span.id = "span_" + avTracker; new_span.appendChild(document.createTextNode('Auto-Visit')); avCbLbl.appendChild(avChkBox); avCbLbl.appendChild(new_span); button_group.appendChild(avCbLbl); fUpdateAutoVisit(false); return false; }