﻿/*
 INCLUDES
 **********************************************/
// specify which javascripts to include on the webpage
//js('/files/javascript/SCRIPTNAME.js');
js('/files/javascript/jquery.colorbox-min.js');
js('/files/javascript/jquery.autocomplete.min.js');
js('/files/javascript/jquery.cycle.all.min.js');
js('/files/javascript/jquery.ba-bbq.min.js');
//js('/files/javascript/development.js');
js('/files/javascript/jquery.simplyscroll-1.0.4.min.js');
//js('/files/javascript/jquery.jcarousel.min.js');



// Variant system
// --------------------------------
// beskrivelse
// version: 1.0 - 2011-02-02
(function($){
// TODO:
//		Lav dokumentation til hvordan plugin'et bliver brugt

	/**
	 * Activate the variantsystem on productinfo pages
	 * @param {Object} options contains an optional settings object that can override or add functionality found in the default object
	 */
	$.fn.variantSystem = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.variantSystem.defaults, options);
		
		// activate the script for each instance found in the selector
		return this.each(function(){
			var $this = $(this);
			
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// We need the variantDataObject to continue - if this does not exist, we cannot continue
			if (o.variantDataObject != null){

				// start by clearing the productid inputfield, as it now needs to be a variant
				$this.closest('form').find('input[name="' + o.productidName + '"]').val('');
					
				// run a anonymous change function on every selectbox used for the variantsystem
				$this.find('select').change(function(){
					
					// run optional onBeforeChange callback function
					if (o.onBeforeChange) {
						o.onBeforeChange($this, $(this), o);
					}

					// everytime a selectbox is changed, we need to clear the productid in the form
					$this.closest('form').find('input[name="' + o.productidName + '"]').val('');
					
					// continue if an option with a value have been selected
					if ($(this).val() != '') {
			  		var objVariantcollection = $(this).find('option').eq(this.selectedIndex).data(o.optionDataObjectName)[0];
			  	
				  	// find out if we are on the last selectbox
						if (typeof(objVariantcollection) != 'undefined') {
							// there is a variantcollection and another selectbox after this one
							
							var intNextBoxIndex = $this.find('select').index(this) + 1;
							
							// fill out the next variant selectbox
							fillVariantBox(o, $this, intNextBoxIndex, objVariantcollection);
						}
						else {
							// this is the final selectbox in the variant selection and we need to get the productid
							
							// get the productid
							var strProductid = $(this).val();
							
							// insert the prooductid in the correct inputfield in the form
							$this.closest('form').find('input[name="' + o.productidName + '"]').val(strProductid);
						}
						
						// if the updateBaseLayout is allowed to run, run it
						if (!o.disableUpdateBaseLayout){
							updateBaseLayout($this, $(this), o);
						}
						
						// run optional onUpdateLayout function to update the layout of the page (images, text, links etc.)
						if (o.updateLayout) {
							o.updateLayout($this, $(this), o);
						}
						
					}
					
					// run optional onBeforeChange callback function
					if (o.onAfterChange) {
						o.onAfterChange($this, $(this), o);
					}
					
				});
				
				// fill out the first variantbox
				fillVariantBox(o, $this);
				
				// run optional onBeforeChange callback function
				if (o.onCreate) {
					o.onCreate($this, o);
				}
			} else {
				log_debug('ERROR in jQuery variantSystem plugin: the option "variantDataObject" is not set in the template - it is needed to activate the variantSystem plugin');
			}
		});
	}
	
	
	
	/**
	 * Fill variant box with data from the objVariantCollection, if it is supplied
	 * @param {Object} o	The options object for the plugin
	 * @param {jQueryObject} $productVariantContainer	The jQuery object for the containing element
	 * @param {number} intIndex	Index of the affected selectbox. Optional (if not specified, first selectbox will be chosen)
	 * @param {Object} objVariantCollection	The variantcollection object from the previously chosen option. Optional (if not specified, it will get the first variantcollection from objVariants)
	 */
	function fillVariantBox(o, $productVariantContainer, intIndex, objVariantcollection){
		var $variantBox, arrVariantValues;
		var intBoxIndex = 0;
		
		// if intIndex exists, use its value in intBoxIndex
		if (typeof(intIndex) != 'undefined') {
			intBoxIndex = intIndex;
		}
		
		// get the selectbox to insert new data into
		$variantBox = $productVariantContainer.find('select').eq(intBoxIndex);
		
		if ($variantBox.size() == 0){
			return false;
		}
		
		// set the array of values to insert into the selectbox
		if (typeof(objVariantcollection) != 'undefined'){
			// if the objVariantcollection parameter have been passed to us, use it
			
			arrVariantValues = objVariantcollection.values;
		} else {
			// otherwise use the first variantcollection in the data object
			
			arrVariantValues = o.variantDataObject.variantcollection[0].values;
		}
		
		// retrieve the first option (choose [varianttype])
		var $firstOption = $variantBox.find('option').eq(0);
		
		// empty the current options and append the previous first option (choose [varianttype])
		$variantBox.empty().append($firstOption);
		
		for(var i = 0, arrLength = arrVariantValues.length; i<arrLength;i++){
			// append new variant options and insert the variantcollection as a data object on the option
			
			// find the variant object for the current productid, so it can be stored as well
			var variantObject;
			for(var j=0, objVarsLength = o.variantDataObject.variants.length; j<objVarsLength; j++){
				if (o.variantDataObject.variants[j].productid == arrVariantValues[i].productid){
					variantObject = o.variantDataObject.variants[j];
					break;
				}
			}
			
			// setup and append the option to the selectbox along with some dataobjects
			$variantBox.append($('<option/>',{
				text: arrVariantValues[i].value,
				value: arrVariantValues[i].productid
			}).data(o.optionDataObjectName,arrVariantValues[i].variantcollection).data(o.optionVariantObjectName,variantObject));
		}
	}
	
	
	
	/**
	 * Update the base layout of the page with the new information, based on the given productid of the selectbox
	 * @param {jQueryObject} $productVariantContainer	The jQuery object for the containing element
	 * @param {jQueryObject} $box	The jQuery object for the selectbox which have been changed
	 * @param {Object} $box	The options object for the plugin
	 */
	function updateBaseLayout($productVariantContainer, $box, o){
		
		/*
		//TODO: make context work properly, so the updateBaseLayout function also is able to handle productlists
		
		var $productContext = $productVariantContainer.closest(o.outerLimitProduct);
		var $productListItemContext = $productVariantContainer.closest(o.outerLimitProductListItem);
		
		// if there is no context, we cannot figure out where to limit ourselves to and therefore we must stop here
		if ($productContext.size() == 0 && $productListItemContext.size() == 0){
			return false;
		}
		*/

		var objVariant = $box.find('option').eq($box.get(0).selectedIndex).data(o.optionVariantObjectName);
		
		// if there is no objVariant, then cancel the entire function
		if (typeof(objVariant) == 'undefined') {
			return false;
		}
		
		// define all the used variables here, that will come from the objVariant object
		var strProductid = '';
		var strNewImage = '';
		var strNetPrice = '';
		var strNetPrice2 = '';
		var intInstock;
		
		// define all references to jQuery objects here
		var $basicProperties = $('#productBasicProperties');
		var $productidInfo = $basicProperties.find('.productidInfo strong');
		var $netprice = $('#jsProductnetprice');
		var $netprice2 = $('#jsProductnetprice2');
		
		// set all the variables here from the object
		
		if (typeof(objVariant.productid) != 'undefined') {
			strProductid = objVariant.productid;
		}
		if (typeof(objVariant.imagefilename) != 'undefined') {
			strNewImage = objVariant.imagefilename;
		}
		if (typeof(objVariant.netprice) != 'undefined') {
			strNetPrice = objVariant.netprice;
		}
		if (typeof(objVariant.netprice2) != 'undefined') {
			strNetPrice2 = objVariant.netprice2;
		}
		
		if (typeof(objVariant.instock) != 'undefined') {
			intInstock = objVariant.instock;
		}
		
		
		
		// #########################################################################
		// the following data will be changed no matter which selectbox is changed #
		// #########################################################################
		
		// change productimage based on variants, if there is an image specified and there is an actual productimage on the page
		if ($('#productImages').size() > 0){
			
			var objFirstimage = $('#productImages').find('img:first');
			var objFirstimageLink = objFirstimage.parent('a');
			if (objFirstimage.size() > 0 && strNewImage != '' && strNewImage != 'undefined'){
	
				var intIndexOfSlash = objFirstimage.attr('src').lastIndexOf('/')+1;
				objFirstimage.attr('src',objFirstimage.attr('src').substring(0,intIndexOfSlash) + strNewImage);
				
				if (objFirstimageLink.size() > 0) {
					var intIndexOfSlash2 = objFirstimageLink.attr('href').lastIndexOf('/')+1;
					objFirstimageLink.attr('href',objFirstimageLink.attr('href').substring(0,intIndexOfSlash2) + strNewImage);
				}
			}
			
			// if we have a lightbox container that should be updated, execute this function, if it exists
			if (typeof updateProductImagesLightbox == 'function'){
				updateProductImagesLightbox();
			}
		}
		
		// change netprice of the product, if it exists on the page and there is something in the variable (not 0,00 and 0.00)
		if ($('#jsProductnetprice').size() > 0 && strNetPrice != '' && strNetPrice != '0,00' && strNetPrice != '0.00'){
			$('#jsProductnetprice').text(strNetPrice);
		}
		
		// change netprice2 of the product, if it exists on the page and there is something in the variable (not 0,00 and 0.00)
		if ($('#jsProductnetprice2').size() > 0 && strNetPrice2 != '' && strNetPrice2 != '0,00' && strNetPrice2 != '0.00'){
			$('#jsProductnetprice2').text(strNetPrice2);
		}
		
		
		
		// #########################################################################################################
		// test if we are at the last selectbox and either reset to defaults or do what the last selectbox defines #
		// #########################################################################################################
		
		if ($productVariantContainer.find('select').index($box) == $productVariantContainer.find('select').size()-1){
			// only do the following if we are at the last selectbox
			
			// change instock status to represent the chosen variant
			if (!isNaN(intInstock) && $basicProperties.size() > 0){
				if (intInstock < 1){
					$basicProperties.find('.instock').hide();
					$basicProperties.find('.notinstock').show();
				} else {
					$basicProperties.find('.instock').show();
					$basicProperties.find('.notinstock').hide();
				}
			}
			
			if (strProductid != '' && $productidInfo.size() > 0){
				$productidInfo.text(strProductid);
			}
			
			
			
		} else {
			// if we are not at the last selectbox, reset some of the page content to the default
			
			// show that the product is in stock since we don't have a variant to measure on yet
			$('#productBasicProperties').find('.instock').show();
			$('#productBasicProperties').find('.notinstock').hide();
			
			// reset the productid information
			if ($productidInfo.size() > 0){
				$productidInfo.text($productidInfo.closest('#productPage').find('form input[name="original_productid"]').val());
			}
			
		}
		
	}
	
	// default values for the options
	$.fn.variantSystem.defaults = {
		productidName: 'productid',
		variantDataObject: null,
		optionDataObjectName: 'variantcollection',
		optionVariantObjectName: 'variant',
		onCreate: null,
		onBeforeChange: null,
		onAfterChange: null,
		updateLayout: null,
		disableUpdateBaseLayout: false,
		outerLimitProduct: '#tProductinfo',
		outerLimitProductListItem: '.productlistVerbose li'
	};
})(jQuery);



// groupsmenu ajax funktionality
// version: 1.0 - 2010-05-12
(function($){

	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.groupsmenuAjax = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.groupsmenuAjax.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
		
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $(this).metadata()) : opts;
			
			// add the correct classes based on which submenus are open and closed when the plugin is called
			$(this).find('ul.' + o.closedClass).prev().addClass(o.closedClass);
			$(this).find('ul.' + o.openClass).prev().addClass(o.openClass);
			
			// dynamisk aktivering af klik på elementerne
			$(this).find('.' + o.hasSubmenuClass + ' > a').live('click', function(e){
			
				var $this = $(this);
				
				if ($this.next().size() > 0) {
					// there is already a submenu, so lets just work with that
					
					if ($this.hasClass('closed')) {
						// when the item is closed, open it and close all the other open menus
						$this.removeClass(o.closedClass).addClass(o.openClass).next().slideDown('fast').parent().siblings().find('ul').slideUp().prev().removeClass(o.openClass).addClass(o.closedClass);
					}
					else {
						// when the item is open, close it
						$this.removeClass(o.openClass).addClass(o.closedClass).next().slideUp('fast');
					}
				}
				else {
					// there is not a submenu yet, so fetch the correct submenu with Ajax
					
					// give feedback to the user, that we are working on getting the submenu
					$('<img class="preloader" src="' + o.preloaderImage + '" alt=""/>').insertAfter($this).fadeIn('fast');
					
					// fetch the submenu
					$.ajax({
						url: '/dynamic.aspx?data=groups&template=groupsmenu_ajax&ajaxmode=1',
						data: {
							key: $this.metadata().menuid
						},
						success: function(data){
							// add a "open" class to the link, remove the preloader image and insert the new list of menuitems after the link
							
							$this.addClass(o.openClass).next('img').fadeOut('fast', function(){
								$(this).remove();
							}).end().after(data).next().slideDown('fast');
						}
					});
				}
				
				// remove focus from the clicked link and cancel the normal click event
				$this.blur();
				e.preventDefault();
				//return false;
				
			});
		});
	}
	
	// default values for the options
	$.fn.groupsmenuAjax.defaults = {
		hasSubmenuClass: 'hasSubmenu',
		openClass: 'open',
		closedClass: 'closed',
		preloaderImage: '/images/preload_16x16.gif'
	};
	
})(jQuery);



// horizontal main menu - suckerfish style drop down
// version: 1.0 - 2010-05-14
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.menuFades = function(options){
	
		// activate the script for each instans found in the selector
		return this.each(function(){
		
			$(this).find('li').hoverIntent(function(){
				// on mouseover
				$('ul:first', this).fadeIn('fast');
			}, function(){
				// on mouseout
				$('ul:first', this).fadeOut('fast');
			});
			
		});
	}
	
})(jQuery);



// add and subtract quantity fields.
// version: 1.1 - 2010-07-22
(function($){

	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.quantityAddSubtract = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.quantityAddSubtract.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			if ($this.hasClass('quantityButtonsAttached') == false){
				
				$this.addClass('quantityButtonsAttached');
				
				// insert a - (subtract) button
				$('<img/>', {
					'class': o.subtractClass,
					'src': o.subtractImage,
					'alt': '',
					click: function(){
						var floatValue = round_float($this.val(), 2);
						var floatNewVal = floatValue - o.step;
						var floatMinVal = round_float($this.closest('form').find('input[name="min_quantity"]').val(), 2);
						
						if (floatNewVal < floatMinVal) {
							$this.val(floatMinVal);
						}
						else if (floatNewVal < o.step) {
							$this.val(o.step);
						}
						else {
							$this.val(floatNewVal);
						}
					}
				}).insertBefore($this);
				
				// insert a + (add) button
				$('<img/>', {
					'class': o.addClass,
					'src': o.addImage,
					'alt': '',
					click: function(){
						var floatValue = round_float($this.val(), 2);
						var floatNewVal = floatValue + o.step;
						$this.val(floatNewVal);
					}
				}).insertAfter($this);
				
				// when the user removes the focus from the field, check the content
				$this.blur(function(){
					var qtycolli = parseFloat(o.step);
					var quantity = parseFloat($this.val().toString().replace(',', '.'));
					
					// check if colliMessage is defined. If it is, give the user this message, else give the standard danish message 
					var messageText = (typeof colliMessage != 'undefined') ? colliMessage : 'Antallet passer ikke med en hel pakning og er blevet justeret.';
					
					if (isNaN(quantity)) {
						$this.val('');
					}
					else {
						$this.val(quantity);
					}
					
					// show a message to the user
					if (qtycolli > 1 && quantity > 0 && round_float(quantity % qtycolli, 2) > 0) {
						$this.val(round_float(Math.ceil(quantity / qtycolli) * qtycolli, 2));
						$this.after('<div class="' + o.messageClass + '"><div>' + messageText + '</div></div>');
						$this.parent().find('.' + o.messageClass).fadeIn('slow', function(){
							window.setTimeout("$('." + o.messageClass + "').fadeOut('slow',function(){ $(this).remove(); })", 5000);
						});
					}
				});
			
			}
		});
	}
	
	// default values for the options
	$.fn.quantityAddSubtract.defaults = {
		addClass: 'jsQuantityAdd',
		addImage: '/images/btn_plus.gif',
		subtractClass: 'jsQuantitySubtract',
		subtractImage: '/images/btn_minus.gif',
		step: 1,
		messageClass: 'jsMessage'
	};
	
})(jQuery);



// jQuery plugin to replace the text in input fields on focus/blur or replace entire password field
// version: 1.0 - 2010-05-14 
(function($){
	$.fn.toggleInputText = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.toggleInputText.defaults, options);
		
		return ($(this).each(function(){
			var $this = $(this);
			title = $this.attr('title');
			
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			if ($this.attr('type') == 'password') {
				// password field specific replacement
				
				var fakePassword = $('<input/>', {
					'class': $this.attr('class') + ' fakePassword',
					'value': $this.attr('title'),
					'type': 'text',
					css: {
						display: 'none'
					},
					focus: function(){
						$(this).hide();
						$this.show().focus();
					}
				});
				
				$this.after(fakePassword).blur(function(){
					if ($this.val() == "") {
						$this.hide().next('.fakePassword').show();
					};
									});
				
				if ($this.val() == "") {
					$this.hide().next('.fakePassword').show();
				};
							}
			else {
				// toggle values
				if ($this.val() == "") {
					$this.val(title);
				};
				$this.focus(function(){
					if ($this.val() == $this.attr('title')) {
						$this.val("");
					};
									}).blur(function(){
					if ($this.val() == "") {
						$this.val($this.attr('title'));
					};
									});
			}
			
			// hide the labels if the option is set to true
			if (o.hideLabels && $this.attr('id') != '') {
				$this.closest('form').find('label[for="' + $this.attr('id') + '"]').hide();
			}
			
		}));
	};
	
	// default values for the options
	$.fn.toggleInputText.defaults = {
		hideLabels: true
	};
	
})(jQuery);



// show the item specified in the href and hide what is specified in the options 
// version: 1.0 - 2010-05-12
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.setActiveBox = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.setActiveBox.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			$this.click(function(){
				// show the specified element
				$($this.attr('href')).show();
				
				// if hideSelector is set, hide the elements in the selector
				if (o.hideSelector != null) {
					$(o.hideSelector).hide();
				}

				// stop the click on the link
				return false;
			})
		});
	}
	
	// default values for the options
	$.fn.setActiveBox.defaults = {
		hideSelector: null
	};
	
})(jQuery);



// beskrivelse
// version: 1.0 - 2010-05-12
(function($){
// TODO:
//		Lav dokumentation til hvordan plugin'et bliver brugt

	$.fn.sendAjaxPost = function(options){
		
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.sendAjaxPost.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			$this.click(function(){
				$.ajax({
					url: '/post.aspx?ajaxmode=1',
					type: 'post',
					data: o.data
				});
				
				if (o.after){
					o.after($this);
				}

				
				return false;
				
			});
		});
	}

	// default values for the options
	$.fn.sendAjaxPost.defaults = {
		data: null,
		after: null
	};

})(jQuery);



// use history.back if the history is present, else fallback to the link.
// version: 1.0 - 2010-05-27
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.historyBack = function(options){
		
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.historyBack.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			$this.click(function(){
				if (history.length > 1){
					// there is a history in the browser
					history.back();
					return false;
				}
				else {
					// there is not a history in the browser
					// let the link work as a normal link
				}
			});
				
		});
	}
	
	// default values for the options
	$.fn.historyBack.defaults = {
		option: 'value'
	};

})(jQuery);



// check if the specified logininfo actually returns a user
// version: 1.0 - 2010-05-28
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.checkLogin = function(options){
		
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.checkLogin.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// check if a user exists with the specified login. If not, throw an error 
			$this.bind('submit.checklogin',function(){
				var strEmail = $('input[name="Email"]',this).val(),
						strPass = $('input[name="Password"]',this).val();
			  
				// create the data object and fill it with data
				var objData = new Object();
				
				if (o.ajaxData){
					// ajaxData contains data, so we fill it into the objData object
					objData = o.ajaxData;
				}
				else {
					// ajaxData is null, so we fill objData with as good data as possible from the visible text/password fields in the form
					$this.find(':text:visible[name],:password:visible[name]').each(function(){
						objData[$(this).attr('name')] = $(this).val();
					});
				}
				
				$.ajax({
					url: '/dynamic.aspx?data=checklogin&ajaxmode=1',
					data: objData,
					success: function(data){
						if (data == '||') {
							// there's no login with those info, so we alert the user and stops the login form
							$this.find('.error').show();
							return false
						}
						else {
							// hide the error, if it's shown and remove the checklogin check (this one) and submit the form normally
							$this.find('.error').hide().end().unbind('submit.checklogin').submit();
						}
					}
				});
				
				// cancel the regular submit function
				return false;
			});
		});
	}
	
	// default values for the options
	$.fn.checkLogin.defaults = {
		ajaxData: null
	};

})(jQuery);



// activate paging on productlistpaging via ajax 
// version: 1.1 - 2010-07-22
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	// global variables for all functions
	var $container;
	
	$.fn.ajaxProductlistpaging = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.ajaxProductlistpaging.defaults, options);
		
		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// find out which page we are on
			var strActivePage = '1';
			if (location.href.match(o.curpageRegExMatch)) {
				strActivePage = location.href.match(o.curpageRegExMatch)[1];
			} 
			
			// wrap the "current page" productlist and actions in a container, a track and a page container
			$this.find(o.productlistGroupSelector)
				.wrapAll('<div class="' + o.containerId + '"/>')
				.wrapAll('<div class="' + o.trackId + '"/>')
				.wrapAll('<div class="' + o.pageIdPrefix + strActivePage + ' ' + o.pageClass + '"/>');
			
			$container = $('.' + o.containerId,$this);
			
			// give the container some styles, so the pages can move inside this as on a "track"
			$container.css({
				position: 'relative',
				width: $container.width() + 'px',
				height: $container.height() + 'px',
				overflow: 'hidden'
			});
			
			$('.' + o.pageIdPrefix + strActivePage,$this).css({
				position: 'absolute',
				top: 0,
				left: $container.width() * (parseInt(strActivePage) - 1) + 'px',
				width: $container.width() + 'px',
				height: $container.height() + 'px'
			});
			
			$('.' + o.trackId,$this).css({
				position: 'absolute',
				top: 0,
				left: '-' + $container.width() * (parseInt(strActivePage) - 1) + 'px'
			});
			
			
			// find out if the user requests a page via the location.hash
			if (location.hash.indexOf(o.hashPrefix) > -1) {
				var strHashPage = parseInt(location.hash.replace('#' + o.hashPrefix,''));
				
				if (strHashPage != strActivePage ){
					
					// decide which key/value to use (searchtext or key) and whether or not jQuery BBQ have been used
					var strKeyset;
					if (typeof $.bbq.getState() != 'undefined' && location.href.match(o.searchtextRegExMatch)){
						// find the search parameter in the jQuery BBQ plugin
						strKeyset = 'searchtext=' + $.bbq.getState().site.match(o.searchtextRegExMatch)[1];
					}
					else if (typeof $.bbq.getState() != 'undefined'){
						// find the second key parameter in the jQuery BBQ plugin
						strKeyset = 'key=' + $.bbq.getState().site.match(o.keyRegExMatch)[1];
					}
					else if (location.href.match(o.searchtextRegExMatch)) {
						// find the search parameter in the HREF eg. "test" in /productlistpaging/?searchtext=test&paging=1&curpage=2
						strKeyset = 'searchtext=' + location.href.match(o.searchtextRegExMatch)[1];
					} else {
						// find the second parameter in the HREF eg. "test group" in /productlistpaging/test group/?paging=1&curpage=2
						strKeyset = 'key=' + location.pathname.match(o.keyRegExMatch)[1];
					}
					
					var strHashPageUrl = '/dynamic.aspx?data=products&' + strKeyset + '&paging=1&curpage=' + strHashPage;
					getPage(strHashPageUrl, strHashPage, o, $this);
				}
			}

			
			$this.find(o.pagingLinkSelector).live('click',function(){
				// make a new url
				var strUrl = $(this).attr('href');
				var objCurPage = strUrl.match(o.curpageRegExMatch); // find the current page in the HREF
				
				var strCurpage = '1';
				if (objCurPage){
					strCurpage = objCurPage[1];
				}
				
				// set the hash in the URL for when links are sent by mail or in other ways
				location.hash = o.hashPrefix + strCurpage;
				
				if ($('.' + o.pageIdPrefix + strCurpage,$this).size() > 0){
					// the page already exists
					
					
					$('.'+ o.trackId,$this).animate({
						left: ($('.' + o.pageIdPrefix + strCurpage,$this).position().left * -1) + 'px'
					},'slow');
					
				} else {
					// the page did not exist 
				
					//var objKey = strUrl.match(o.keyRegExMatch); // find the second parameter in the HREF eg. "test group" in /productlistpaging/test group/?paging=1&curpage=2
					
					
					// decide which key/value to use (searchtext or key)
					var strKeyset2;
					if (strUrl.match(o.searchtextRegExMatch)) {
						// find the search parameter in the HREF eg. "test" in /productlistpaging/?searchtext=test&paging=1&curpage=2
						strKeyset2 = 'searchtext=' + strUrl.match(o.searchtextRegExMatch)[1];
					} else {
						// find the second parameter in the HREF eg. "test group" in /productlistpaging/test group/?paging=1&curpage=2
						strKeyset2 = 'key=' + strUrl.match(o.keyRegExMatch)[1];
					}
					
					var strDynamicurl = '/dynamic.aspx?data=products&' + strKeyset2 + '&paging=1&curpage=' + strCurpage;
					
					activatePagePreloader();
					getPage(strDynamicurl, strCurpage, o, $this);
				}
				
				// cancel the normal click event
				return false;
			});
			
		});
	}
	
	function getPage(strUrl,strPageId,o,pageContainer){
		/*
		console.log(strUrl);
		console.log(strPageId);
		console.log(o);
		console.log(pageContainer);
		*/
		
		$.get(strUrl,function(data){
			// find the body element  
			var startCut = data.indexOf('<body');
			var endCut = data.indexOf('</body>') + 7;
			
			// if the new page has content, insert it and scroll to it
			if ($(data.substring(startCut, endCut)).find(o.productlistGroupSelector).size() > 1) {
				$('.'+ o.trackId, pageContainer).append('<div class="' + o.pageIdPrefix + strPageId + ' ' + o.pageClass + '"/>');
				
				$('.' + o.pageIdPrefix + strPageId, pageContainer).css({
					position: 'absolute',
					left: ($container.width() * (strPageId - 1)) + 'px',
					top: 0,
					width: $container.width() + 'px',
					height: $container.height() + 'px',
					overflow: 'hidden'
				}).html($(data.substring(startCut, endCut)).find(o.productlistGroupSelector));
				
				if (o.beforeAjaxAnimation) {
					o.beforeAjaxAnimation();
				}
				
				// hide the page preloader
				deActivatePagePreloader();
				
				$('.'+ o.trackId, pageContainer).animate({
					left: ($('.' + o.pageIdPrefix + strPageId, pageContainer).position().left * -1) + 'px'
				}, 'slow');
				
				if (o.afterAjaxAnimation) {
					o.afterAjaxAnimation();
				}

			}
		});
	}
	
	// default values for the options
	$.fn.ajaxProductlistpaging.defaults = {
		containerId: 'productlistpaging-ajax-container',
		trackId: 'productlistpaging-ajax-track',
		pageIdPrefix: 'productlistpaging-ajax-page',
		pageClass: 'productlistpaging-ajax-page',
		hashPrefix: 'page',
		productlistGroupSelector: '.productlistActions,.productlist',
		pagingLinkSelector: '.productlistPaging a',
		curpageRegExMatch: /curpage=(\d+)/i,
		keyRegExMatch: /\/[^\/]+\/(.+)\//i,
		searchtextRegExMatch: /searchtext=([^&]+)/i,
		beforeAjaxAnimation: null,
		afterAjaxAnimation: null
	};
})(jQuery);



 // GLS lookup
 // version: 1.0 - 2010-06-09
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt
	
	$.fn.glsLookup = function(options){
		
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.glsLookup.defaults, options);
		
		// activate the script for each instance found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// when selecting a GLS shop, update the input values
			$(o.glsContainer + ' :radio').live('click',function(){
				$(o.glsShopName).val($(this).metadata().name);
				$(o.glsShopAddress).val($(this).metadata().address);
			});
			
			// when selecting a shippingtype, toggle the glsData depending on whether useGLS is set or not
			$(o.shippingtypesContainer + ' :radio').click(function(){
				
				if ($(this).metadata().useGLS == true){
					$(o.glsContainer).fadeIn();
				} else {
					$(o.glsContainer).fadeOut();
				}
			});
			
			// set basic values for street postalcode and country
			var strStreet = $(o.street).val();
			var strPostalcode = $(o.postalcode).val();
			var strCountry = $(o.country).val();
			
			// if an alternate delivery address is chosen, replace the previous values with these 
			if ($(o.postalcode2).size() > 0 && $(o.postalcode2).val() != '') {
				strStreet = $(o.street2).val();
				strPostalcode = $(o.postalcode2).val();
				strCountry = $(o.country2).val();
			}
			
			// do an ajax request to the server
			if (strPostalcode != '') {
				$.ajax({
					url: "/dynamic.aspx?data=glsdelivery&ajaxmode=1",
					data: {
						street: strStreet,
						postalcode: strPostalcode,
						country: strCountry
					},
					success: function(data){
						if (data != '') {
							// replace the old GLS data with new
							$(o.glsContainer).html(data);
						}
						else {
							$(o.glsContainer).empty('');
						}
						
						// click the checked radiobutton so it saves data
						$(o.glsContainer).find(':radio:checked').click();
					}
				});
			}
		});
	}

	
	// default values for the options
	$.fn.glsLookup.defaults = {
		glsContainer: '#jsGlsdata',
		postalcode: '#addrPostalcode',
		street: '#addrStreet',
		country: '#addrCountry',
		postalcode2: '#addrPostalcode2',
		street2: '#addrStreet2',
		country2: '#addrCountry2',
		glsShopName: '#glsShopName',
		glsShopAddress: '#glsShopAddress',
		shippingtypesContainer: '#shippingtypes'
	};

})(jQuery);


/*
function singleLookup(){
		var objForm = $(this).closest('form').get(0);
*/	
		/*
		var strStreet = o.street ? o.street.val() : objForm.street.value;
		var strPostalcode = o.postalcode ? o.postalcode.val() : objForm.postalcode.value;
		var strCountry = o.country ? o.country.val() : objForm.country.value;
		*/
		
		/*
		var strStreet = o.street.val();
		var strPostalcode = o.postalcode.val();
		var strCountry = o.country.val();
		*/
		
		/*
		var strStreet = objForm.street.value;
		var strPostalcode = objForm.postalcode.value;
		*/
		
		/*
		if (objForm.postalcode2 || o.postalcode2) {
			if (objForm.postalcode2.value != '' || o.postalcode2) {
				strStreet = o.street2 ? o.street2.val() : objForm.street2.value;
				strPostalcode = o.postalcode2 ? o.postalcode2.val() : objForm.postalcode2.value;
				strCountry = o.country2 ? o.country2.val() : objForm.country2.value;
				
			}
		}
		*/
/*		
		if (strPostalcode != '') {
		
			$.get("dynamic.aspx?data=glsdelivery&ajaxmode=1", {
				street: strStreet,
				postalcode: strPostalcode,
				country: strCountry
			}, function(data){
			
				if (data != '') {
					// replace the old GLS data with new
					$(o.glsContainer).replaceWith(data);
				}
				else {
					$(o.glsContainer).empty('');
				}
				
				$(o.glsContainer).find(':radio:checked').click();
				
			}, 'html');
			
		}
	}
*/


// read out RSS and Atom feeds
// dependent on the jQuery plugin getFeed
// version: 1.0 - 2010-07-28
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt

	$.fn.readFeed = function(options){

		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.readFeed.defaults, options);

		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this)
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			if (o.feed){
				
				if (o.feed.match('http://') == null){
					o.feed = 'http://' + o.feed;
				}
				o.feed = '/proxy.aspx?datatype=xml&url=' + o.feed;
				
				$.getFeed({
					url: o.feed,
					success: function(feed){
						if (feed.image){
							$this.append('<a href="' + feed.image.link + '"><img src="' + feed.image.url + '" alt="' + feed.image.title + '"/></a>');
						}
						$this.append('<h2><a href="' + feed.link + '">' + feed.title + '</a></h2><h3>' + feed.description + '</h3>');
						var html = '';
						for(var i = 0; i < feed.items.length && i < 5; i++) {
							var item = feed.items[i];
							html += '<h3><a href="' + item.link + '">' + item.title + '</a></h3>';
							html += '<div class="updated">' + item.updated + '</div>';
							html += '<div class="description">' + item.description + '</div>';
						}
						$this.append(html);
					}
				});
				
			}
			
		});
	}

	// default values for the options
	$.fn.readFeed.defaults = {
		feed: false
	};

})(jQuery);


/*
 // Standard jQuery plugin opbygning
 // --------------------------------
 // beskrivelse
 // version: 1.0 - 2010-06-09
 (function($){
 // TODO:
 //		Lav dokumentation til hvordan plugin'et bliver brugt
 
 $.fn.FUNKTIONSNAVN = function(options){
 
 // create the options object with data from the default options and the user specified options
 var opts = $.extend({}, $.fn.FUNKTIONSNAVN.defaults, options);
 
 // activate the script for each instans found in the selector
 return this.each(function(){
 var $this = $(this);
 // build element specific options
 var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
 
 
 });
 }
 
 // default values for the options
 $.fn.FUNKTIONSNAVN.defaults = {
 option: 'value'
 };
 
 })(jQuery);
*/


// round floats up / down
function round_float(x, n){
	if (!parseInt(n)) var n = 0;
	if (!parseFloat(x)) 		
		return false;
	return Math.round(x * Math.pow(10, n)) / Math.pow(10, n);
}


// NY activate ajax shopping - skal kopieres over i korrekt javascript fil, når den er færdig og gennemtestet.
function activateAjaxShopping_NEW(objArg){

	/* 
	 * ajaxMode (default = false)             : defines whether or not ajaxMode is being used in the querystring
	 * target (default = '.basketpreview')    : selector string to the element which should be replaced with the content
	 * find (default = '.basketpreview')      : selector string to find a specific element inside the collected data
	 *
	 * if no arguments are passed, default values are set
	 */
	objArg = (typeof objArg == 'undefined') ? new Object : objArg;
	objArg.ajaxMode = (typeof objArg.ajaxMode == 'undefined') ? false : objArg.ajaxMode;
	objArg.target = (typeof objArg.target == 'undefined') ? '.basketpreview' : objArg.target;
	objArg.find = (typeof objArg.find == 'undefined') ? '.basketpreview' : objArg.find;
	
	var strAjaxMode = '';
	if (objArg.ajaxMode) {
		strAjaxMode = '&ajaxmode=1'; // call the page with ajaxmode = 1 
	}

	// remove products from basket and update basket preview
	$('.basketpreview input').live('click', function(){
		$(this).closest('form').submit(function(){
			$.post('/post.aspx', {
				_Function: this._Function.value,
				_ReturnTo: '/dynamic.aspx?data=basket&template=basketpreview' + strAjaxMode,
				productid: this.productid.value,
				quantity: this.quantity.value,
				pkid: this.pkid.value
			}, function(data){
			
				var $content = '';
				
				if (objArg.ajaxMode) {
				
					$content = $(data).filter(objArg.find);
					
				}
				else {
				
					// find the body element  
					var startCut = data.indexOf('<body');
					var endCut = data.indexOf('</body>') + 7;
					
					var $content = $(data.substring(startCut, endCut));
					
				}
				
				// replace the target with the new content
				$(objArg.target).replaceWith($content);
				
			}, 'html');
			
			// cancel the normal form submit
			return false;
		});
	});
	

	// add products to basket and update basketpreview
	$('form.jsUpdateBasket').live('submit',function(){
		var strAlert;
		
		// cancel the Ajax call, if some values are missing
		if (this.productid.value == '' || this.quantity.value == '') {
		
			strAlert = (typeof strErrorFieldRequired == 'undefined') ? 'Udfyld alle n\u00F8dvendige felter' : strErrorFieldRequired;
			
			modalAlert(strAlert);
			return false;
		}
		
		// cancel the Ajax call, if the quantity is less than minimum quantity
		if (parseInt(this.min_quantity.value) > parseInt(this.quantity.value)) {
		
			strAlert = (typeof strErrorOrderMinimum == 'undefined') ? 'Du skal bestille minimum' : strErrorOrderMinimum;
			var strAlertPcs = (typeof strErrorOrderMinimumPcs == 'undefined') ? 'stk.' : strErrorOrderMinimumPcs;
			
			modalAlert(strAlert + ' ' + this.min_quantity.value + ' ' + strAlertPcs);
			return false;
		}
		
		
		$.post("/post.aspx", {
			_Function: this._Function.value,
			_ReturnTo: '/dynamic.aspx?data=basket&template=basketpreview' + strAjaxMode,
			productid: this.productid.value,
			quantity: this.quantity.value
		}, function(data){
		
			var $content = '';
			
			if (objArg.ajaxMode) {
				$content = $(data).filter(objArg.find);
			}
			else {
			
				// find the body element  
				var startCut = data.indexOf('<body');
				var endCut = data.indexOf('</body>') + 7;
				
				var $content = $(data.substring(startCut, endCut));
				
			}
			
			// replace the target with the new content
			$(objArg.target).replaceWith($content);
			
		}, 'html');
		
		
		// this is used to show that the form have been sent to the server and the basket have been updated  
		$('.added', this).fadeIn(100, function(a){
			setTimeout(function(){
				$('.added').fadeOut('slow');
			}, 2000)
		});
		
		// cancel the normal form submit
		return false;
	});

	// hack to make Internet Explorer respect the live event on the forms (it could otherwise just use the browser default action)
	$('form.jsUpdateBasket :submit, form.jsUpdateBasket :image').live('click',function(){
		$(this).closest('form').submit();
		return false;
	});
}

/*
 * Cycle Carousel (siteSlider)
 ***************************/
function siteSlider()
{
	if ($('#shopSlider img').size() > 1) {
		$('#shopSlider ul').simplyScroll({
			autoMode: 'loop',
			horizontal: true,
			speed: 2,
			frameRate: 20, // 24
			pauseOnHover: true,
			startOnLoad: false // true
		});
		/*$('#shopSlider').jcarousel({
			auto: 1, //4,
			wrap: 'circular',
			scroll: 1,
			animation: 'slow',
			//rtl: true,
			initCallback: shopSlider_initCallback
		});*/
	}
}

function shopSlider_initCallback(carousel)
{
    // Disable autoscrolling if the user clicks the prev or next button.
    /*carousel.buttonNext.bind('click', function() {
        carousel.startAuto(0);
    });

    carousel.buttonPrev.bind('click', function() {
        carousel.startAuto(0);
    });*/

    // Pause autoscrolling if the user moves with the cursor over the clip.
    carousel.clip.hover(function() {
        carousel.stopAuto();
    }, function() {
        carousel.startAuto();
    });
};

// GiftWrapping
function GiftWrapping()
{
	$('.inpWrapping').live('click', function() {
			var that = $(this);
			
			activatePagePreloader();
			
			if ($(this).is(':checked'))
			{
				var params = {};
				params[encodeURI('pkid')] = $(this).attr('name').substring(8);
				params[encodeURI('productid')] = $('#update' + $(this).attr('name').substring(8)).find('input[name=productid]').val();
				params[encodeURI('quantity')] = $('input[name=quantity' + $(this).attr('name').substring(8) + ']').val();
				params[encodeURI('@wrapping')] = 1;
				params[encodeURI('_Function')] = 'UpdateBasket';
				params[encodeURI('_ReturnTo')] = '/dynamic.aspx?data=basket';
				
				$.post("/post.aspx", params,
				function(data){
					//alert('CHECKED: ' + that.attr('name').substring(8));
					$('#siteMain').html(data);
				}, 'html');
			}
			else
			{
				var params = {};
				params[encodeURI('pkid')] = $(this).attr('name').substring(8);
				params[encodeURI('productid')] = $('#update' + $(this).attr('name').substring(8)).find('input[name=productid]').val();
				params[encodeURI('quantity')] = $('input[name=quantity' + $(this).attr('name').substring(8) + ']').val();
				params[encodeURI('@wrapping')] = 0;
				params[encodeURI('_Function')] = 'UpdateBasket';
				params[encodeURI('_ReturnTo')] = '/dynamic.aspx?data=basket';
				
				$.post("/post.aspx", params,
				function(data){
					//alert('UNCHECKED: ' + that.attr('name').substring(8));
					$('#siteMain').html(data);
				}, 'html');
			}
			
			deActivatePagePreloader();
		});
	//});
}

function resizeFrontColumns() {
	if ($('#siteGroupsmenu').height() > ($('#tFrontpage .newslettersignup').height() + $('#tFrontpage .facebook').outerHeight(true)))
	{
		$('#tFrontpage .newslettersignup').height(($('#siteGroupsmenu').height() - $('#tFrontpage .facebook').outerHeight(true)));
		$('#tFrontpage .promotiongroup').height(($('#siteGroupsmenu').height()));
	}
	if ($('#siteGroupsmenu').height() > $('#siteMain').height())
	{
		$('#siteMain').height($('#siteGroupsmenu').height() + 20);
	}
}

/*
 ON LOAD
 *********************************************/
// jQuery 'onReady' script - runs when the document have been loaded, but before images
$(function(){
	//validateForms();
	
	activateAjaxShopping_NEW({
		ajaxMode: true,
		target: '#basketpreview',
		find: '#basketpreview'
	});
	
	$('form').formvalidation();
	
	//autocompletePostalCode3('#tDelivery #addrPostalcode', '#tDelivery #addrCity', '#tDelivery #addrCountry');
	//autocompletePostalCode3('#tDelivery #addrPostalcode2', '#tDelivery #addrCity2', '#tDelivery #addrCountry2');
	//autocompletePostalCode3('#tCreatecustomer #customerPostalcode', '#tCreatecustomer #customerCity', '#tCreatecustomer #customerCountry');
	
	resizeFrontColumns();
	siteSlider();
	productlistImage();
	postPolls();
	quizWizzard();
	tracktrace();
	GiftWrapping();
	changeProductImage();
	flashLoad();
	openPopups();
	//showInlineHelp();
	//variantSelection();
	
	// when changing sort method on productlistpaging, submit the sorting form
	$('#siteMain').delegate('.productlistSorting select', 'change', function(){
		$(this).closest('form').submit();
	});
	
	$('.tProducts').ajaxProductlistpaging({
		beforeAjaxAnimation: function(){
			$('.jsQuantity').quantityAddSubtract();
		}
	});
	
	
	$('#mainMenu').menuFades();
	$('#areaMenu').groupsmenuAjax();
	$('.jsQuantity').quantityAddSubtract();
	$('.jsInput').toggleInputText();
	$('.jsShowForgotPwd, .jsShowLogin').setActiveBox();
	$('.jsGoBack').historyBack();
	$('#menuLoginForm form, #siteLoginForm form').checkLogin();
	$('#tPayment').glsLookup();
	$('.rssFeed').readFeed();
	
	
	// toggle optional delivery address
	$('#addrOptionalDelivery').click(function(){
		if (this.checked){
			$('#tDelivery').find('.secondaryAddress .secondaryAddresinput').removeAttr('disabled');
			$('#tDelivery').find('.secondaryAddress').show();
		} else {
			$('#tDelivery').find('.secondaryAddress .secondaryAddresinput').attr('disabled','disabled');
			$('#tDelivery').find('.secondaryAddress').hide();
		}
	});
	$('#tDelivery').find('.secondaryAddress:hidden .secondaryAddresinput').attr('disabled','disabled');

	
	// tests if the terms are accepted on the orderstatus page before going on
	$('#tOrderstatus').find('form').submit(function(){
		if ($('#TermsAccepted').is(':checked') == false){
			var strAlert = typeof strAcceptTermsError == 'undefined' ? 'Du skal acceptere handelsbetingelserne' : strAcceptTermsError;
			alert(strAlert);
			return false;
		}
	});
	
	// when user wants to unsubscribe the newsletter, fill out the correct form and submit it
	$('#tNewssignup').find('.cancelSubscription').click(function(){
		var objForm = $('#newsletterCancelSubscription');
		objForm.get(0).email.value = $('#newslettersubscribeEmail').val();
		objForm.submit();
	});
	
	// show/hide the menuLogin container, based on the class
	$('#menuLogin>a').click(function(){
		$(this).blur().parent().toggleClass('itemLoginActive');
		return false;
	});
	
	// add/remove product to/from wishlist
	$('.productLinkwishlist').not('.productLinkwishlistRemove').sendAjaxPost({
		after: function(){ $('.productLinkwishlist').toggle(); }
	});
	$('.productLinkwishlistRemove').sendAjaxPost({
		after: function(){ $('.productLinkwishlist').toggle(); }
	});
	
	// add/remove product to/from favorites
	$('.productLinkfavorites').not('.productLinkfavoritesRemove').sendAjaxPost({
		after: function(){ $('.productLinkfavorites').toggle(); }
	});
	$('.productLinkfavoritesRemove').sendAjaxPost({
		after: function(){ $('.productLinkfavorites').toggle(); }
	});
	
	// add lightbox/colorbox functionality to shoppinglist links
	$('.productLinkshoppinglist').colorbox({
		onComplete: function(){
			$('#tUpdateshoppinglist .jsQuantity').quantityAddSubtract();
			$('#tUpdateshoppinglist .jsInput').toggleInputText();
			$('#tUpdateshoppinglist').find('form').ajaxForm({
				success: function(data){
					$(document).one('cbox_closed',function(){
						$.fn.colorbox({
							html: data
						});
					});
					$.fn.colorbox.close();
				}
			})
		}
	});
	
	// add lightbox/colorbox functionality to tip a friend links
	$('.productLinktipafriend').colorbox({
		onComplete: function(){
			$('#tTipafriend .jsInput').toggleInputText();
			$.fn.colorbox.resize();
			$('#tTipafriend').find('form').formvalidation().ajaxForm({
				beforeSubmit: function(formData, jqForm, options){
					if (jqForm.data('allOk') == 0){
						return false;
					}
				},
				success: function(data){
					$(document).one('cbox_closed',function(){
						$.fn.colorbox({
							html: data
						});
					});
					$.fn.colorbox.close();
				}
			})
		}
	});
	
	// add lightbox/colorbox functionality to print links
	$('.productLinkprint').colorbox({
		iframe: true,
		width:700,
		height:'80%'
	});
	
	
	
	
	// standard lightbox feature for productinfo page - building the container
	updateProductImagesLightbox();
	
	// standard lightbox feature for productinfo page - activating the overlay
	$('#productImages a').colorbox({
		inline: true,
		href: '#productImagesLightbox',
		onOpen: function(){
			$('#productImagesLightbox').find('.imageContainer img[src$="' + escape($(this).attr('href')) + '"]:first').show().siblings('img').hide();
			$('#productImagesLightbox').find('.productImageActions').html($('#productAdditions').children().clone(true));
		},
		onComplete: function(){
			$('#productImagesLightbox').find('.imageContainer').css({
				height: $('#productImagesLightbox').find('.imageContainer').height()
			});
			
			if ($('#productImagesLightbox').find('.imageContainer img').size() > 1) {
				updateLightboxButtons();
				
				$('#productImagesLightbox').find('.imageContainer .lightboxNavigation').click(function(){
					$this = $(this);
					$img = $this.siblings('img:visible');
					
					if ($img.siblings('img').size() > 0) {
						if ($img.next('img').size() > 0 && $this.hasClass('next')) {
							$img.fadeOut('fast', function(){
								$img.next('img').fadeIn('slow');
								updateLightboxButtons();
							});
						}
						else if ($img.prev('img').size() > 0 && $this.hasClass('prev')) {
							$img.fadeOut('fast', function(){
								$img.prev('img').fadeIn('slow');
								updateLightboxButtons();
							});
						}
					}
				});
			}
			else {
				$('#productImagesLightbox').find('.imageContainer .lightboxNavigation').hide();
			}			
		}
	});
	
	
	
	// delete from basket
	$('#tBasket').find('.jsDelete').live('click',function(){
		$($(this).attr('href')).ajaxSubmit({
			beforeSubmit: activatePagePreloader,
			success: function(data){
				// find the body element  
				var startCut = data.indexOf('<body');
				var endCut = data.indexOf('</body>') + 7;
				
				var $content = $(data.substring(startCut, endCut));
				$('#tBasket').replaceWith($content);
				
			}
		});
		return false;
	});
	
	// update quantity in basket
	$('#tBasket').find('.quantity input').live('change',function(){
		var strPkid = $(this).attr('name').replace('quantity',''),
				intValue = $(this).val();
		
		$('#update' + strPkid).get(0).quantity.value = intValue;
		
		$('#update' + strPkid).ajaxSubmit({
			beforeSubmit: activatePagePreloader,
			success: function(data){
				// find the body element  
				var startCut = data.indexOf('<body');
				var endCut = data.indexOf('</body>') + 7;
				
				var $content = $(data.substring(startCut, endCut));
				$('#tBasket').replaceWith($content);
				
			}
		});
		return false;
	});
	
	$('#tBasket').find('#basketWrapping').live('click',function(){
		$(this).closest('form').ajaxSubmit();
	});
	
	// toggle the visibility of the optional delivery form
	$('.jsOptionalDelivery').click(function(){
		var $this = $(this);
		
		if ($this.attr('checked')){
			$('.secondaryAddress').show();
		} else {
			$('.secondaryAddress').hide();
		}
	});
	
	
	// empty city and postalcode input fields, when changing country 
	$('#tDelivery').find(':input[name=country]').change(function(){
		$('#tDelivery').find(':input[name=city], :input[name=postalcode]').val('');
		$('#addrPostalcode').flushCache();
	})
	.end().find(':input[name=country],:input[name=country2]').change(function(){
		$('#tDelivery').find(':input[name=city2], :input[name=postalcode2]').val('');
		$('#addrPostalcode2').flushCache();
	});
	
	
	
	// ajax submitting the subscribe newsletter form
	$('#newsletterSubscription').ajaxForm({
		beforeSubmit: function(formData, jqForm, options){
			if (jqForm.data('allOk') == 0){
				return false;
			}
			$('#newsletterSubscription').find('.preloader').fadeIn('fast');
		},
		success: function(){
			$('#newsletterSubscription').find('.preloader').hide();
			$('#newsletterSignupSuccess').fadeIn('fast', function(){
				setTimeout("$('#newsletterSignupSuccess').fadeOut('fast')",5000);
			});
			
		}
	});
	
	// ajax submitting the unsubscribe newsletter form
	$('#newsletterCancelSubscription').ajaxForm({
		beforeSubmit: function(formData, jqForm, options){
			if (jqForm.data('allOk') == 0){
				return false;
			}
			$('#newsletterSubscription').find('.preloader').fadeIn('fast');
		},
		success: function(){
			$('#newsletterSubscription').find('.preloader').hide();
			$('#newsletterUnsubscribeSuccess').fadeIn('fast', function(){
				setTimeout("$('#newsletterUnsubscribeSuccess').fadeOut('fast')", 5000);
			});
		}
	});
	
	
	
	// promotion articles rotation
	if ($('#promotion .promotionImages img').size() > 1){
		$('#promotion .promotionImages').cycle({ 
			speed:  'fast',
			timeout: 4000,
			pager: '#promotion .promotionNav',
			pagerAnchorBuilder: function(idx, slide){
				// return selector string for existing anchor 
				return '#promotion .promotionNav li:eq(' + idx + ') a';
			},
			pagerEvent: 'mouseover',
			pauseOnPagerHover: true
		});
		
		// force a click event on the carousel navigation links, to counteract the cycle plugin event unbinder.
		$('#promotion .promotionNav a').click(function(){
			location.href = this;
		});
	}
	
	// toggle visibility of input fields on the customerinfo page, when clicking on the edit profile button
	$('#tCustomerinfo').find('.inpEditProfile').click(function(){
		$('#tCustomerinfo .updatecustomerForm').find('span.value,:text, select, textarea,:submit,:button').toggle();
		return false;
	});
	
	// on submitting forms on the shoppinglist page, ask if the user wants to save the list for later. 
	$('#tShoppinglist').find('.jsTransferShoppinglistToBasket').submit(function(){
		var preserveText = (typeof preserveListText != 'undefined')? preserveListText : 'Vil du bevare listen?'; 
		var agree = confirm(preserveText);
		if (agree){
			this.preserve.value = '1';
		}
	});
	
	
	// galleries on pages should have lightbox/colorbox functionality and an icon at mouseover
	$('#pageGallery').find('a[rel="imageGallery"]').append('<img class="zoom" src="/images/icon_zoom.png" alt="">').colorbox({
		current: ''
	});
	
	// images on normal pages should have lightbox/colorbox functionality
	$('a[rel="pageImages"]').colorbox({
		current: ''
	});
	
	// activate search suggests - type-ahead search
	$('.searchform input[name="searchtext"]').searchSuggest({
		afterAjax: function(){
			$('.jsQuantity').quantityAddSubtract();
		}
	});

	$('.getEmailLink').click(function(){
		var $this = $(this);
		$.ajax({
			url: '/dynamic.aspx?ajaxmode=1&data=article&template=getemail',
			data: {
				key: $this.attr('href').substring(1)
			},
			success: function(data){
				$this.replaceWith(data);
			}
		});
		return false;
	});




	initializeBBQ();

	// activate variant system
	$('#productVariantsNew').variantSystem();
	
	
}); // jQuery ready end


// if popups are used on the page, show it
// have to be in the load event, since "ready state" is to early
$(window).load(function(){
	// set default id on the popup
	var strCurrentPKID = '0';
	
	// if the strPagePKID variable is set, replace the old id 
	if (typeof strPagePKID != 'undefined'){ strCurrentPKID = strPagePKID; }
	
	// if a popup should be shown and the cookie is not set to 1
	if ($('#pagePopup').size() > 0 && readCookie('pagePopup'+ strCurrentPKID) != '1'){
		$.colorbox({
			href: $('#pagePopup').attr('href'),
			iframe: true,
			width: '700',
			height: '80%',
			title: '<a href="#" onclick="closeAndHidePopup('+ strCurrentPKID +'); return false;">Luk og vis ikke igen</a>',
			onOpen: function(){
				$('#colorbox').addClass('pagePopup');
			},
			onClosed: function(){
				$('#colorbox').removeClass('pagePopup');
			}
		});
	}
});

// close and hide the pagePopup
function closeAndHidePopup(strPKID){
	createCookie('pagePopup' + strPKID,'1',1);
	$.colorbox.close();
}

// standard lightbox feature for productinfo page - building the container
function updateProductImagesLightbox(){
	
	$('#productImagesLightbox .imageContainer').find('img').remove()
		.end().prepend($('#productImages img').clone().removeAttr('id')).find('.zoom').remove()
		.end().find('img').each(function(){
	
			var strSrc = $(this).attr('src').replace('/thumbnail/','/productzoom/').replace('/productmain/','/productzoom/');
			$(this).attr('src',strSrc);
		
		}).hide();
	
} // updateProductImagesLightbox end


function autocompletePostalCode3(pcodeField, cityField, countryField) {
	if ($.isFunction($(this).autocomplete)) {//kontroller om autocomplete-funktionen er importeret
		$(pcodeField)
			.autocomplete('/dynamic.aspx?data=citynames&ajaxmode=1', {
				formatItem: function(row, i, max) {
					return row[0].replace('_',' ');
				},
				max: 9,
				extraParams: {
					countryid: function() { return $(countryField).val(); }
				},
				width: '200px'
			})
			.result(function(event, data, formatted){
				
				if (data) {
					var result = data[0].split('_');
					$(pcodeField).val(result[0]);
					if ($(pcodeField).val() != '') {
						$(cityField).val(result[1]);
					}
					else {
						$(cityField).val('');
					}
				}
				
				/*
				else {
					$(cityField).val('');
				}
				*/
				
			})
			/*
			.blur(function(){
					$(this).search();
			})
			*/
		;
		
		$(cityField).attr('readonly', true).addClass('disabled');
	}
}


function activatePagePreloader(){
	$('#pagePreloader').fadeTo('fast',0.5);
}
function deActivatePagePreloader(){
	$('#pagePreloader').fadeOut('fast');
}

// productImagesLightbox buttons update
function updateLightboxButtons(){
	
	var $imageContainer = $('#productImagesLightbox').find('.imageContainer');
	var $prev = $imageContainer.find('.prev'),
			$next = $imageContainer.find('.next'),
			$img = $imageContainer.find('img:visible');
	
	// enable/disable the next-button as needed
	if ($img.nextAll('img').size() < 1){ $next.addClass('disabled'); }
	else { $next.removeClass('disabled'); }
	
	// enable/disable the prev-button as needed
	if ($img.prevAll('img').size() < 1){ $prev.addClass('disabled'); }
	else { $prev.removeClass('disabled'); }

} // updateLightboxButtons end


// OLD FORM VALIDATION!!!! NOT USED ANYMORE
// validate forms on submit and on input typing and blur
function formValidation(){

	// single field validation
	function validateField(evt){
		var $this = $(this), objForm = $this.closest('form'), strActivateKeyup = 'jsTextfieldactivatekeyup', bitOk = true, re;
		
		if (evt.type != "keyup" || $this.hasClass(strActivateKeyup)) {
			// if the input doesn't allow keyup events, activate it (this happens at first blur event)
			if (!$this.hasClass(strActivateKeyup)) {
				$this.addClass(strActivateKeyup);
			}
			
			// validate field
			
			/*
			 * Valideringen skal understoette foelgende data, krav og afgraensninger:
			 *
			 * Fornavn og efternavn skal indeholde tekst.
			 * Gade skal indeholde minimum et ord efterfulgt af et mellemum og et tal.
			 * postnummer skal vaere 4 tegn i Danmark.
			 * By bliver automatisk indsat efter postnummer.
			 * Telefon skal indeholde 8 tegn for dansk tlf.nummer.
			 * E-mail skal indeholde min. 1 tegn efterfulgt af et @ (snabel a) efterfulgt af min. 1 tegn efterfulgt af et . (punktum) efterfulgt af 2-4 karakterer.
			 *
			 *
			 * For at identificere de forskellige felttyper, skal hvert felt have en css klasse der fort�ller hvordan feltet skal valideres.
			 * Forslag til css klasser, der kan benyttes til validering samt beskrivelse af hvad de skal validere:
			 *
			 * jsValidate: bruges kun til at identificere hvilke felter der skal valideres.
			 * jsValidatetext: validerer om feltet ikke er tomt - dette skal vaere basis form for validering, alle andre valideringstyper goer automatisk dette
			 * jsValidatefullname: kontrollerer om der er minimum 2 ord i feltet
			 * jsValidatepostalcode: tester om postnummeret er korrekt i forhold til det enkelte lands krav
			 * jsValidatephone: Ser om telefonnummeret er indtastet korrekt i forhold til landets krav
			 * jsValidatemail: E-mail skal indeholde de paakraevede dele specificeret ovenfor
			 * jsValidateaddress: Korrekt indtastet adresse - efter ovenstaaende specifikation
			 * jsValidaterepeat: Tester om teksten i feltet er det samme som i feltet med det tilknyttede ID (i css klassen "jsValidaterepeatfromIDPAAFELT"
			 *
			 *
			 */
			// test if there is a required field for this input field
			var strCurrentName = $this.attr('name');
			var objRequiredField = $('input[name=_' + strCurrentName + '_required],input[name=' + strCurrentName + '_Required]', objForm);
			var bitRequired = (objRequiredField.size() > 0);
			
			if ($this.hasClass('jsValidatetext')) {
				re = /.+/;
			}
			else 
				if ($this.hasClass('jsValidatefullname')) {
					re = /\w+\s\w+/;
				}
				else 
					if ($this.hasClass('jsValidatepostalcode')) {
						// her boer man have forskellige landevalg, saa valideringen ved hvordan den skal validere? ligenu gaar den kun efter 4 cifre
						//re = /^\d{4}$/;
						re = /^\d+$/;
					}
					else 
						if ($this.hasClass('jsValidatephone')) {
							// her boer man have forskellige landevalg, saa valideringen ved hvordan den skal validere? ligenu gaar den kun efter 8 cifre
							re = /^\d{8}$/;
						}
						else 
							if ($this.hasClass('jsValidatemail')) {
								re = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$/i;
							}
							else 
								if ($this.hasClass('jsValidateaddress')) {
									re = /^(.)+\s[1-9]/;
								}
								else {
									// hvis der ikke er nogen specifik validering, skal der alligevel valideres paa om der er indhold i feltet.
									re = /.+/;
								}
			
			bitOk = re.test($this.val());
			
			// hvis feltet er et repeat felt, f.eks. gentag password eller e-mail,
			// skal valideringen i stedet gaa paa om feltets indhold er det samme som det tilknyttede
			if ($this.hasClass('jsValidaterepeat')) {
				var strAllclasses = $this.attr('class').split(' '), strOriginalInputId;
				
				$.each(strAllclasses, function(i, val){
					if (val.indexOf('jsValidaterepeatfrom') > -1) {
						strOriginalInputId = val.replace('jsValidaterepeatfrom', '');
						
						return false;
					}
				});
				
				bitOk = ($this.val() == $('#' + strOriginalInputId).val() && $this.val != '');
			}
			
			// hvis et postalcode felt ikke indeholder tal mellem 1000 og 9999, skal der vises en fejl
			/*
			if ($this.hasClass('jsValidatepostalcode') && bitOk) {
				var intPostal = parseInt($this.val());
				if (intPostal < 1000 || intPostal > 9999){
					bitOk = false;
				}
			}
			*/
			
			if ((bitRequired && bitOk) || (!bitRequired && $this.val() != '' && bitOk)) {
				// hvis feltet er korrekt udfyldt
				$this.removeClass('textfield_error').siblings('.validationMessage').removeClass('validationMessageError');
				$this.addClass('textfield_valid').siblings('.validationMessage').addClass('validationMessageValid');
				
				$this.data('validatedOk', true);
			}
			else 
				if ((bitRequired && !bitOk) || (!bitRequired && $this.val() != '' && !bitOk) || (bitRequired && $this.val() == '')) {
					// hvis feltet ikke er udfyldt korrekt.
					$this.removeClass('textfield_valid').siblings('.validationMessage').removeClass('validationMessageValid');
					$this.addClass('textfield_error').siblings('.validationMessage').addClass('validationMessageError');
					
					$this.data('validatedOk', false);
				}
				else
					if ($this.val() == '' && !bitRequired) {
						// hvis feltet ikke er udfyldt og det ikke er paakraevet
						$this.removeClass('textfield_error').siblings('.validationMessage').removeClass('validationMessageError');
						$this.removeClass('textfield_valid').siblings('.validationMessage').removeClass('validationMessageValid');
						
						$this.data('validatedOk', true);
					}
					else {
					}
		}
	} // validateField end
	
	
	$('form').each(function(){
		var objForm = this;
		
		// if the 'allOk' is already set as a string on the form, validation is already active and does not need to bet set again.
		if (typeof ($(objForm).data('allOk')) == 'string'){
			return false;
		}
		
		$(objForm).data('allOk', '1');
		
		// select all fields that require a certain mask validation
		$('.jsValidate', objForm).bind('keyup blur', validateField);
		
		$(objForm).submit(function(){
			var bitSendform = true;
			
			// Run a validation on all required fields
			$(':input[name*=_Required], :input[name*=_required]', this).each(function(){
				var relatedInput = $(':input[name=' + $(this).attr('name').replace(/_Required$/i, '').replace(/^_/, '') + ']', objForm);
				relatedInput.each(validateField)
			});
			
			// test if any active fields are not valid
			$(':input', this).not('[disabled]').each(function(){
				var $input = $(this);
				
				if ($input.data('validatedOk') == false) {
					bitSendform = false;
				}
			});
			
			if (!bitSendform) {
				$(objForm).data('allOk', '0');
				
				var strAlert = 'Du skal udfylde alle felter med * med korrekt data';
				alert(strAlert);
				return false;
			}
		});
		
	});

} // formValidation end










// beskrivelse
// version: 1.0 - 2010-06-08
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt

	$.fn.formvalidation = function(options){
	
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.formvalidation.defaults, options);
	
		// activate the script for each instans found in the selector
		return this.each(function(){
			var objForm = this;
			var $this = $(objForm);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			
			// if the 'allOk' is already set as a string on the form, validation is already active and does not need to bet set again.
			if (typeof ($this.data('allOk')) == 'string'){
				return false;
			}
			
			$this.data('allOk', '1');
			
			// select all fields that require a certain mask validation
			$this.find('.jsValidate').bind('keyup blur', validateField);
			
			$this.submit($.fn.formvalidation.validate);
		});
	}
	
	$.fn.formvalidation.validate = function(){
		var $this = $(this), bitSendform = true;
		
		// Run a validation on all required fields
		$this.find(':input[name*=_Required], :input[name*=_required]').each(function(){
			var relatedInput = $this.find(':input[name=' + $(this).attr('name').replace(/_Required$/i, '').replace(/^_/, '') + ']');
			relatedInput.each(validateField);
		});
		
		// test if any active fields are not valid
		$this.find(':input').not('[disabled]').each(function(){
			var $input = $(this);
			
			if ($input.data('validatedOk') == false) {
				bitSendform = false;
			}
		});
		
		if (!bitSendform) {
			$this.data('allOk', '0');
			
			var strAlert = 'Du skal udfylde alle felter med * med korrekt data';
			alert(strAlert);
			return false;
		} else {
			$this.data('allOk', '1');
		}
	}
	
	// single field validation
	function validateField(evt){
		var $this = $(this), objForm = $this.closest('form'), strActivateKeyup = 'jsTextfieldactivatekeyup', bitOk = true, re;
		
		if (evt.type != "keyup" || $this.hasClass(strActivateKeyup)) {
			// if the input doesn't allow keyup events, activate it (this happens at first blur event)
			if (!$this.hasClass(strActivateKeyup)) {
				$this.addClass(strActivateKeyup);
			}
			
			// validate field
			
			/*
			 * Valideringen skal understoette foelgende data, krav og afgraensninger:
			 *
			 * Fornavn og efternavn skal indeholde tekst.
			 * Gade skal indeholde minimum et ord efterfulgt af et mellemum og et tal.
			 * postnummer skal vaere 4 tegn i Danmark.
			 * By bliver automatisk indsat efter postnummer.
			 * Telefon skal indeholde 8 tegn for dansk tlf.nummer.
			 * E-mail skal indeholde min. 1 tegn efterfulgt af et @ (snabel a) efterfulgt af min. 1 tegn efterfulgt af et . (punktum) efterfulgt af 2-4 karakterer.
			 *
			 *
			 * For at identificere de forskellige felttyper, skal hvert felt have en css klasse der fort�ller hvordan feltet skal valideres.
			 * Forslag til css klasser, der kan benyttes til validering samt beskrivelse af hvad de skal validere:
			 *
			 * jsValidate: bruges kun til at identificere hvilke felter der skal valideres.
			 * jsValidatetext: validerer om feltet ikke er tomt - dette skal vaere basis form for validering, alle andre valideringstyper goer automatisk dette
			 * jsValidatefullname: kontrollerer om der er minimum 2 ord i feltet
			 * jsValidatepostalcode: tester om postnummeret er korrekt i forhold til det enkelte lands krav
			 * jsValidatephone: Ser om telefonnummeret er indtastet korrekt i forhold til landets krav
			 * jsValidatemail: E-mail skal indeholde de paakraevede dele specificeret ovenfor
			 * jsValidateaddress: Korrekt indtastet adresse - efter ovenstaaende specifikation
			 * jsValidaterepeat: Tester om teksten i feltet er det samme som i feltet med det tilknyttede ID (i css klassen "jsValidaterepeatfromIDPAAFELT"
			 *
			 *
			 */
			// test if there is a required field for this input field
			var strCurrentName = $this.attr('name');
			var objRequiredField = $('input[name=_' + strCurrentName + '_required],input[name=' + strCurrentName + '_Required]', objForm);
			var bitRequired = (objRequiredField.size() > 0);
			
			if ($this.hasClass('jsValidatetext')) {
				re = /.+/;
			}
			else 
				if ($this.hasClass('jsValidatefullname')) {
					re = /\w+\s\w+/;
				}
				else 
					if ($this.hasClass('jsValidatepostalcode')) {
						// her boer man have forskellige landevalg, saa valideringen ved hvordan den skal validere? ligenu gaar den kun efter 4 cifre
						//re = /^\d{4}$/;
						re = /^\d+$/;
					}
					else 
						if ($this.hasClass('jsValidatephone')) {
							// her boer man have forskellige landevalg, saa valideringen ved hvordan den skal validere? ligenu gaar den kun efter 8 cifre
							re = /^\d{8}$/;
						}
						else 
							if ($this.hasClass('jsValidatemail')) {
								re = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]+$/i;
							}
							else 
								if ($this.hasClass('jsValidateaddress')) {
									re = /^(.)+\s[1-9]/;
								}
								else {
									// hvis der ikke er nogen specifik validering, skal der alligevel valideres paa om der er indhold i feltet.
									re = /.+/;
								}
			
			bitOk = re.test($this.val());
			
			// hvis feltet er et repeat felt, f.eks. gentag password eller e-mail,
			// skal valideringen i stedet gaa paa om feltets indhold er det samme som det tilknyttede
			if ($this.hasClass('jsValidaterepeat')) {
				var strAllclasses = $this.attr('class').split(' '), strOriginalInputId;
				
				$.each(strAllclasses, function(i, val){
					if (val.indexOf('jsValidaterepeatfrom') > -1) {
						strOriginalInputId = val.replace('jsValidaterepeatfrom', '');
						
						return false;
					}
				});
				
				bitOk = ($this.val() == $('#' + strOriginalInputId).val() && $this.val != '');
			}
			
			// hvis et postalcode felt ikke indeholder tal mellem 1000 og 9999, skal der vises en fejl
			/*
			if ($this.hasClass('jsValidatepostalcode') && bitOk) {
				var intPostal = parseInt($this.val());
				if (intPostal < 1000 || intPostal > 9999){
					bitOk = false;
				}
			}
			*/
			
			if ((bitRequired && bitOk) || (!bitRequired && $this.val() != '' && bitOk)) {
				// hvis feltet er korrekt udfyldt
				$this.removeClass('textfield_error').siblings('.validationMessage').removeClass('validationMessageError');
				$this.addClass('textfield_valid').siblings('.validationMessage').addClass('validationMessageValid');
				
				$this.data('validatedOk', true);
			}
			else 
				if ((bitRequired && !bitOk) || (!bitRequired && $this.val() != '' && !bitOk) || (bitRequired && $this.val() == '')) {
					// hvis feltet ikke er udfyldt korrekt.
					$this.removeClass('textfield_valid').siblings('.validationMessage').removeClass('validationMessageValid');
					$this.addClass('textfield_error').siblings('.validationMessage').addClass('validationMessageError');
					
					$this.data('validatedOk', false);
				}
				else
					if ($this.val() == '' && !bitRequired) {
						// hvis feltet ikke er udfyldt og det ikke er paakraevet
						$this.removeClass('textfield_error').siblings('.validationMessage').removeClass('validationMessageError');
						$this.removeClass('textfield_valid').siblings('.validationMessage').removeClass('validationMessageValid');
						
						$this.data('validatedOk', true);
					}
					else {
					}
		}
	} // validateField end
	
	
	
	// default values for the options
	$.fn.formvalidation.defaults = {
		option: 'value'
	};

})(jQuery);


// searchSuggest - type ahead
// version: 1.0 - 2010-07-23
(function($){
	// TODO:
	//		Lav dokumentation til hvordan plugin'et bliver brugt.
	//		Udvid funktionalitet, så man kan kalde/aktivere søgningen direkte fra javascript ved at kalde det på ca. denne måde: $(selector).searchSuggest.search().
	//		Lav callback funktioner.
	//		Burde man kunne navigere ned igennem listen af resultater med keyboardet? Hvis man skal, skal det være en option og hvordan skulle det gøres med et fleksibelt system - der skal være en form for selector-option tilknyttet så?
	
	
	$.fn.searchSuggest = function(options){
		
		// create the options object with data from the default options and the user specified options
		var opts = $.extend({}, $.fn.searchSuggest.defaults, options);

		// activate the script for each instans found in the selector
		return this.each(function(){
			var $this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// remove the autocomplete from the input
			$this.attr('autocomplete','off').keyup(function(e){
				var intKey = e.keyCode;
				// only allow certain keystrokes
				if ((intKey > 47 && intKey < 58) || (intKey > 36 && intKey < 41) || (intKey > 64 && intKey < 91) ||
						(intKey > 96 && intKey < 112) || (intKey > 185 && intKey < 223) ||
						intKey == 32 || intKey == 226 ||
						intKey == 46 || intKey == 8){
			
					// if the timeout is still counting down, cancel it to stop the client from hammering the server with search requests
					if (typeof($.fn.searchSuggest.searchSuggestTimeout) != 'undefined') {
						clearTimeout($.fn.searchSuggest.searchSuggestTimeout);
					}
					
					// set the timeout to when the search should be made after last keystroke
					$.fn.searchSuggest.searchSuggestTimeout = window.setTimeout(function(){
						searchSuggestAjax($this,o);
					}, o.timeout);
				}
			});
		});
	}
	
	
	// timeout container for the searchsuggestion container
	$.fn.searchSuggest.searchSuggestTimeout;
	
	
	// search suggest ajax request
	// strSort: optional method of sorting
	function searchSuggestAjax($this,o,strSort){
		
		// if no sorting method has been chosen, use the default
		if (!strSort){
			strSort = o.defaultSort
		};
		
		if ($this.val().length >= o.minLength) {
			var strQuery = '/dynamic.aspx?ajaxmode=1&data=' + o.ajaxDataFormat + '&template=' + o.ajaxTemplate + '&sort=' + strSort + '&searchtext=' + $this.val();
			
			$.ajax({
				url: strQuery,
				type: 'get',
				success: function(data){
					
					// collect the position and dimensions of the searchfield
					var inputX = $this.offset().left,
							inputY = $this.offset().top,
							inputHeight = $this.outerHeight(),
							inputWidth = $this.outerWidth();
					
					// position the search container below the searchfield aligned to the left.
					var containerX = inputX + o.offsetX,
							containerY = inputY + inputHeight + o.offsetY;
					
					// If horisontalAlign is set to right, position the search container to be aligned to the right
					if (o.horisontalAlign == 'right'){
						containerX = inputX - (o.containerCss.width - inputWidth);
					}
					
					// set the default container CSS and let the user extend it as needed
					var containerCssObject = $.extend({
						position: 'absolute',
						top: containerY,
						left: containerX,
						zIndex: o.zIndex
					}, o.containerCss);
					
					//if the container do not already exist, create it and append it to the body
					if ($('#' + o.containerId).size() == 0){
						var ajaxSearchBox = $('<div/>',{
							'id': o.containerId,
							css: containerCssObject,
							html: data
						}).css('opacity',0).appendTo('body').fadeTo(200,1);
					} else {
						// if the container already exists, just replace the content with new data
						$('#' + o.containerId).html(data);
					}
					
					// unbind previous events and append new ones.
					// if the user press Esc on the keyboard or click outside the search container, close the search container and unbind the events
					$(document).unbind('.searchSuggest').bind('keyup.searchSuggest click.searchSuggest',function(e){
						if (e.which == 27 || (e.type == 'click' && !$(e.target).closest('#'+o.containerId).size() > 0)) {
							$('#'+o.containerId).remove();
							$(document).unbind('.searchSuggest');
						}
					});
					
					if (o.afterAjax) {
						o.afterAjax();
					}
				}
			});
		} else {
			$('#'+o.containerId).remove();
		}
	}
	
	
	// default values for the options
	$.fn.searchSuggest.defaults = {
		ajaxDataFormat: 'products',
		ajaxTemplate: 'ajaxsearch',
		containerCss: {
			background: '#fff', // IE6-7 bugfix, so elements can't be clicked through the searchcontainer. It can be replaced with a (transparent) background-image instead.
			width: 300
		},
		containerId: 'ajaxSearchSuggestContainer',
		defaultSort: 'pop',
		horisontalAlign: 'right',
		minLength: 2,
		offsetX: 0,
		offsetY: 5,
		timeout: 200,
		zIndex: 1000,
		afterAjax: null
	};

})(jQuery);


function initializeBBQ(){
	
	// to prevent any empty page reloads, test if $ exists
	if (typeof $ == 'undefined') {
		return false;
	}
	
	// cancel the BBQ integration if the confirmation page is loaded
	if ($('#tConfirmation').size() > 0 || $('.shopflowForm, .shopflow').size() > 0) {
  	return false;
  }
	
	// insert the needed classes and default content
	$('#site').addClass('jsBbq');
	$('#siteMain').addClass('jsBbq-content').wrapInner('<div class="jsBbq-default"/>');
	
	// For each .bbq widget, keep a data object containing a mapping of
	// url-to-container for caching purposes.
	$('.jsBbq').each(function(){
		$(this).data('bbq', {
			cache: {
				// If url is '' (no fragment), display this div's content.
				'': $(this).find('.jsBbq-default'),
				'/': $(this).find('.jsBbq-default')
			}
		});
	});
	
	// For all links inside a .jsBbq widget, push the appropriate state onto the
	// history when clicked.
	$('#areaMenu a[href^="/groups/"], #siteBreadcrumb a[href^="/groups/"]').live('click', function(e){
		var state = {},  // Get the id of this .jsBbq widget.
		id = $(this).closest('.jsBbq').attr('id'),  // Get the url from the link's href attribute, stripping any leading #.
		url = $(this).attr('href');
		
		// Set the state!
		state[id] = url;
		$.bbq.pushState(state);
		
		// save the request for the latest clicked url, so the callback knows which to show, even if the return order is not the same as the requested order
		$(this).closest('.jsBbq').data('currentLinkUrl',url);

		// And finally, prevent the default link click behavior by returning false.
		e.preventDefault();
		//return false;

	});
	
	// Bind an event to window.onhashchange that, when the history state changes,
	// iterates over all .bbq widgets, getting their appropriate url from the
	// current state. If that .bbq widget's url has changed, display either our
	// cached content or fetch new content to be displayed.
	$(window).bind('hashchange', function(e){
	
		// Iterate over all .bbq widgets.
		$('.jsBbq').each(function(){
			var that = $(this),   // Get the stored data for this .bbq widget.
			data = that.data('bbq'),   // Get the url for this .bbq widget from the hash, based on the
			// appropriate id property. In jQuery 1.4, you should use e.getState()
			// instead of $.bbq.getState().
			url = $.bbq.getState(that.attr('id')) || '';
			
			// If the url hasn't changed, do nothing and skip to the next .bbq widget.
			if (data.url === url || url == '') {
				return;
			}
			
			// Store the url for the next time around.
			data.url = url;
			
			// Remove .bbq-current class from any previously "current" link(s).
			that.find('a.selected').removeClass('selected');
			
			// Hide any visible ajax content.
			that.find('.jsBbq-content').children(':visible').hide();
			
			// Add .bbq-current class to "current" nav link(s), only if url isn't empty.
			url && that.find('#areaMenu a[href="' + url + '"]').addClass('selected');
			
			// create a url to the dynamic page, to get a faster and smaller page
			// the url could be built up of a dataformat, key and template
			var arrLinkUrl = url.substr(1).split('/');
			var strLinkUrl = '/dynamic.aspx?ajaxmode=1';
			var strBreadcrumbUrl = '/dynamic.aspx?ajaxmode=1&data=breadcrumb';
			
			if (arrLinkUrl[0] && arrLinkUrl[0] != '') {
				strLinkUrl = strLinkUrl + '&data=' + arrLinkUrl[0];
				strBreadcrumbUrl = strBreadcrumbUrl + '&maindata=' + arrLinkUrl[0];
			}
			if (arrLinkUrl[1] && arrLinkUrl[1] != '') {
				strLinkUrl = strLinkUrl + '&key=' + arrLinkUrl[1];
				strBreadcrumbUrl = strBreadcrumbUrl + '&mainkey=' + arrLinkUrl[1];
			}
			if (arrLinkUrl[2] && arrLinkUrl[2] != '') {
				strLinkUrl = strLinkUrl + '&template=' + arrLinkUrl[2];
				strBreadcrumbUrl = strBreadcrumbUrl + '&maintemplate=' + arrLinkUrl[2];
			}
			
			// update the breadcrumb if the URL contains something
			if (url) {
				$('#siteBreadcrumb').load(strBreadcrumbUrl + ' >div');
			}
			
			if (data.cache[url]) {
				// Since the widget is already in the cache, it doesn't need to be
				// created, so instead of creating it again, let's just show it!
				data.cache[url].show();
				
			}
			else {
				// Show "loading" content while AJAX content loads.
				that.find('.jsBbq-loading').show();
				
				// Create container for this url's content and store a reference to it in
				// the cache.
				
				
				//data.cache[url] = $('<div class="jsBbq-item"/>')				// Append the content container to the parent container.
				//.appendTo(that.find('.jsBbq-content'));
				
				$.ajax({
					url: strLinkUrl,
					success: function(strData){
						
						// find the body element  
						var startCut = strData.indexOf('<body');
						var endCut = strData.indexOf('</body>') + 7;
						
						// Create container for this url's content and store a reference to it in
						// the cache.
					
						var strStyle = '';
						if( that.data('currentLinkUrl') != url && typeof that.data('currentLinkUrl') != 'undefined') {
							strStyle = ' style="display: none;"';
						}
					
						// if the new page has content, insert it and scroll to it
						data.cache[url] = $('<div class="jsBbq-item"' + strStyle + '/>')				// Append the content container to the parent container.
						.appendTo(that.find('.jsBbq-content'))
						.html($(strData.substring(startCut, endCut)));
						
						// reactivate the add and subtract features on productlists 
						$('.jsQuantity').quantityAddSubtract();
						
						$('.tProducts').ajaxProductlistpaging({
							beforeAjaxAnimation: function(){
								$('.jsQuantity').quantityAddSubtract();
							}
						});
						
						// Content loaded, hide "loading" content.
						that.find('.jsBbq-loading').hide();
					}
				});
				
			/*
			 // Load external content via AJAX.
			 .load( strLinkUrl + ' >div', function(){
			 // reactivate the add and subtract features on productlists
			 $('.jsQuantity').quantityAddSubtract();
			 
			 $('.tProducts').ajaxProductlistpaging({
			 beforeAjaxAnimation: function(){
			 $('.jsQuantity').quantityAddSubtract();
			 }
			 });
			 
			 // Content loaded, hide "loading" content.
			 that.find( '.jsBbq-loading' ).hide();
			 });
			 */
			}
		});
	});
	
	// Since the event is only triggered when the hash changes, we need to trigger
	// the event now, to handle the hash the page may have loaded with.
	$(window).trigger('hashchange');
}

