TradeMe PhotoView

Show thumbnails for all listings in TradeMe

As of 01/09/2017. See the latest version.

/*

TradeMe PhotoView


//Shows thumbnails for all listings in TradeMe

 Version 0.37 (01 September 2017)
 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 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
// ==/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']", //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 || bgIm){
        thisImg = allImgs.snapshotItem(i); 
        thisImg.setAttribute('thumbnailnumber', i);
        
        addHover(thisImg, bgIm)
        
    }
}

//Set the style up in the <HEAD> 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 = "<img src='" + n.replace('/gv/', '/full/') + "'>";
                    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 = /<img.*mainImage.*\/>/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;
}