TalkBass price filter

Filters TalkBass for sale threads based on price

// ==UserScript==
// @name        TalkBass price filter
// @namespace   [email protected]
// @description Filters TalkBass for sale threads based on price
// @include     http://www.talkbass.com/forums/for-sale*
// @version     1
// @grant       none
// ==/UserScript==   

var FLOAT_REGEX = /\d+,?\d*(\.\d*)?/;
var PRICE_LOW_COOKIE_NAME = "talkbasspricefilter_pricelow";
var PRICE_HIGH_COOKIE_NAME = "talkbasspricefilter_pricehigh";
var HARD_FILTER_COOKIE_NAME = "talkbasspricefilter_hardfilter";

var getInput = function(promptString){
    //Prompts user to enter a price than can be converted to a float. 
    //Returns the value of the input converted to a float. Handles 
    //incorrect input by asking the user for a new entry.
    var acceptableInput =  false, priceString, priceVar;
    while(!acceptableInput){
        priceString = prompt(promptString).match(FLOAT_REGEX)[0]
            .replace(",", "");
        priceVar = parseFloat(priceString);
        if (isNaN(priceVar)){
            alert("Invalid input!");
        }
        else{
            acceptableInput = true;
        }
    }
    return priceVar;
};

var filterType = function(){
    //Asks the user whether she would like a hard or soft filter to be 
    //used. The hard filter eliminates threads without listed prices and 
    //threads with prices that cannot be converted to floats. The soft 
    //filter keeeps these threads. Returns true if hard filter is chosen 
    //or false if soft filter is chosen
    var acceptableInput = false;
    var hardFilter = false;
    while(!acceptableInput){
        var filterString = prompt("Would you like to use a HARD or " +
                                  "SOFT filter?").toUpperCase();
        switch(filterString){
            case "HARD":
                hardFilter = true;
                acceptableInput = true;
                break;
            case "SOFT":
                hardFilter = false;
                acceptableInput = true;
                break;
            default:
                alert("Invalid input!");
                break;
        }
    }
    return hardFilter;
};

var docCookies = {
/*\
|*|
|*|  :: cookies.js ::
|*|
|*|  A complete cookies reader/writer framework with full unicode support.
|*|
|*|  Revision #1 - September 4, 2014
|*|
|*|  https://developer.mozilla.org/en-US/docs/Web/API/document.cookie
|*|
|*|  This framework is released under the GNU Public License, version 3 or 
|*|  later.
|*|
|*|  http://www.gnu.org/licenses/gpl-3.0-standalone.html
|*|
|*|  Syntaxes:
|*|
|*|  * docCookies.setItem(name, value[, end[, path[, domain[, secure]]]])
|*|  * docCookies.getItem(name)
|*|  * docCookies.removeItem(name[, path[, domain]])
|*|  * docCookies.hasItem(name)
|*|  * docCookies.keys()
|*|
\*/
    getItem: function (sKey) {
        if (!sKey) { return null; }
        return decodeURIComponent(
            document.cookie.replace(
                new RegExp("(?:(?:^|.*;)\\s*" + 
                           encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, 
                                                            "\\$&") + 
                           "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
    },
    setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
        if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { 
            return false; 
        }
        var sExpires = "";
        if (vEnd) {
            switch (vEnd.constructor) {
                case Number:
                    sExpires = vEnd === Infinity ? 
                        "; expires=Fri, 31 Dec 9999 23:59:59 GMT" :
                        "; max-age=" + vEnd;
                    break;
                case String:
                    sExpires = "; expires=" + vEnd;
                    break;
                case Date:
                    sExpires = "; expires=" + vEnd.toUTCString();
                    break;
            }
        }
        document.cookie = encodeURIComponent(sKey) + "=" + 
            encodeURIComponent(sValue) + sExpires + 
            (sDomain ? "; domain=" + sDomain : "") + 
            (sPath ? "; path=" + sPath : "") + 
            (bSecure ? "; secure" : "");
        return true;
    },
    removeItem: function (sKey, sPath, sDomain) {
        if (!this.hasItem(sKey)) { return false; }
        document.cookie = encodeURIComponent(sKey) + 
            "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + 
            (sDomain ? "; domain=" + sDomain : "") + 
            (sPath ? "; path=" + sPath : "");
        return true;
    },
    hasItem: function (sKey) {
        if (!sKey) { return false; }
        return (new RegExp("(?:^|;\\s*)" + 
                           encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, 
                                                            "\\$&") + 
                           "\\s*\\=")).test(document.cookie);
    },
    keys: function () {
        var aKeys = document.cookie.replace(
            /((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, 
            "").split(/\s*(?:\=[^;]*)?;\s*/);
        for (var nLen = aKeys.length, nIdx = 0; nIdx < nLen; nIdx++) {
            aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]); 
        }
        return aKeys;
    }
};

var eraseAllCookies = function(){
    docCookies.removeItem(PRICE_LOW_COOKIE_NAME, "/", "talkbass.com");
    docCookies.removeItem(PRICE_HIGH_COOKIE_NAME, "/", "talkbass.com");
    docCookies.removeItem(HARD_FILTER_COOKIE_NAME, "/", "talkbass.com");
};

var createButton = function(){
    //Creates a button so that the filter parameters can be reset
    var input=document.createElement("input");
    input.type="button";
    input.value="Reset Filter";
    input.onclick = function(){
        eraseAllCookies();
        this.remove();
    };
    input.style.position = 'fixed';
    input.style.bottom = '240px';
    input.style.right = '80px';
    document.body.appendChild(input);
};

$(document).ready(function(){
    var priceLowCookieValue = docCookies.getItem(PRICE_LOW_COOKIE_NAME);
    var priceHighCookieValue = docCookies.getItem(PRICE_HIGH_COOKIE_NAME);
    var hardFilterCookieValue = docCookies.getItem(HARD_FILTER_COOKIE_NAME);
    var getPrices, hardFilter, priceLow, priceHigh;

    if(priceLowCookieValue === null || priceHighCookieValue === null || 
       hardFilterCookieValue === null){
        getPrices = true;

        while(getPrices){
            priceLow = getInput("Enter the lowest price you wish to see.");
            priceHigh = getInput("Enter the highest price you wish to see.");
            if(priceLow > priceHigh){
                alert("Your low price was greater than your high price!");
            }
            else{
                getPrices = false;
            }
        }

        hardFilter = filterType();
        docCookies.setItem(PRICE_LOW_COOKIE_NAME, priceLow.toString(), 24 * 3600,
                           "/", "talkbass.com");
        docCookies.setItem(PRICE_HIGH_COOKIE_NAME, priceHigh.toString(), 24 * 3600,
                           "/", "talkbass.com");
        if(hardFilter){
            hardFilterCookieValue = 'true';
        }
        else{
            hardFilterCookieValue = 'false';
        }
        docCookies.setItem(HARD_FILTER_COOKIE_NAME, hardFilterCookieValue, 24 * 3600,
                           "/", "talkbass.com");
    }
    else{
        priceLow = parseFloat(priceLowCookieValue);
        priceHigh = parseFloat(priceHighCookieValue);
        hardFilter = (hardFilterCookieValue == 'true');
    }

    createButton();

    if(hardFilter){
        $('li:not(:has(.pairsInline))').remove();
        $('.pairsInline:not(:has(span))').parents('li').remove();
        $('li[class*=prefix4]').remove();
        $('li[class*=prefix6]').remove();
        $('li[class*=prefix7]').remove();
    }

    //class pairsInline indicates the line under the thread titles that
    //contain the Price and Location information. The price itself is located 
    //in the only 'span' decendent of pairsInline 
    var prices = $('.pairsInline').find('span').contents(), price;

    for(var i = 0; i < prices.length; i++){
        price = prices[i].data.match(FLOAT_REGEX);
        if(price){
            price = parseFloat(price[0].replace(",",""));
            if(price < priceLow || price > priceHigh){
                //each thread is indicated by an 'li' selector, 'li' is not 
                //used for any other purpose
                $(prices[i]).parents('li').remove();
            }
        }
        else if(hardFilter){
            $(prices[i]).parents('li').remove();
        }
    }
});