﻿/***
@title:
Live Search

@version:
2.0

@author:
Andreas Lagerkvist

@date:
2008-08-31

@url:
http://andreaslagerkvist.com/jquery/live-search/

@license:
http://creativecommons.org/licenses/by/3.0/

@copyright:
2008 Andreas Lagerkvist (andreaslagerkvist.com)

@requires:
jquery, jquery.liveSearch.css

@does:
Use this plug-in to turn a normal form-input in to a live ajax search widget. The plug-in displays any HTML you like in the results and the search-results are updated live as the user types.

@howto:
jQuery('#q').liveSearch({url: '/ajax/search.php?q='}); would add the live-search container next to the input#q element and fill it with the contents of /ajax/search.php?q=THE-INPUTS-VALUE onkeyup of the input.

@exampleHTML:
<form method="post" action="/search/">

<p>
<label>
Enter search terms<br />
<input type="text" name="q" />
</label> <input type="submit" value="Go" />
</p>

</form>

@exampleJS:
jQuery('#jquery-live-search-example input[name="q"]').liveSearch({url: Router.urlForModule('SearchResults') + '&q='});
***/
jQuery.fn.liveSearch = function(conf) {
    var config = jQuery.extend({
        url: '/search-results.php?q=',
        id: 'jquery-live-search',
        duration: 400,
        typeDelay: 200,
        loadingClass: 'loading',
        onSlideUp: function() { },
        uptadePosition: false
    }, conf);

    var liveSearch = jQuery('#' + config.id);

    // Create live-search if it doesn't exist
    if (!liveSearch.length) {
        liveSearch = jQuery('<div id="' + config.id + '"></div>')
						.appendTo(document.body)
						.hide()
						.slideUp(0);

        // Close live-search when clicking outside it
        jQuery(document.body).click(function(event) {
            var clicked = jQuery(event.target);

            if (!(clicked.is('#' + config.id) || clicked.parents('#' + config.id).length || clicked.is('input'))) {
                liveSearch.slideUp(config.duration, function() {
                    config.onSlideUp();
                });
            }
        });
    }

    return this.each(function() {
        var input = jQuery(this).attr('autocomplete', 'off');
        var liveSearchPaddingBorderHoriz = parseInt(liveSearch.css('paddingLeft'), 10) + parseInt(liveSearch.css('paddingRight'), 10) + parseInt(liveSearch.css('borderLeftWidth'), 10) + parseInt(liveSearch.css('borderRightWidth'), 10);

        // Re calculates live search's position
        var repositionLiveSearch = function() {
            var tmpOffset = input.offset();
            var inputDim = {
                left: tmpOffset.left,
                top: tmpOffset.top,
                width: input.outerWidth(),
                height: input.outerHeight()
            };

            inputDim.topPos = inputDim.top + inputDim.height;
            inputDim.totalWidth = inputDim.width - liveSearchPaddingBorderHoriz;

            liveSearch.css({
                position: 'absolute',
                left: inputDim.left + 'px',
                top: inputDim.topPos + 'px',
                width: inputDim.totalWidth + 'px'
            });
        };

        // Shows live-search for this input
        var showLiveSearch = function() {
            // Always reposition the live-search every time it is shown
            // in case user has resized browser-window or zoomed in or whatever
            repositionLiveSearch();

            // We need to bind a resize-event every time live search is shown
            // so it resizes based on the correct input element
            $(window).unbind('resize', repositionLiveSearch);
            $(window).bind('resize', repositionLiveSearch);

            liveSearch.slideDown(config.duration);
        };

        // Hides live-search for this input
        var hideLiveSearch = function() {
            liveSearch.slideUp(config.duration, function() {
                config.onSlideUp();
            });
        };

        input
        // On focus, if the live-search is empty, perform an new search
        // If not, just slide it down. Only do this if there's something in the input
			.focus(function() {
			    if (this.value !== '') {
			        // Perform a new search if there are no search results
			        if (liveSearch.html() == '') {
			            this.lastValue = '';
			            input.keyup();
			        }
			        // If there are search results show live search
			        else {
			            // HACK: In case search field changes width onfocus
			            setTimeout(showLiveSearch, 1);
			        }
			    }
			})
        // Auto update live-search onkeyup
			.keyup(function() {
			    // Don't update live-search if it's got the same value as last time
			    if (this.value != this.lastValue) {
			        input.addClass(config.loadingClass);

			        var q = this.value;

			        // Stop previous ajax-request
			        if (this.timer) {
			            clearTimeout(this.timer);
			        }

			        // Start a new ajax-request in X ms
			        this.timer = setTimeout(function() {
			            jQuery.get(config.url + q, function(data) {
			                input.removeClass(config.loadingClass);

			                // Show live-search if results and search-term aren't empty
			                if (data.length && q.length) {
			                    liveSearch.html(data);

			                    // ########################################################
			                    //
			                    // START -- Goldsmiths specific ordering of results
			                    //
			                    // ########################################################

			                    // init variables
			                    var el = $("#live-search");
			                    var top5 = [], theRest = [];
			                    var company = false, charity = false, collections = false, exhibitions = false, assay = false, technology = false, centre = false;
			                    var idx = 0, idx2 = 0;
			                    var $output = null;                  

			                    // determine which strand we're in
			                    switch ($("body").attr("id")) {
			                        case "company":
			                            var sctn = "[The Goldsmiths' Company]";
			                            var strandBlockClass = "company";
			                            break;
			                        case "charity":
			                            var sctn = "[Charity & Education]";
			                            var strandBlockClass = "charity";
			                            break;
			                        case "collections":
			                            var sctn = "[Collections & Library]";
			                            var strandBlockClass = "collections";
			                            break;
			                        case "exhibitions":
			                            var sctn = "[Exhibitions & Promotions]";
			                            var strandBlockClass = "exhibitions";
			                            break;
			                        case "assay":
			                            var sctn = "[Assay Office]";
			                            var strandBlockClass = "assay";
			                            break;
			                        case "technology":
			                            var sctn = "[Technology & Training]";
			                            var strandBlockClass = "technology";
			                            break;
			                        case "thecentre":
			                            var sctn = "[The Centre]";
			                            var strandBlockClass = "thecentre";
			                            break;
			                    }

			                    var ttl = sctn.slice(1, -1);

			                    // loop through the search results to get the top 5 results from the current strand
			                    // and 1 result from any other strands

			                    $("div.results > div", el).each(function() {
			                        var cat = $.trim($(this).find("span.category").text());
			                        // process current strand
			                        if ((cat === sctn) && (idx < 5)) {
			                            top5[idx] = $(this).html();
			                            idx++;
			                        }
			                        // process other strands
			                        if (cat !== sctn) {
			                            switch (cat) {
			                                case "[The Goldsmiths' Company]":
			                                    if (company === false) {
			                                        theRest[idx] = "<div class='strand-block company'><h6>The Goldsmiths&rsquo; Company</h6>" + $(this).html() + "</div>";
			                                        company = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[Charity & Education]":
			                                    if (charity === false) {
			                                        theRest[idx] = "<div class='strand-block charity'><h6>Charity &amp; Education</h6>" + $(this).html() + "</div>";
			                                        charity = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[Collections & Library]":
			                                    if (collections === false) {
			                                        theRest[idx] = "<div class='strand-block collections'><h6>Collections &amp; Library</h6>" + $(this).html() + "</div>";
			                                        collections = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[Exhibitions & Promotions]":
			                                    if (exhibitions === false) {
			                                        theRest[idx] = "<div class='strand-block exhibitions'><h6>Exhibitions &amp; Promotions</h6>" + $(this).html() + "</div>";
			                                        exhibitions = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[Assay Office]":
			                                    if (assay === false) {
			                                        theRest[idx] = "<div class='strand-block assay'><h6>The Assay Office</h6>" + $(this).html() + "</div>";
			                                        assay = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[Technology & Training]":
			                                    if (technology === false) {
			                                        theRest[idx] = "<div class='strand-block technology'><h6>Technology &amp; Training</h6>" + $(this).html() + "</div>";
			                                        technology = true;
			                                        idx2++;
			                                    }
			                                    break;
			                                case "[The Centre]":
			                                    if (centre === false) {
			                                        theRest[idx] = "<div class='strand-block thecentre'><h6>The Centre</h6>" + $(this).html() + "</div>";
			                                        centre = true;
			                                        idx2++;
			                                    }
			                                    break;
			                            }
			                        }
			                    });

			                    $("div.results > div", el).remove();

			                    if (top5.length > 0) {
			                    $("div.results", el).append("<div class='strand-block " + strandBlockClass + "'><h6>" + sctn.slice(1, -1) + "</h6>");
			                    for (i = 0; i < top5.length; i++) {
			                        $(".results div.strand-block", el).append(top5[i]);
			                    }
			                    $("div.results", el).append("</div>");
                                }

			                    for (j = 0; j < theRest.length; j++) {
			                        $("div.results", el).append(theRest[j]);
			                    }

			                    $("div.results b", el).remove();

			                    // ########################################################
			                    //
			                    // END -- Goldsmiths specific ordering of results
			                    //
			                    // ########################################################

			                    showLiveSearch();
			                }
			                else {
			                    hideLiveSearch();
			                }
			            });
			        }, config.typeDelay);

			        this.lastValue = this.value;
			    }
			});

    });


};


