Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Anyone interested/know how to make a Greasemonkey script?

Options
  • 17-11-2011 9:59pm
    #1
    Registered Users Posts: 2,840 ✭✭✭


    Quick question, anyone out these know anything about greasemonkey? :)

    Tesco.ie have their online grocery website, however in these recessionary times a lot of people would like if it worked like a normal online e-commerce site by allowing users to sort their search results based on ascending price :cool:, rather than the way they present search results which makes no sense whatsoever - I assume they charge their supplies hello money to show up in searches the same way they charge them for good shelf placement positions.

    Now, a guy in the UK called George Nixon wrote a greasemonkey script called Tesco Money Saver that worked up till mid 2009 on the UK site which allowed you to sort by price ascending, however I know very little about greasemonkey (or programming in general) - would it be possible to modify this script and get it running on the Tesco.ie website and help people to find groceries cheaper?


Comments

  • Registered Users Posts: 2,089 ✭✭✭henryporter


    Well greasemonkey is just a Firefox addon allowing you to insert your own javascript into a web page to manipulate the data received from the server - I don't see why the javascript on Georges Site wouldn't work on the Irish Tescos site, without any changes needed - have you tried it that way?

    ps I has a look- installed Greasemonkey and the script but I'm not signing up to Tescos.ie to see what the result is!


  • Registered Users Posts: 2,840 ✭✭✭Arciphel


    It doesn't work on the tesco.ie site unfortunately...


  • Registered Users Posts: 10,624 ✭✭✭✭28064212


    This works, more or less, just adapted it from the previous add-on. Note that it's limited to the current page of groceries, so if your search returns more than the 20/40 that the Tesco search displays, you can only sort it page-by-page. Also, it tends to break the images
    // ==UserScript==
    // @name           TescoSort
    // @namespace      Tesco
    // @include        http://www.tesco.ie/groceries/product/search/*
    // ==/UserScript==
    
    //if product list exists, continue
    if (productsNode = document.getElementsByClassName("products")[0]) {
    	//create input (i.e. original products in original order) items list
    	var inputList = new Array();
    	//create output list
    	var outputList;
    
    	//populate input list
    	for (i = 0; i < countProducts(); i++) {
    		inputList[i] = getProduct(i);
    	}
    	
    	//if sort by price is turned on, continue
    	if (document.cookie.match("sortByPrice=true")) {
    		// add ticked checkbox to page
    		addCheckbox(productsNode, true);
    		sortByPrice();
    		printSorted();
    	}
    
    	//if sorting by price is disabled
    	else {
    		//... add unticked checkbox to page
    		addCheckbox(productsNode, false);
    	}
    }
    
    
    //////functions//////
    
    /////// object product constructor////
    function product(id, rank) {
    	this.id = id; //- tesco's id for item
    	var li = document.getElementById(id);
    	this.price = parseFloat(li.getElementsByClassName("linePrice")[0].innerHTML.replace(/[^0-9\.]+/g, '')); //- price in pounds
    	this.html = getHTMLbyID(id); // - original html code for this item to make the item appear on the page
    	this.next = null; //- next node in linked list
    	this.previous = null; //- previous node in linked list
    	this.rank = rank; //- original ranking on page (alphabetically) so can be reverted later if desired
    }
    
    ////// object linkedList constructor ///////
    function linkedList(){
    	this.firstNode = null;
    	this.lastNode = null;
    }
    
    // count number of products on page
    function countProducts() {
    	var count = 0;
    	productList = document.getElementsByClassName("products")[0];
    	return productList.childNodes.length;
    }
    
    // return a product by place in original list
    function getProduct(index) {
    	productList = document.getElementsByClassName("products")[0];
    	if (productList){
    		productId = productList.childNodes.item(index).id;
    		return new product(productId, index);
    	}
    	else {alert("error: Product list not found. Please report how this happened so this problem can be eliminated.");}
    }
    
    // get html of item by id
    function getHTMLbyID(myID){
    	myElement = document.getElementById(myID);
    	if (myElement) {
    		return myElement.innerHTML;
    	}
    }
    
    // set html of item by id
    function setHTMLbyID(myHTML, myID){
    	myElement = document.getElementById(myID);
    	if (myElement) {
    		myElement.innerHTML = myHTML;
    	}	
    }
    
    // insert a new node after an existing node
     function insertAfter( list, node, newNode) {
         newNode.previous = node;
         newNode.next = node.next;
         if (node.next == null) {
             node.next = newNode;
             list.lastNode = newNode;
    	}
         else {
             node.next.previous = newNode;
    		node.next = newNode;
    	 }
    }
    
    // insert a new node before an existing node
    function insertBefore(list, node, newNode) {
         newNode.previous = node.previous;
         newNode.next = node;
         if (node.previous == null) {
             node.previous = newNode;
             list.firstNode = newNode;
    	}
         else {
             node.previous.next = newNode;
    		 node.previous = newNode;
    	}
    }
    
    // insert a node at the beginning of the list
    function insertBeginning(list, newNode) {
         if (list.firstNode == null) {
             list.firstNode = newNode;
             list.lastNode = newNode;
             newNode.prev = null;
             newNode.next = null;
    	}
         else {
             insertBefore(list, list.firstNode, newNode)
    	}
    }
    
    // insert a node at the end of the list
    function insertEnd(list, newNode) {
         if (list.lastNode == null) {
             insertBeginning(list, newNode);
    	}
         else {
             insertAfter(list, list.lastNode, newNode);
    	}
    }
    
    // switch price sorting from current setting (i.e. on -> off or off -> on)
    function switchPriceSort() {
    	//if sorting is enabled...
    	if (document.cookie.match("sortByPrice=true")) {
    		//...turn it off
    		document.cookie="sortByPrice=false; path=/";
    		//and revert sorting to original order
    		revertSorting();
    	}
    	// sorting disabled...
    	else {
    		//.... turn it on!
    		document.cookie="sortByPrice=true; path=/";
    		// and then carry out sorting
    		if (outputList == null) {
    			sortByPrice();
    		}
    		printSorted();
    	}
    }
    
    //set an attribute for a node
    function setMyAttribute(node, attName, attValue) {
    	att = document.createAttribute(attName);
    	att.value = attValue;
    	node.setAttributeNode(att);
    }
    
    //check url's terms for a match to provided string
    function urlContains(str){
    	 return location.search.match(str);
    }
    
    //creates a checkbox which can enable or disable sorting by price
    function addCheckbox(node, checked) {
    	// create div node
    	divNode = document.createElement('DIV');
    	// create div's children, input and label
    	inputNode = document.createElement('INPUT');
    	labelNode = document.createElement('LABEL');
    	
    	//set labelNode attribute for => sortByPriceBox
    	setMyAttribute (labelNode, "for", "sortByPriceBox");
    	//set inputNode's attibutes - type => checkbox, checked => checked, onclick => switchPriceSort(this), name => sortByPriceBox
    	setMyAttribute(inputNode, "type", "checkbox");
    	if (checked) {
    		setMyAttribute(inputNode, "checked", "checked");
    	}
    	inputNode.addEventListener("click", switchPriceSort, true);
    	setMyAttribute(inputNode, "name", "sortByPriceBox");
    	//append label text to labelNode
    	textNode = document.createTextNode("Show products cheapest first");
    	labelNode.appendChild(textNode);
    	
    	//add style attributes to checkbox to match current  "show images" checkbox as of 17/2/08
    	setMyAttribute(divNode, "style", "font-size:0.7em; margin: 0em 1.4em 0 1.3em; width:50%; font-weight:bold");
    	setMyAttribute(inputNode, "style", "border: 0px solid white; margin: 0 0.5em 0 0; padding:0");
    	setMyAttribute(labelNode, "style", "padding-left:0.2em; color:#333333");
    	
    	// append input and label to div
    	divNode.appendChild(inputNode);
    	divNode.appendChild(labelNode);
    	//insert into DOM	
    	node.parentNode.insertBefore(divNode, node);
    }
    
    // traverse an output list to find item specified by rank
    function getProductByRank(outlist, rank) {
    	examinedItem = outlist.firstNode;
    	if (examinedItem.rank == rank) {
    		return examinedItem;
    	}
    	while (examinedItem.next) {
    		if (examinedItem.next.rank == rank) {
    			return examinedItem.next;
    		}
    		examinedItem = examinedItem.next
    	}
    }
    
    // revert sorted page to unsorted page
    function revertSorting () {
    
    	for (i = 0; i < inputList.length; i++) {		
    		setHTMLbyID(inputList[i].html, getProductByRank(outputList, i).id);
    	}
    }
    
    // traverse sorted output list and print in order
    function printSorted() {
    	//for each product on page
    	examinedItem = outputList.firstNode;
    	setHTMLbyID(getHTMLbyID(examinedItem.id), inputList[0].id);
    
    	for (i = 1; i < countProducts(); i++) {	
    		//replace with outputList item
    		setHTMLbyID(examinedItem.next.html, inputList[i].id);
    		if (examinedItem.next) {examinedItem = examinedItem.next;}
    	}
    }
    	
    // set global variable outputList to a linked list of products ordered in ascending order (cheapest first)
    function sortByPrice() {
    	
    	// create list for outputting
    	outputList = new linkedList();
    	//add first item to output list
    	insertBeginning(outputList, inputList[0]);
    	//if second item is cheaper, add to beginning...
    	if (inputList[1].price < inputList[0].price) insertBeginning(outputList, inputList[1]);
    	//...or else add to the end
    	else insertEnd(outputList, inputList[1]);
    
    	/////add products to output list///////
    	//get a new product to enter to the output list
    	for  (i = 2; i < inputList.length; i++) {
    		newProduct = inputList[i];
    		//create an iteration pointer to traverse the list
    		examinedProduct = outputList.firstNode;
    		// look through output list until a place is found for the new product
    		flagItemNotPlacedYet = true;
    		while (flagItemNotPlacedYet) {
    			//if new product is cheaper than examined product...
    			if (newProduct.price < examinedProduct.price) {
    				//... then add new product before examined product in the list
    				insertBefore(outputList, examinedProduct, newProduct);
    				//mark it as placed
    				flagItemNotPlacedYet = false;
    			}
    			else if (examinedProduct.next == null) {		
    				//...add new product to end of list
    				insertEnd(outputList, newProduct);
    				//and mark item as placed
    				flagItemNotPlacedYet = false;
    			}
    			//if more products left to examine...
    			if (examinedProduct.next != null) {
    				// examine next product
    				examinedProduct = examinedProduct.next;
    			}
    		}
    	}
    }
    

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users Posts: 2,840 ✭✭✭Arciphel


    28064212, you are an absolute legend. The original creator said that it only works when you have it in list view alright, in the grid view it never worked. I am going to try it at home tonight ;-) Are you going to share it anywhere? You should, I'd say a fair few people would be very appreciative (as I am)...


  • Registered Users Posts: 2,840 ✭✭✭Arciphel


    It works brilliantly, with the caveat that it only sorts the current page. The next question (you already know what it's going to be!) - how can you tell the website to return more than 20 or 40 results?


  • Advertisement
  • Registered Users Posts: 2,840 ✭✭✭Arciphel


    Tesco replied to my email...

    Dear Paul
    Firstly, I'd like to thank you for contacting me regarding this matter and please allow me to apologise for the delay in getting back to you. We do normally try to reply to all enquiries as quickly as possible, but unfortunately, we have had a very high volume of inbound emails that have affected our response times and let you down.


    I'm sorry but there is not a facility to search by price but if you search “Tesco Value’ you will get the cheapest or there about. (:rolleyes:)



    Finally, I hope the information I've provided has answered your questions over this matter and I apologise for not being able to help.
    If you’ve any further queries please don’t hesitate to contact me at online@tesco.co.uk.
    Kind Regards

    Stephen Wood
    Tesco Ireland Grocery Customer Services

    ?ui=2&ik=98620e9cac&view=att&th=133c5a570870cb7e&attid=0.0.1.1&disp=emb&zw

    .................. Original Message ..................

    To: customer.services@tesco.ie
    Received: 17/11/2011


    Subject: Tesco online website, not possible to sort search results by price?

    Hi there,

    Just a quick question.

    Maybe I am missing something completely obvious here, but - is it possible
    on the Tesco online website to sort search results based on price?

    For instance, if I search for liquid hand wash, I should be able to sort
    the results from low to high price. I can't seem to see how to do this at
    the moment.

    Thanks,
    Paul.


  • Registered Users Posts: 10,624 ✭✭✭✭28064212


    Arciphel wrote: »
    It works brilliantly, with the caveat that it only sorts the current page. The next question (you already know what it's going to be!) - how can you tell the website to return more than 20 or 40 results?
    You can't, Tesco only have that option server-side, it's not a client parameter.

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



  • Registered Users Posts: 1,311 ✭✭✭Procasinator


    I'm haven't seen the Tesco listings, nor am I very experienced in using Greasemonkey, but couldn't you make requests from the script to the next page (using the pagination links) and build the product list up?

    You could make an AJAX request, create an element (say pageElem, but really an array), use the innerHTML of that element which will then build the DOM of the response. Then use pageElem instead of document to find all your products on the page. Keep fetching pages as long as there is a next page link.


  • Registered Users Posts: 10,624 ✭✭✭✭28064212


    I'm haven't seen the Tesco listings, nor am I very experienced in using Greasemonkey, but couldn't you make requests from the script to the next page (using the pagination links) and build the product list up?

    You could make an AJAX request, create an element (say pageElem, but really an array), use the innerHTML of that element which will then build the DOM of the response. Then use pageElem instead of document to find all your products on the page. Keep fetching pages as long as there is a next page link.
    Yep, have done it before with other stuff, but it's not great performance-wise. For example, "milk" turns up 25 pages of results, you'd have to make 25 requests, and parse each of them. It's very slow

    Boardsie Enhancement Suite - a browser extension to make using Boards on desktop a better experience (includes full-width display, keyboard shortcuts, dark mode, and more). Now available through your browser's extension store.

    Firefox: https://addons.mozilla.org/addon/boardsie-enhancement-suite/

    Chrome/Edge/Opera: https://chromewebstore.google.com/detail/boardsie-enhancement-suit/bbgnmnfagihoohjkofdnofcfmkpdmmce



Advertisement