/* TradeMe PhotoView //Shows thumbnails for all listings in TradeMe Version 0.37.1 (18 June 2018) Author: tbird81 / JimBob Baggins Licence: Will be free to edit as you choose, but i'd like to sort it out a bit first Gui: {333eb056-63c4-4e4b-9589-85a0d46d22b0} // Future improvements For me to think about: - DieNicelies for GM functions. - Convert to normal xmlhttprequest - More resilience Fix the pop ups since TradeMe's changes. // Risks Risks of using this software: - Your incoming traffic may slightly increase because more pictures are loaded. - This software may slow down the loading of TradeMe listings pages. - You might forget that other people don't have this script, so may under-promote your auction. - TradeMe may change its site without notice, rendering this script useless. Changes: - v0.37.1 TM have switched to a peculiar list layout - v0.37 Switched to https - v0.36.1 Grrr... - v0.36 Bug fix... - v0.35 Pop-ups in gallery view of clothing/home & living fixed. - v0.31 New asynchronous clothing not showing pop-ups. Had to finally use jquery... - v0.30 Obvious speed fix made. Property slowness should be eliminated. - v0.29 Big changes people! - v0.28.3 Chrome strikes again... - v0.28.2 Double D'oh! - v0.28.1 D'oh! - v0.28 Property and Flatmates were causing issues. Should be good now. - v0.27 Fixed my shennanigans. - v0.26 Fixed TradeMe shennanigans. - v0.25 Fixed clothing issue. - v0.23 Open homes bug fixed. - v0.22 Big Zooms! - v0.21 TM Server change... - v0.20 Chrome's GM_xmlhttpRequest issue bypassed (will probably be resolved by them in due course)... - v0.15 Stuffed up the href link on the image brought forward. - v0.08 Sorry about the vary slow update!!! Should work with new trademe. I'm not sure what I was doing wrong. - v0.07 Fixed snippets. - v0.06 Updated image folder. Prior versions will not work. - v0.05 Displays an enlarged image when the mouse hovers over a thumbnail - v0.04 Now adds snippets of information about items. - v0.04 Uses maxHeight and maxWidth styles to confine picture to 85x64px - v0.03 Remove an unneeded loop! - v0.02 Made the User-agent the same as the browser. - v0.02 Exits search for images once first thumbnail has been found . - v0.02 Exits search for images once matching icon is found. - v0.02 Changed some variable names to make more sense. */ // ==UserScript== // @name TradeMe PhotoView // @namespace http://www.girlza.com/ // @include https://www.trademe.co.nz/* // @description Show thumbnails for all listings in TradeMe // @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js // @grant GM_addStyle // @grant metadata // @version 0.37.1 // @downloadURL none // ==/UserScript== //This allows you to turn off unnecessary features var showThumbs = true; var showSnippets = true; var showZoom = true; function addCustomSearchResult (jNode) { //Open Homes were bugging out var z = document.getElementsByClassName('openhomes') for (var i = 0; i < z.length; i++) { if (z[i].tagName == "LI") { z[i].style.width = '170px'; z[i].style.textAlign = 'center'; z[i].childNodes[1].style.width = '170px'; z[i].childNodes[1].style.textAlign = 'center'; } } //The prototype for the callback function that allows me to remember what link I was loading! Function.prototype.bind = function(thisObject) { var method = this; var oldargs = [].slice.call(arguments, 1); return function() { var newargs = [].slice.call(arguments); return method.apply(thisObject, oldargs.concat(newargs)); }; } var allImgs, thisImg; var globalTimer; //First we load all the images of that little camera allImgs = document.evaluate( "//img | //div[@class='image'] | //div[@class='image ']", //the name of the little camera icon document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); //Then we go through them one-by-one for (var i = 0; i < allImgs.snapshotLength; i++) { var n = allImgs.snapshotItem(i).src; var bgIm = false if(typeof n === 'undefined'){ n = allImgs.snapshotItem(i).style.backgroundImage; n = n.substring(4,n.length-1).replace(/["']/g, ""); bgIm = true; } if (n.indexOf('hasPhoto_160x120.png') > -1) { thisImg = allImgs.snapshotItem(i); //the photos exist but no thumbnail thisImg.setAttribute('thumbnailnumber', i); //We need to request the page that the icon links to, to get it's thumbnail if (thisImg.parentNode.href) { var oReq = new XMLHttpRequest(); oReq.open("GET", thisImg.parentNode.href); oReq.addEventListener("load", cbReplaceWithPhoto.bind({ specificIcon: thisImg.parentNode }), false); oReq.send(); } } else if (n.indexOf('/lv2/') > -1 || n.indexOf('/gv/') > -1 || n.indexOf('/med/') > -1 || n.indexOf('/tq/') > -1 || bgIm){ thisImg = allImgs.snapshotItem(i); thisImg.setAttribute('thumbnailnumber', i); addHover(thisImg, bgIm) } } //Set the style up in the tag var head = document.getElementsByTagName('head')[0]; style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = '.enlargement {visibility:hidden;position:absolute;z-index:100;top:20px;}\r\n.enlargement img {}'; head.appendChild(style); var dimsz = document.getElementById("container").offsetLeft + document.getElementById("mainContent").offsetLeft style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = ".imgBig {top:50px;position:absolute;max-width:100%;min-height:100%;margin-left:20px;left:0px;border:1px solid #000;box-shadow:0 0 17px #000;-moz-box-shadow:0 0 17px #000;-webkit-box-shadow:0 0 17px #000;}"; head.appendChild(style); String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); } function hasClass(element, cls) { return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1; } function addHover(imgUse, bgIm){ //This handles the tooltip-like zoom function var zoomDiv = document.createElement('div'); zoomDiv.setAttribute('id', "enlargement" + imgUse.getAttribute('thumbnailnumber')); zoomDiv.setAttribute('class', 'enlargement'); document.body.appendChild(zoomDiv); //When mouse goes over it starts a timer. imgUse.addEventListener( 'mouseover', function(event) { var x = event.pageX; var y = event.pageY var divId = 'enlargement' + this.getAttribute('thumbnailnumber'); obj = document.getElementById(divId); var n = this.src; if (bgIm){ n = this.style.backgroundImage; n = n.substring(4,n.length-1).replace(/["']/g, "") var x1 = n.indexOf('photoserver') var x2 = n.indexOf('/',x1+13) n = n.substring(0,x1+12)+"full"+n.substring(x2,n.length) } obj.innerHTML = ""; obj.innerHTML = obj.innerHTML.replace('/lv2/', '/full/') obj.innerHTML = obj.innerHTML.replace('/med/', '/full/') obj.style.width = (dimsz - 20) + 'px' obj.style.top = (window.pageYOffset + 100) + 'px'; document.getElementById(divId).childNodes[0].className="imgBig" globalTimer = window.setTimeout( //after 700msec the pic will become visible function() { showPopupDiv(x, y, divId); }, 200); }, true); //Hide image and reset timer once mouse moves out imgUse.addEventListener('mouseout', function(event) { window.clearTimeout(globalTimer); document.getElementById('enlargement' + this.getAttribute('thumbnailnumber')).style.visibility = 'hidden'; }, true); } //This is the callback function that gets run when the itemDetailsPage has loaded //It grabs the filename of the thumbnail, and replaces the icon with it. function cbReplaceWithPhoto(rD) { //Borrowed some code from Gallery+. Thanks :-) var imgtag = //g.exec(rD.target.responseText); var imgsrc = /.*src="([^"]*)"/.exec(imgtag) if (imgsrc !== null) { replacementImg = document.createElement("img"); //replace it with this replacementImg.src = imgsrc[1].replace("\/tq\/", "\/lv2\/") var useThis = 0 var foundIt = false while (foundIt == false) { if (useThis < this.specificIcon.childNodes.length) { if (this.specificIcon.childNodes[useThis].nodeName.toUpperCase() == "IMG") { if (this.specificIcon.childNodes[useThis].hasAttribute("thumbnailnumber")) { foundIt = true } } } if (foundIt == false) { useThis = useThis + 1 } } var iconH = Number(this.specificIcon.childNodes[useThis].style.height.replace(/[^\d\.\-]/g, '')) + "px" var iconW = Number(this.specificIcon.childNodes[useThis].style.width.replace(/[^\d\.\-]/g, '')) + "px" if (iconH == "0px") {iconH = "120px"} if (iconW == "0px") {iconW = "160px"} replacementImg.style.maxHeight = iconH replacementImg.style.maxWidth = iconW replacementImg.setAttribute('thumbnailnumber', this.specificIcon.childNodes[useThis].getAttribute('thumbnailnumber')); if (this.specificIcon.childNodes[useThis].id.indexOf("GalleryView")>-1) { replacementImg = this.specificIcon.childNodes[useThis] } //replace the icon with the thumbnail this.specificIcon.replaceChild(replacementImg, this.specificIcon.childNodes[useThis]); addHover(replacementImg) } } /* Function to popup the hidden div */ function showPopupDiv(triggerX, triggerY, divId) { obj = document.getElementById(divId); obj.style.visibility = "visible"; //make it visible } } addCustomSearchResult(); waitForKeyElements (".supergrid-overlord, #ListViewList", addCustomSearchResult); 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 = $(selectorTxt); else targetNodes = $(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 = $(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; }