﻿/*
 *		Gordon Food Service
 *		Site-wide scripts
 *
 *		Lee Allen [lee.allen@acquitygroup.com]
 *
 *		Copyright © 2008 Acquity Group LLC
 */

 /*
	Adds URL parsing support to jQuery
	http://projects.allmarkedup.com/jquery_url_parser/
 */
jQuery.url=function(){var segments={};var parsed={};var options={url:window.location,strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};var parseUri=function(){str=decodeURI(options.url);var m=options.parser[options.strictMode?"strict":"loose"].exec(str);var uri={};var i=14;while(i--){uri[options.key[i]]=m[i]||""}uri[options.q.name]={};uri[options.key[12]].replace(options.q.parser,function($0,$1,$2){if($1){uri[options.q.name][$1]=$2}});return uri};var key=function(key){if(!parsed.length){setUp()}if(key=="base"){if(parsed.port!==null&&parsed.port!==""){return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/"}else{return parsed.protocol+"://"+parsed.host+"/"}}return(parsed[key]==="")?null:parsed[key]};var param=function(item){if(!parsed.length){setUp()}if(typeof item=='undefined'){return(parsed.queryKey)}return(parsed.queryKey[item]===null)?null:parsed.queryKey[item]};var setUp=function(){parsed=parseUri();getSegments()};var getSegments=function(){var p=parsed.path;segments=[];segments=parsed.path.length==1?{}:(p.charAt(p.length-1)=="/"?p.substring(1,p.length-1):path=p.substring(1)).split("/")};return{setMode:function(mode){strictMode=mode=="strict"?true:false;return this},setUrl:function(newUri){options.url=newUri===undefined?window.location:newUri;setUp();return this},segment:function(pos){if(!parsed.length){setUp()}if(pos===undefined){return segments.length}return(segments[pos]===""||segments[pos]===undefined)?null:segments[pos]},attr:key,param:param}}();

/*
	Adds jQuery integration with Google Analytics. Modified from:
	http://davidsimpson.me/2008/06/18/jgoogleanalytics-google-analytics-integration-for-jquery/
*/
/**
 * @author   David Simpson david.simpson [at] nottingham.ac.uk
 * @version  1.0 2008-06-18
 * 
 * jGoogleAnalytics - Monitor events with Google Analytics ga.js tracking code
 * 
 * Requires jQuery 1.2.x or higher (for cross-domain $.getScript)
 * 
 * Uses some elements of gaTracker (c)2007 Jason Huck/Core Five Creative
 *    http://plugins.jquery.com/files/jquery.gatracker.js_0.txt  
 *  
 * @param {String} trackerCode
 * @param {Object} options see setings below
 *    
 * usage: 
 *	 $.jGoogleAnalytics( 'UA-XXXXXX-X');
 *	 $.jGoogleAnalytics( 'UA-XXXXXX-X', {anchorClick: true, pageViewsEnabled: false} );
 * 
 */
(function($){$.jGoogleAnalytics=function(trackerCode,options){settings={anchorClick:false,clickEvents:null,crossDomainSelector:false,domainName:false,evalClickEvents:null,evalSubmitEvents:null,extensions:['pdf','doc','xls','csv','jpg','gif','mp3','swf','txt','ppt','zip','gz','dmg','xml'],external:'/external/',mailto:'/mailto/',download:'/download/',organicSearch:null,pageViewsEnabled:true,sampleRate:null,submitEvents:null};if(options){$.extend(settings,options)}function setupTracking(){var pageTracker=_gat._getTracker(trackerCode);if(settings.topLevelDomain){pageTracker._setDomainName(settings.topLevelDomain)}if(settings.sampleRate){pageTracker._setSampleRate(settings.sampleRate)}if(settings.crossDomainSelector){pageTracker._setDomainName('none');pageTracker._setAllowLinker(true);$('form'+settings.crossDomainSelector).submit(function(){pageTracker._linkByPost(this)});$('a'+settings.crossDomainSelector).click(function(){pageTracker._link($(this).attr('href'))})}if(settings.organicSearch){$.each(settings.organicSearch,function(key,val){pageTracker._addOrganic(key,val)})}addTracking(pageTracker)};function addTracking(pageTracker){if(settings.anchorClick){$('a').each(function(){var u=$(this).attr('href');if(typeof(u)!='undefined'){var newLink=decorateLink(u);if(newLink.length){$(this).click(function(){pageTracker._trackPageview(newLink)})}}})}if(settings.clickEvents){$.each(settings.clickEvents,function(key,val){$(key).click(function(){pageTracker._trackPageview(val)})})}if(settings.evalClickEvents){$.each(settings.evalClickEvents,function(key,val){$(key).click(function(){evalVal=eval(val);if(evalVal!=''){pageTracker._trackPageview(evalVal)}})})}if(settings.evalSubmitEvents){$.each(settings.evalSubmitEvents,function(key,val){$(key).submit(function(){evalVal=eval(val);if(evalVal!=''){pageTracker._trackPageview(evalVal)}})})}if(settings.submitEvents){$.each(settings.submitEvents,function(key,val){$(key).submit(function(){pageTracker._trackPageview(val)})})}if(settings.pageViewsEnabled){pageTracker._trackPageview()}else{}};function decorateLink(u){var trackingURL='';if(u.indexOf('://')==-1&&u.indexOf('mailto:')!=0){var ext=u.split('.')[u.split('.').length-1];var exts=settings.extensions;for(i=0;i<exts.length;i++){if(ext==exts[i]){trackingURL=settings.download+u;break}}}else{if(u.indexOf('mailto:')==0){trackingURL=settings.mailto+u.substring(7)}else{var regex=/([^:\/]+)*(?::\/\/)*([^:\/]+)(:[0-9]+)*\/?/i;var linkparts=regex.exec(u);var urlparts=regex.exec(location.href);if(linkparts[2]!=urlparts[2]){trackingURL=settings.external+u}}}return trackingURL};setupTracking()}})(jQuery);

/*
	Small jQuery extension to allow ID generation
*/
if (!jQuery.generateId) {
	jQuery.generateId = function() {
		return arguments.callee.prefix + arguments.callee.count++;
	};
	jQuery.generateId.prefix = 'jq-';
	jQuery.generateId.count = 0;

	jQuery.fn.generateId = function() {
		return this.each(function() {
			this.id = $.generateId();
		});
	};
}
 
/*
	Load all required functions on DOM load
*/
$(function() {
	try {
		if (typeof lsAnalyticsAccountid != 'undefined') {
			$.jGoogleAnalytics(lsAnalyticsAccountid, {
				extensions: ['doc','eps','jpg','png','svg','xls','ppt','pdf','xls','zip','txt','vsd','vxd','js','css','rar','exe','wma','mov','avi','wmv','mp3'],
				download: '',
				anchorClick: true,
				pageViewsEnabled: false
			});
		}
	}
	catch (e) {}

	LayoutFixes.initialize();
	MultiTabPanel.initialize();
	DropDownMenu.initialize();
	DropShadow.initialize();
	Forms.initialize();
	HomepageReveal.initialize();
	Print.initialize();
	SlideShow.initialize();
	QuestionAndAnswer.initialize();
	EmailModal.initialize();
	PageModal.initialize();
	SiteSearch.initialize();
	FlashVideo.initialize();
	SWFEmbed.initialize();
	CollapsibleLists.initialize();
	ImageTips.initialize();
});

/*
	jQuery extension to clear default input values onfocus
	For password fields, it adds/removes a password field class that fakes the Password defaultValue
*/
$.fn.clearDefaultValue = function() {
	return this.focus(function() {
		if(this.value == this.defaultValue) {
			this.value = '';
		}
		if(this.type == 'password' && this.value == '') {
			$(this).removeClass('password-field');
		}
	}).blur(function() {
		if(!this.value.length) {
			this.value = this.defaultValue;
		}
		if(this.type == 'password' && this.value == '') {
			$(this).addClass('password-field');
		}
	});
};

/*
	Helper code to add classes for CSS selection
*/
var LayoutFixes = {
	initialize: function(){
		// We add column-left and column-right to the two column layouts
		$('.columns:not(.secondary-grid, .horizontal-callouts)')
			.children('.column-two:even').addClass('column-left').end()
			.children('.column-two:odd').addClass('column-right').end();
	}
}

/*
	Combines content into a multi tabbed panel with images that show info upon hover
*/
var MultiTabPanel = {
	initialize: function() {
		MultiTabPanel.clearAll();
		
		$('#multi-tab-panel').addClass('active');
		
		// Count the number of portraits for each tab body and add a class so the text is the proper width
		$('#multi-tab-panel div.tab-body').each(function(){
			$(this).addClass('clear-block');
			var widest = 1;
			// Find the widest row
			$(this).children('ul').each(function(){
				if ($(this).children('li').length > widest)
					widest = $(this).children('li').length;
			});
			
			$(this).addClass('tab-body-' + widest);
		});
		
		$('#multi-tab-panel div.tab-body > ul > li').children('span.portrait, a').mouseover(function() {
			MultiTabPanel.clearAll();
			$(this).parent().children('div').show();
		});
		
		$('#multi-tab-panel #tabs a').click(function(){
			$(this).parent().addClass('active').siblings().removeClass('active');
			$('#multi-tab-panel div.tab-body').hide();
			$('#multi-tab-panel div.tab-body:eq(' + $(this).parent().prevAll().length + ')').show()
				.children('ul').children('li:first').children('span.portrait, a').mouseover();
			return false;
		});
		
		$('#multi-tab-panel #tabs a:first').click();
	},
	clearAll: function() {
		$('#multi-tab-panel ul li div').each(function() {
			$(this).hide();
		});
	}
};

/*
	Simple drop-down menus on global navigation
*/
var DropDownMenu = {
	initialize: function() {
		$('#header #global-navigation li .drop-down-menu-wrap-outer').each(function() {
			$(this).parent().hover(
				function() {
					DropDownMenu.displayMenu($(this));
				},
				function() {
					DropDownMenu.clearAll();
				}
			);
		});
	},
	displayMenu: function(menu) {
		DropDownMenu.clearAll();
		menu.addClass('display-menu');
	},
	clearAll: function() {
		$('#header #global-navigation li').each(function() {
			$(this).removeClass('display-menu');
		});
	}
};

/*
	Adds presentational markup for drop-shadow framed images
	Adds markup to elements with class="drop-shadow"
	Adding class="drop-shadow interactive" will addiitonally add the indicator for clickable "interactive" images
*/
var DropShadow = {
	initialize: function() {
		$('.drop-shadow, .drop-shadow-left, .drop-shadow-right').each(function() {
			if ($(this).hasClass('flash')) {
				return false;
			}
			else {
				var isImagetip = $(this).is('.imagetip');
				$(this).removeClass('imagetip');
				
				// If the class is on an image, create a wrapping div and use that.
				var wrapper = $(this);
				if ($(this).is('img')) {
					$(this).wrap($('<div/>').addClass($(this).attr('class')));
					$(this).removeAttr('class');
					wrapper = $(this).parent();
				}

				wrapper.wrapInner('<div class="drop-shadow-outer"><div class="drop-shadow-inner"></div></div>');
				wrapper.find('div.drop-shadow-inner').prepend('<div class="drop-shadow-top-left"></div><div class="drop-shadow-top-right"></div><div class="drop-shadow-bottom-left"></div><div class="drop-shadow-bottom-right"></div>');
				
				if (isImagetip) ImageTips.addtip($(this));
			}
		});
	}
};


/*
	Various functions to enhance forms
*/
var Forms = {
	fakePasswordTimer: null,
	
	initialize: function() {
		Forms.clearDefaults();
		Forms.customControls();
		Forms.firefox2WindowsHack();
		Forms.fakePasswordDefault();
		Forms.fakePasswordHandleAutocomplete();
		Forms.experienceLogin();
	},
	/*
		Run clearDefaultValue on all inputs and password inputs
	*/
	clearDefaults: function() {
		$('input[type="text"],input[type="password"]').clearDefaultValue();
	},
	/*
		Runs replacement functions for select, radio, and checkbox elements
	*/
	customControls: function(parent) {
		parent = parent || document;
		$('select', parent).selectbox({selectedClass:'select-selected'});
		$('input[type="radio"]', parent).checkbox({cls:'custom-radio', empty: '/images/blank.png'});
		$('input[type="checkbox"]', parent).checkbox({cls:'custom-checkbox', empty: '/images/blank.png'});
	},
	/*
		Deals with Firefox 2 ignoring font-size in buttons by resizing them in two elements that the higher font-size will break
	*/
	firefox2WindowsHack: function() {
		if(window.navigator.platform === 'Win32' && $.browser.mozilla && $.browser.version.substr(0,3) == '1.8') {
			$('#find-your-local-store button span,#msds-lookup-center button span').css('font-size','8px');
		}	
	},
	/*
		Adds class to all password inputs to fake a defaultValue of "Password"
	*/
	fakePasswordDefault: function() {
		$('input[type="password"][value=""]').addClass('password-field');
	},
	/*
		Handles Experience Login autocomplete.
		This is a terrible hack, but it is needed.
		When the username gains focus, check every 50 ms to
		see if the password field has content. If it does then
		clear the password class and stop the interval.
		Also stop the interval if username loses focus.
	*/
	fakePasswordHandleAutocomplete: function() {
		var passwordAutocompleteFunction = function() {
			if ($('#password').length > 0 && $('#password').val().length > 0)
			{
				$('#password').removeClass('password-field');
				clearInterval(Forms.fakePasswordTimer);
			}
		};
		
		$('#username').focus(function(){
			if ($('#password').length > 0 && $('#password').val().length == 0) {
				Forms.fakePasswordTimer = setInterval(passwordAutocompleteFunction, 50);
			}
		}).blur(function(){
			clearInterval(Forms.fakePasswordTimer);
			Forms.fakePasswordTimer = setTimeout(passwordAutocompleteFunction, 1);
		});
		
		$(window).load(function(){
			Forms.fakePasswordTimer = setTimeout(passwordAutocompleteFunction, 200);
		});
	},
	/*
		When a user signs into Experience, ping Google Analytics
	*/
	experienceLogin: function() {
		$('#LoginForm').submit(function(){
			try {
				if (typeof pageTracker != 'undefined') {
					pageTracker._trackPageview('/experience/portal/login.do');
				}
			}
			catch (e) {
			
			}
		});
	}
};

/*
	Enables "slide-up" <div> on Homepage
*/
var HomepageReveal = {
	initialize: function() {
		$('#gfshero #hero-info').bind('mouseenter',HomepageReveal.slideUp);
	},
	slideUp: function() {
		$('#gfshero #hero-info').animate(
			{top: '232px'},
			250,
			function() {
				$(this).unbind('mouseenter',HomepageReveal.slideUp).bind('mouseleave',HomepageReveal.slideDown);
			}
		);
	},
	slideDown: function() {
		$('#gfshero #hero-info').animate(
			{top: '308px'},
			250,
			function() {
				$(this).unbind('mouseleave',HomepageReveal.slideDown).bind('mouseenter',HomepageReveal.slideUp);
			}
		);
	}
};

/*
	Bind window.print to all links under class="print" <li>s
*/
var	Print = {
	initialize: function() {
		$('.print a').click(function() {
			window.print();
			return false;
		});
	}
};

/*
	Enables users to cycle through two or more images with in a <div> with a class="slideshow"
	The script looks for all the images in the div, hides every one but the first, then reveals the next image in the source order onclick.
*/
var SlideShow = {
	initialize: function() {
		$('.slideshow').each(function() {
			//	Hide all images
			$(this).children('img').each(function() {
				$(this).hide();
			});
			//	Show the first one
			$(this).children('img:first').show();
		}).click(function() {
			SlideShow.nextImage($(this));
		}).hover(
			function() {
				SlideShow.mouseOver($(this));
			},
			function() {
				SlideShow.mouseOut($(this));
			}
		);
	},
	nextImage: function(element) {
		element.children('img').each(function() {
			if($(this).is(':visible')) {
				//	Hide current image
				$(this).hide();
				//	If this is the last image, show the first, if not, show the next image
				if($(this).next('img').length > 0) {
					$(this).next('img').show();
				} else {
					$(this).parent().children('img:first').show();
				}
				return false;
			}
		});
	},
	mouseOver: function(element) {
		element.css('cursor','pointer');
	},
	mouseOut: function(element) {
		element.css('cursor','inherit');
	}
};


/*
	jQuery extension to add a case insensitive version of ":contains"
*/
jQuery.extend(jQuery.expr[':'], {
	"contains-nc": function(elem, i, match){
		return (elem.textContent || elem.innerText || "").toLowerCase().indexOf(match[3].toLowerCase()) >= 0;
	}
});

/*
	Enables users to collapse and expand answers to questions and search through results.
*/
var QuestionAndAnswer = {
	initialize: function() {
		if($('.question-and-answer').length > 0){
			var preloadMinus = new Image();
			preloadMinus.src = '/images/bullets/minus-bullet.gif';
		}	
		// Make all links open in a new window
		$('.question-and-answer a:not([href=#])').attr('target', '_blank');
		
		// hide all the answers by default
		$('.question-and-answer dl dd, .question-and-answer .qa-category dl').hide();
		
		// Setup the category title to toggle display of questions
		// Setup the question text to toggle the answer
		$('.question-and-answer dl dt a, .question-and-answer .qa-category > h3 > a').each(function(){
			// Add a class we can use to track this anchor
			$(this).attr('class', $.generateId());
			$(this).data('clicked', false);
		}).click(function(){
			var a = $(this);
			// If they're clicking a cloned question in search results, we need to find the original
			if (a.parents('.qa-category').is('#qa-category-search'))
				a = $('.qa-category:not(#qa-category-search) a.' + a.attr('class'));
			
			// Only work when clicking questions, not categories, and only if this link isn't expanded and hasn't been clicked
			if (a.length > 0 && a.parent().is('dt') && !a.is('.active') && !a.data('clicked')) {
				a.data('clicked', true);
				try {
					if (typeof pageTracker != 'undefined') {
						// Strip out everything that isn't a-z, A-Z, 0-9, spaces, period, parenthesis, or hyphens
						var category = $('> h3 > a', a.parents('.qa-category')).text().replace(/[^a-zA-Z0-9 .()-]/gi, '');
						var question = a.text().replace(/[^a-zA-Z0-9 .()-]/gi, '');
						// The regex on the URL makes sure there is no trailing forward slash
						var url = $.url.attr('path').replace(/\/$/i, '') + '/faqclicks/' + category + '/' + question;
						pageTracker._trackPageview(url);
					}
				}
				catch (e) {}
			}
			
			$(this).toggleClass('active').parent().next('dd, dl').slideToggle();
			return false;
		});
		
		// We create the label and select instead of having it in the HTML because otherwise IE6 has issues with the select
		$('<label for="qa-filter">Filter:</label><select id="qa-filter"><option value="qa-all">All Categories</option><option value="qa-search-results">Search Results</option></select>')
			.appendTo('.question-and-answer form .row .column-2:first');
			
		// Loop through each category and add it as an option to the select
		$('.question-and-answer > div:not(:last) > h3').each(function(i){
			$('<option value="' + i + '">' + $(this).text() + '</option>').insertBefore('#qa-filter option:last');
		});
		
		// Remove the old custom selectbox styling and recreate it, since we added some options above
		$('#qa-filter_input, #qa-filter_container').remove();
		$('#qa-filter').selectbox({selectedClass:'select-selected'});
		
		// Clicking on one of the options in the drop down searches for the corresponding category and displays it
		// Also, click the first category by default
		$('#qa-filter_container ul li').click(function(){
			$('.question-and-answer .qa-category').hide();
			if ($(this).prev().length == 0) {
				$('.question-and-answer .qa-category:not(:last)').show();
				$('.question-and-answer > div > dl').hide();
				$('.question-and-answer > div > h3 > a').removeClass('active');
			}
			else {
				$('.question-and-answer .qa-category')
					.filter(':eq(' + ($(this).prevAll().length - 1) + ')').show()
					.children('dl').show().end().children('h3').children('a').addClass('active');
			}
		}).filter(':first').trigger('click', [true]);
		
		// Clicking the collapse all link hides all answers
		$('a.qa-collapse-all').click(function(){
			try {
				if (typeof pageTracker != 'undefined') {
					// The regex on the URL makes sure there is no trailing forward slash
					var url = $.url.attr('path').replace(/\/$/i, '') + '/faqclicks/collapse-all';
					pageTracker._trackPageview(url);
				}
			}
			catch (e) {}
				
			// If viewing all categories, then collapse the categories too
			if ($('#qa-filter_input_qa-all').is('.select-selected')) {
				$('.question-and-answer > .qa-category > h3 > a').removeClass('active');
				$('.question-and-answer > .qa-category > dl').slideUp();
			}
			$('.question-and-answer dl dt a').removeClass('active');
			$('.question-and-answer > div:hidden dd').hide();
			$('.question-and-answer > div:visible dl dd').slideUp();
			return false;
		});
		
		// Clicking the expand all link shows all answers
		$('a.qa-expand-all').click(function(){
			try {
				if (typeof pageTracker != 'undefined') {
					// The regex on the URL makes sure there is no trailing forward slash
					var url = $.url.attr('path').replace(/\/$/i, '') + '/faqclicks/expand-all';
					pageTracker._trackPageview(url);
				}
			}
			catch (e) {}
			
			// If viewing all categories, then expand the categories too
			if ($('#qa-filter_input_qa-all').is('.select-selected')) {
				$('.question-and-answer > .qa-category > h3 > a').addClass('active');
				$('.question-and-answer > .qa-category > dl').slideDown();
			}
			$('.question-and-answer dl dt a').addClass('active');
			$('.question-and-answer > div:hidden dd').show();
			$('.question-and-answer > div:visible dl dd').slideDown();
			return false;
		});
		
		// When the search form is submitted...
		$('.question-and-answer > form').submit(function(){
			// This first set of code is responsible for breaking apart the text entered by the user and
			// create an array of terms to use when searching. 
			var searchTerms = [];

			var enteredTerms = $('#field-id-search').val();
			if (enteredTerms.length > 0) {			
				// First try to find all of the double quoted text and add those to the terms so we perserve the word order
				var matchQuoted = enteredTerms.match(/"[^"]+"/g);
				if (matchQuoted != null)
				{	// Remove double quotes from the double quoted terms
					matchQuoted = $.map(matchQuoted, function(n, i){ return n.replace(/"/g, ''); });
					searchTerms = searchTerms.concat(matchQuoted);
					// Remove the double quoted text from the search string
					enteredTerms = enteredTerms.replace(/"[^"]+"/g, ' ');
				}
				
				enteredTerms = $.trim(enteredTerms);
				
				// Next just split on whitespace to find the individual words
				if (enteredTerms.length > 0 && !enteredTerms.match(/^\s+$/))
					searchTerms = searchTerms.concat(enteredTerms.split(/\s+/));
			}
			
			// Loop through each search term and find questions/answers that contain the term
			var searchResults = $([]);
			var i = 0;
			for (i in searchTerms) {
				// Check through each question and then check the question text and its corresponding answer text against the search term
				var searchResult = $('.question-and-answer div:not(#qa-category-search) dl dt').filter(function(){
					// This filter is the core of the search. Because the selector grabs all the DTs (the question text) we also do
					// a .add with .next() to grab the DD, which is the corresponding question answer.
					// Next it runs a filter using a case insensitive version of :contains with the search term as the argument.
					// Finally we turn all of this into a boolean check against the length of the element set. If there is any length,
					// then the :contains check found some elements, and so we know the current question we're checking is valid.
					return ($(this).add($(this).next()).filter(':contains-nc("' + searchTerms[i] + '")').length > 0);
				});
				
				// If we have a search result, add it to the search results set
				if (searchResult.length > 0) 
					searchResults = searchResults.add(searchResult);
			}
			
			// If we have some search results we need to display them...
			if (searchResults.length > 0) {
				// Update the paragraph text showing the number of results
				$('#qa-category-search > p').text('Your search returned ' + searchResults.length + ' result' +
					(searchResults.length > 1 ? 's' : '') + ':');
				// If there is an old definition list, remove it, then create a new one
				$('#qa-category-search > dl').remove();
				var definitionList = $('<dl></dl>');
				
				// Go through each question we found and clone it and the corresponding answer to the DL
				searchResults.each(function(){
					$(this).clone(true).appendTo(definitionList);
					$(this).next().clone(true).appendTo(definitionList);
				});
				
				// Add the DL to the search results DIV
				definitionList.appendTo('#qa-category-search');
			}
			// If we have no search results, first remove any lingering definition list and then show the
			// no search results paragraph text.
			else {
				$('#qa-category-search > dl').remove();
				$('#qa-category-search > p').text('Your search did not return any results.').show();
			}
			
			// Automatically move the filter dropdown to the search results filter
			$('#qa-filter_input_qa-search-results').click();
			
			return false;
		});
	}
};

jQuery.validator.addMethod("maxEmails", function(value, element, params) {
    return this.optional(element) || value.split(/\r?\n/g).length <= params; 
}, "Too many addresses."); 

jQuery.validator.addMethod("multiEmail", function(value, element, params) {
	var valid = false;
	var context = this;
	$.each(value.split(/\r?\n/g), function(){
		return (valid = $.validator.methods['email'].call(context, this.toString(), element, true ));
	});
    return this.optional(element) || valid; 
}, "Invalid address.");

var EmailModal = {
	initialize: function() {
		$('#action-navigation .email a').click(function(){
			// Remove the old hidden modal if it exists
			$('.ui-dialog').remove();
	
			// Format the form as a modal
			var dialogHTML = $(EmailModal.HTML).dialog({
				modal: true,
				width: 480,
				height: 525,
				title: 'Email this Page from GFS.com',
				draggable: false,
				resizable: false,
				//show: 'clip',
				overlay: {
					background: '#000',
					opacity: 0.4
				},
				buttons: {
					'Send': function(){
						if ($('#email-modal form').valid()) {
							$('#to').val($('#to').val().replace(/\r/g, '').replace(/\n/g, ','));
							var formData = $('#email-modal form').serialize();

							$('#email-modal form').remove();
							$('#email-modal').text('Sending your e-mail... Please wait.');

							var url = ($.url.attr('source').indexOf('iw-preview') != -1) ? '/iw-preview/emailModal' : '//emailModal';
							url = $.url.attr('protocol') + "://" + $.url.attr('host') + ($.url.attr('port') == null ? '' : (':' + $.url.attr('port'))) + url;
							
							$.ajax({
                                url: url,
								type: 'GET',
								dataType: 'xml',
								data: formData,
								success: function(data, textStatus){
									var returnedData = $('ServiceResponse', data).text();
									$('#email-modal').text(returnedData);
									
									// Track that the e-mail was sent.
									try {
										if (typeof pageTracker != 'undefined') {
											pageTracker._trackPageview('/email-modal/sent' + location.pathname);
										}
									}
									catch (e) {}
					
									setTimeout(function(){
										$('#email-modal').dialog('destroy').remove();
									}, 3000);
								},
								error: function(XHR, textStatus, errorThrown){
									$('#email-modal').text('Sorry, but your email could not be sent.');

									setTimeout(function(){
										$('#email-modal').dialog('destroy').remove();
									}, 3000);
								}
							});
						}
					},
					'Cancel': function(){
						$('#email-modal').dialog('destroy').remove();
					}
				},
				open: function(){
					// When clicking the overlay, close the dialog
					$('.ui-widget-overlay').click(function(){
						$('#email-modal').dialog('destroy').remove();
					});
					
					$('#url').val($.url.attr('source'));
					
					try {
						if (typeof pageTracker != 'undefined') {
							pageTracker._trackPageview('/email-modal/opened' + location.pathname);
						}
					}
					catch (e) {}
									
					$('#email-modal .page-title').text($('#main-content h1:first').text());
					$('#subject').val('I just read this on GFS.com: ' + $('#main-content h1:first').text());
					$('#message').keyup(function(){
						$(this).parent().next('.character-counter').children('.remaining-characters').text(
							Math.max(0, 500 - $(this).val().length)
						);
					});
				}
			});
			
			$('form', dialogHTML).validate({
				rules: {
					subject: 'required',
					message: {
						maxlength: 500
					},
					email: {
						required: true,
						email: true
					},
					to: {
						//required: true,
						maxEmails: 5,
						multiEmail: true
					}
				}, 
				messages: {
					name: 'Required.',
					subject: 'Required.',
					message: {
						required: 'Required.',
						maxlength: 'Cannot exceed 500 characters.'
					},
					email: {
						required: 'Required.',
						email: 'Invalid format.'
					},
					to: {
						//required: 'Required.',
						email: 'Invalid format.'
					}
				},
				errorPlacement: function(error, element) {
					error.prependTo( element.parent() );
				}
			});
			
			// Style the inputs on the modal HTML
			$('input[type="radio"]', dialogHTML).checkbox({cls:'custom-radio', empty: '/images/blank.png'});
			$('input[type="checkbox"]', dialogHTML).checkbox({cls:'custom-checkbox', empty: '/images/blank.png'});
			
			return false;
		});
	},
	
	HTML: '<div id="email-modal"><h2 class="page-title">&nbsp;</h2><div>Enter one e-mail address per line. For example:<br />person1@example.com<br />person2@example.com</div><form id="email-form"><fieldset><input type="hidden" name="url" id="url" value="" /><div class="row"><div class="column-2"><p><label for="name" class="text">Your name:</label><input type="text" class="text" name="name" id="name" value="" /></p><p><label for="email" class="text">Your e-mail:</label><input type="text" class="text" name="email" id="email" value="" /></p></div><div class="column-2"><p><label class="textarea" for="to">To (5 max):</label><textarea class="textarea" name="to" id="to" rows="2" cols="6"></textarea></p></div></div><div class="row"><div class="column-4"><p><label for="subject" class="text">Subject:</label><input type="text" class="text" name="subject" id="subject" value="" /></p><p class="checkbox"><input type="checkbox" name="sendcopy" id="sendcopy" value="1" /><label for="sendcopy">Send me a copy</label></p><p><label class="textarea" for="message">Message:</label><textarea class="textarea" name="message" id="message" rows="10" cols="16"></textarea><div class="character-counter">You have <span class="remaining-characters">500</span> character(s) remaining.</div></p></div></div></fieldset></form></div>'
};

var PageModal = {
	initialize: function() {
		$('a.modalize').click(function(){
			// Remove the old hidden modal if it exists
			$('#page-modal, .ui-dialog').remove();
			
			$('<div id="page-modal"><strong>Loading...</strong></div>').appendTo('body')
				.dialog($.extend({
						title: $(this).attr('title')
				}, PageModal.modalDefaults))
				.data('title', $(this).attr('title'))
				.load($(this).attr('href') + ' #main-content', null, function(){
					// track that this modal loaded in GA
					try {
						if (typeof pageTracker != 'undefined') {
							pageTracker._trackPageview($(this).attr('href'));
						}
					}
					catch (e) {}
				
					// If no title is set on the anchor and there is an h1 tag, use it as the title
					if ($(this).data('title').length == 0 && $('#main-content h1:first', this)) {
						$(this).data('title', $('#main-content h1:first', this).text());
					}
					
					// Remove the h1 tag
					$('#main-content h1:first', this).remove();
					
					// We don't want two main-content ids
					$('#main-content', this).removeAttr('id').addClass('ui-dialog-inner');
					$('#breadcrumb-navigation, #action-navigation', this).removeAttr('id').remove();
					
					FlashVideo.initialize(this);
				});
			// Prevent the link from being followed
			return false;
		});
	},
	
	modalDefaults: {
		modal: true,
		draggable: false,
		resizable: false,
		width: 480,
		height: 500,
		overlay: {
			background: '#000',
			opacity: 0.4
		},
		buttons: {
			'Close': function(){
				$(this).dialog('destroy').remove();
			}
		},
		open: function(){
			// When clicking the overlay, close the dialog
			$('.ui-widget-overlay').click(function(){
				$('#page-modal').dialog('destroy').remove();
			});
		}
	}
};

var SiteSearch = {
	initialize: function(){
		// Prevents an element from having its default value as its submitted value.
		$.validator.addMethod('notdefault', function(value, element) {
			return this.optional(element) || element.defaultValue != value;
		}, 'Cannot be default.');
		
		// Setup form validation
		var validator = $('#site-search').validate({
			rules: {
				QueryTerm: {
					'required': true,
					'notdefault': true
				}
			},
			messages: {
				QueryTerm: 'Enter keywords, then click Go.'
			},
			errorPlacement: function(error, element){
				element.parent().find('h2:first').after(error);
			},
			errorClass: 'error',
			errorElement: 'h2',
			highlight: function(element, errorClass) {
				$(element).addClass(errorClass);
				$(element.form).find('h2:first').hide();
			},
			unhighlight: function(element, errorClass) {
				$(element).removeClass(errorClass);
				$(element.form).find('h2:first').show();
			}
		});

		$('#site-search input:text').blur(function(){
			$('#site-search h2:first').show();
			validator.resetForm();
		});
	}
};

var FlashVideo = {
	initialize: function(element){
    element = element || document;
    
		// Find all anchor tags that link to .flv files
		$('a[href*=.flv], a[href*=.mp4]', element).each(function(){
			var originalURL = $.url.attr('source');
			
			// Parse out the URL, which has the file location and flashvars
			var flvURL = $.url.setUrl($(this).attr('href'));
			
			// Skip turning this anchor into a player if the "ignore" query string parameter is defined
			if (flvURL.param('ignore') != null) return;
			
			// Default flashvars
			// Note that we remove the query string from the URL
			var flashvars = {
				file: $(this).attr('href').replace('?' + flvURL.attr('query'), ''),
				plugins: 'googlytics-1'
			};
			
			// Combine query string settings from the anchor URL into the flashvars
			$.extend(true, flashvars, flvURL.param());
			
			// If width and height aren't set, then provide some defaults
			if (typeof flashvars.width == 'undefined') flashvars.width = 480;
			if (typeof flashvars.height == 'undefined') flashvars.height = 380;
			
			var attributes = {
				allowscriptaccess: 'always',
				allowfullscreen: 'true'
			};
			
			// Generate an ID for this anchor if it doesn't have one
			if ($(this).parent().attr('id') == '') $(this).generateId();
			
			// Replace the anchor with the flash video player
			$(this).parent().flashembed({
				src: '/flash/player.swf',
				allowscriptaccess: 'always',
				allowfullscreen: 'true',
				width: flashvars.width,
				height: flashvars.height,
				wmode: 'transparent'
			}, flashvars);
			
			$.url.setUrl(originalURL);
			
			/*swfobject.embedSWF('/flash/player.swf', $(this).attr('id'), flashvars.width, flashvars.height,
				'9.0.0', '', flashvars, null, attributes);*/
		});
	}
};

var SWFEmbed = {
	initialize: function(){
		// Find all anchor tags that link to .flv files
		$('a[href*=.swf]').each(function(){
			var originalURL = $.url.attr('source');
			
			// Parse out the URL, which has the file location and flashvars
			var flvURL = $.url.setUrl($(this).attr('href'));
			
			// Skip turning this anchor into a player if the "ignore" query string parameter is defined
			if (flvURL.param('ignore') != null) return;
			
			// Default flashvars
			var flashvars = {};
			
			// Combine query string settings from the anchor URL into the flashvars
			$.extend(true, flashvars, flvURL.param());
			
			// If width and height aren't set, then provide some defaults
			if (typeof flashvars.width == 'undefined') flashvars.width = '100%';
			if (typeof flashvars.height == 'undefined') flashvars.height = 200;
			
			var attributes = {
				allowscriptaccess: 'always',
				allowfullscreen: 'true'
			};
			
			// Generate an ID for this anchor if it doesn't have one
			if ($(this).parent().attr('id') == '') $(this).generateId();
			
			// Replace the anchor with the flash video player
			$(this).parent().flashembed({
				src: $(this).attr('href'),
				allowscriptaccess: 'always',
				allowfullscreen: 'true',
				width: flashvars.width,
				height: flashvars.height,
				wmode: 'transparent'
			}, flashvars);
			
			$.url.setUrl(originalURL);
			
			/*swfobject.embedSWF('/flash/player.swf', $(this).attr('id'), flashvars.width, flashvars.height,
				'9.0.0', '', flashvars, null, attributes);*/
		});
	}
};

var CollapsibleLists = {
	initialize: function(){
		$('a.collapsible').click(function(){
			if ($(this).next('ul, div').length > 0)
				$(this).toggleClass('active').next('ul, div').slideToggle();
			else
				$(this).toggleClass('active').parent().next('ul, div').slideToggle();
		
			return false;
		}).each(function(){
			if ($(this).next('ul, div').length > 0)
				$(this).next('ul, div').hide();
			else
				$(this).parent().next('ul, div').hide();
		});
	}
};

var ImageTips = {
	initialize: function(){
		$('img.imagetip').each(function(){
			ImageTips.addtip($(this));
		});
	},
	addtip: function($image){
		$image.removeClass('imagetip');
		var id = $.generateId();
		var title = $image.attr('title');
		
		if (title) {
			$image.removeAttr('title');
			
			var $tip = $('<div/>').attr({
				id: id,
				'class': 'imagetip'
			}).css({
				width: $image.width(),
				height: $image.height()
			}).hide().appendTo($image.parent());

			$tip.css($image.parents('div[class*=drop-shadow]:first').length ? $image.position() : $image.offset());
				
			$('<div/>').addClass('inner').html(title).appendTo($tip);
			
			$tip.mouseleave(function(){ $(this).hide(); });
			$image.mouseenter(function(){ $tip.show(); });
		}
	}
}