/* **************************************************************************** 
// Denison JavaScript Library
//
// 	These are truly _universal_ interaction designs used across all Denison
//	web properties and apps. 
//	(c) Copyright, 2010 Denison University
//
//  $Id: denison.js 108 2011-11-11 14:35:01Z leggn $
**************************************************************************** */

// Below are alphabetical lists of the Denison-approved interaction design 
// patterns. The key names below should match the corresponding callbacks.
//  Design patterns are broken up into 3 groups:
//		* GLOBAL: generic things, always activated at init time (menu, header, etc.)
//		* CLASS: less common, activated by du_registrar if any are found. They're
//			usually just defined by adding a CSS class to their parent element.
//		* ID: unique widgets that generally require detailed arguments. Individual
//			instances are activated by du_registrar, which passes id and args object.
//
//	NOTE: class and id design patterns are only activated by du_registrar(), so
//	they must be "registered", which means that they are listed in a JavaScript
//	array named like their entry in du_designpatterns(_class/_id).
//
var du_designpatterns_global = ['du_hotkeys', 'du_newwindow', 'du_previewbox', 'du_sharethis', 'du_eventwidget',
	'du_highslidealbum', 'du_sidenav', 'du_searchbox', 'du_toggle', 'du_close_this'];
var du_designpatterns_class = ['du_chatwidget', 'du_expandabletext', 'du_tabbedbox'];
var du_designpatterns_id = ['du_slideshow', 'du_embedmedia', 'du_popup'];

// Main init method. Initializes any standard elements, then calls du_registrar
// to look for more.
function du_init() //{{{
{
	// Bootstrap global design patterns
	for (var my_designpattern in du_designpatterns_global)
	{
		var my_instance = du_designpatterns_global[my_designpattern];
		if (typeof my_instance == 'undefined')
		{
			 continue;
		}
		
		// Ensure design pattern has an _impl function before calling
		var my_function_name = my_instance + '_impl';
		if (typeof this[my_function_name] == 'function')
		{
			this[my_function_name]();
		}
	}
	du_registrar();
}//}}}

// Loop through du_designpatterns(_class/_id), and see if any objects with those 
// names exist. If so, loop though all entries, passing them to their eponymous
// callback methods.
function du_registrar() //{{{
{
	// Bootstrap class design patterns
	for (var my_designpattern in du_designpatterns_class)
	{
		var my_instance = du_designpatterns_class[my_designpattern];
		if (typeof this[my_instance] == 'undefined')
		{
			 continue;
		}

		// Ensure design pattern has an _impl function before calling
		var my_function_name = my_instance + '_impl';
		if (typeof this[my_function_name] == 'function')
		{
			this[my_function_name]();
		}
	}

	// Bootstrap id design patterns
	for (var my_designpattern in du_designpatterns_id)
	{
		var my_instance = du_designpatterns_id[my_designpattern];
		if (typeof this[my_instance] == 'undefined')
		{
			 continue;
		}

		// Call _impl on each id design pattern instance
		for (var my_item in this[my_instance])
		{
			// Ensure design pattern has an _impl function before calling
			var my_function_name = my_instance + '_impl';
			if (typeof this[my_function_name] == 'function')
			{
				this[my_function_name](my_item, this[my_instance][my_item]);
			}
		}
	}
}//}}}

/* ****************************************************************************
// Design Pattern Callback Methods
//
//	These methods are responsible for initializing interaction design code. 
//	Their names should correspond to the approved key names as defined in
//	du_designpatterns, e.g., "du_chatwidget" entries are passed to the 
//	"du_chatwidget_impl()" method.
**************************************************************************{{{*/

// Handle pop-up windows
function du_popup_impl(element_id, parameters_object) {//{{{
	// Setup required variables and default parameters
	if (element_id == 'undefined' || element_id == '') return false;//required!
	var element = $('#' + element_id);
	var url = element.attr("href") || '';
	var target = element.attr("target") || '';
	var type = (typeof parameters_object.type == 'undefined') ? 'window' : parameters_object.type;
	var name = (typeof parameters_object.name == 'undefined') ? '_blank' : parameters_object.name;
	var replace = (typeof parameters_object.replace == 'undefined') ? false : parameters_object.replace;
	var i, opt, opt_count, options_string, options_object, dialog_allowed_options, window_allowed_options;
	
	opt_count = propertyCount(parameters_object.options) || 0;
	
	// Bind click event, setup window behaviors based on 'type' parameter
	element.click(function(event) {
		event.preventDefault();
		if (type == 'window'){ // If we want to open new browser window...
			
			window_allowed_options = ['height', 'width', 'top', 'left', 'location', 'menubar', 'resizable', 'scrollbars', 'status', 'titlebar', 'toolbar'];
			
			// build options string
			options_string = '';
			i = 1;
			for (opt in parameters_object.options) {
				if (jQuery.inArray(opt, window_allowed_options) != -1) options_string += opt + '='+ parameters_object.options[opt];
				if (i < opt_count) options_string += ',';
				i++;
			}
			
			window.open(url, name, options_string, replace);
			
		} else if (type == 'dialog') { // If we want a jQuery dialog overlay...
			
			dialog_allowed_options = ['disabled', 'autoOpen', 'buttons', 'buttons', 'closeOnEscape', 'closeText', 'dialogClass', 'draggable', 'height', 'hide', 'maxHeight', 'maxWidth', 'minHeight', 'minWidth', 'modal', 'position', 'resizable', 'show', 'stack', 'title', 'width', 'zIndex'];
			
			// build options object
			options_object = {
				autoOpen: true,
				title: (element.attr('title')) ? element.attr('title') : '',
				dialogClass: 'du-popup'
			};
			parameters_object.options.width = (typeof parameters_object.options.width == 'undefined') ? Math.floor($(window).width()*.75) : parameters_object.options.width;
			parameters_object.options.height = (typeof parameters_object.options.height == 'undefined') ? Math.floor($(window).height()*.75) : parameters_object.options.height;
			
			for (opt in parameters_object.options) {
				if (jQuery.inArray(opt, dialog_allowed_options) != -1) options_object[opt] = parameters_object.options[opt];

			}
			$('<iframe src="' + url + '" />').dialog(options_object).width(options_object.width).height(options_object.height);
		}
		
	});
}//}}}

// Close alert boxes
function du_close_this_impl() {//{{{
	$('.alert .close-this').click(function(){
		$(this).parent().parent('.alert').fadeOut('slow');
		return false;
	});
}//}}}

//search box behaviours
function du_searchbox_impl() {//{{{
	var searchbox_changed = false;

  $("#search_box").change(function () {
			searchbox_changed = true;
  });

	$("#search_box").focus(function () {
		if (!searchbox_changed &&($(this).val() == 'Search')) {
			$(this).val('');
		}
	});

	$("#search_box").blur(function () {
		if ($(this).val() == '') {
			$(this).val('Search');
		} 
	});
}//}}}

// jQuery content toggling; clicking an element with class 'toggle_hit_area'
// will show/hide the next DOM node of class 'toggle_content_area'
function du_toggle_impl() {//{{{
	$(".toggle_content_area").hide();

  $('.toggle_hit_area').click(function(e) {
    e.preventDefault();
		$(this).nextAll(".toggle_content_area").first().slideToggle(350);
  });
}//}}}

// sidenav expandable menu
function du_sidenav_impl() //{{{
{
	$('ul.nestedlist').css('display', 'none');

	$('#side-nav .nohref').click(function(){
		$(this).next('.nestedlist').slideToggle();
		$(this).toggleClass('nohref-open');
		return false;
	});

	$('#page #side-nav #gateway h3').click(function(){
		if ( $(this).parent("#gateway").parent("#side-nav").parent("#page").length == 1 ){
			$(this).next('ul').slideToggle()
		}
		//return false;
	});
}//}}}

// Chat widget setup
function du_chatwidget_impl() //{{{
{
	// Open chat widget window on click
	$('.chat-widget a').click(function(e) {
		window.open($(this).attr('href'), "livechat", "status=0, toolbar=0, menubar=0, resizable=0, scrollbars=0, status=0, titlebar=0, width=190, height=275");
		e.preventDefault();
	});
}//}}}

// Tabbed content boxes
function du_tabbedbox_impl() { //{{{
	$("div.du-tabbedbox div.tabs").each( function() {
		$(this).prepend( function() {
			var tabbed_nav_html = '<ul class="ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all">';
			$(this).children("ul").each( function() {
				tabbed_nav_html += $(this).html();
			});
			tabbed_nav_html += "</ul>";
			$(this).children("ul").remove();
			return tabbed_nav_html;
		});
		$(this).tabs();
	});
}//}}}

function du_slideshow_impl(element_id, parameters_object) //{{{
{
	// Setup required parameters, assign defaults
	if (element_id == undefined) return false; //Must have an ID!
	if (parameters_object.fx == undefined) parameters_object.fx = "fade";
	if (parameters_object.timeout == undefined) parameters_object.timeout = 4000;
	if (parameters_object.type == undefined) parameters_object.type = "denison-slideshow";
	if (parameters_object.click_behavior == undefined) parameters_object.click_behavior = 'none';
	if (parameters_object.autoplay == undefined) parameters_object.autoplay = false;
	if (parameters_object.pause == undefined) parameters_object.pause = false;
	if (parameters_object.autoplay == 0) {
		parameters_object.pause = 0;
	}
	var slidesid = '#' + element_id;
	var navid = '#navigation_' + element_id;

	// Standard slideshow
	if (parameters_object.type == 'denison-slideshow')
	{
		/* {{{ Util Functions */
		// sub-function to facilitate slideshow plugin initialization
		function init_slideshow(slide) {
			// 'after' callback function for Cycle
			function afterCycle(curr, next, opts) {
				var carousel = $('#navigation_' + slide.slideshowid).data('jcarousel');
				var switchcontent = $('#navigation_' + slide.slideshowid).parents('.switchcontent');
				var visible = true;
				if (switchcontent && switchcontent.is('div') && !switchcontent.is(':visible')) {
					visible = false;
				}
				if (carousel && visible) {
					if (opts.nextSlide == 0) {
						carousel.scroll(opts.nextSlide + 1);
					}
					else {
						carousel.scroll(opts.currSlide);
					}
				}
			}

			// Initialize Cycle plugin
			var slidenavid = '#navigation_' + slide.slideshowid;
			$('#' + slide.slideshowid + ' div.slides').cycle({
				fx: slide.transition,
				speed: 'slow',
				timeout: slide.timeout,
				pager: slidenavid,
				cleartype: true,
				cleartypeNoBg: true,
				activePagerClass: 'activeSlide fauxshadow',
				pagerAnchorBuilder: function(idx, slide) {
					// Use src from slide JSON object
					for (var myslide in parameters_object.slides) {
						if (parameters_object.slides[myslide].id == slide.id) {
							return slidenavid + ' li a[href="' + parameters_object.slides[myslide].src + '"]';
						}
					}
					// Otherwise use src from markup (useful for 1st slide since it is not in JSON)
					return slidenavid + ' li a[href="' + $('#' + slide.id + ' div div a img').attr('src') + '"]';
				},
				after: afterCycle
			});

			// Prevent Cycle from autoplaying if necessary
			if (slide.autoplay == 0) {
					$('#' + slide.slideshowid + ' div.slides').cycle('pause');
			}

			// Display "paused" message on mouseover
			if (slide.pause == 1) {
				$('#' + slide.slideshowid).hover(function() {
						$(this).children('div.slides').cycle('pause');
						$(this).children('div.slideshow-controls').show();
						$(this).children('div.slideshow-controls').stop().animate({
							height: '1.5em'
						});
					},
					function() {
						$(this).children('div.slides').cycle('resume');
						$(this).children('div.slideshow-controls').stop().animate({
							height: '0em'
						},
						function() {
							$(this).hide();
						});
					}
				);
			}
		}

		// sub-function to properly scale and setup a loaded slide
		function slide_loaded(slide) {
			$('#' + slide.id + ' img').each(function() {
				// Scale image
				var original_width = this.naturalWidth;
				var original_height = this.naturalHeight;
				if (!original_width || !original_height) {
					var img = new Image();
					img.src = $(this).attr('src');
					original_width = img.width;
					original_height = img.height;
				}
				$my_slide = $('#' + slide.id);
				$(navid).parents('.switchcontent').show();
				var target_width = $my_slide.width();
				var target_height = $my_slide.height();
				$(navid).parents('.switchcontent').hide();
				var scaling_factor = determineImageScalingFactor(original_width, original_height, target_width, target_height);
				var scaled_width = original_width;
				var scaled_height = original_height;
				if (original_width > target_width + 20 || original_height > target_height + 20) {
					scaled_width *= scaling_factor;
					scaled_height *= scaling_factor;
					$(this).width(scaled_width);
					$(this).height(scaled_height);
				}
				if (!($.browser.msie && parseInt($.browser.version) == 6)) {
					$(this).css('margin-top', (target_height - scaled_height) / 2 + 'px');
					// Prevent Webkit from pre-emptively pushing down the first slideshow image
					if (scaled_width == 0 || scaled_height == 0) {
						$(this).css('margin-top', 0);
					}
				}

				// Set up this image for lightbox (if necessary)
				if (slide.click_behavior == 'lightbox') {
					// Scale image in ColorBox
					target_width = Math.min($(window).width() * 0.85, original_width);
					target_height = Math.min($(window).height() * 0.85, original_height);
					scaling_factor = determineImageScalingFactor(original_width, original_height, target_width, target_height);
					$(this).data('scaled_width', original_width * scaling_factor);
					$(this).data('scaled_height', original_height * scaling_factor);

					// Determine caption height for proper ColorBox sizing
					$caption = $(this).parent('a.lightbox').parent().siblings('div.caption-box').clone();
					$caption.css('left', '-2000px');
					$caption.css('width', target_width * 0.85);
					$caption.attr('id', 'cboxLoadedContent');
					$('body').append($caption);
					var caption_height = $caption.height() + 24;
					$caption.remove();

					// Initialize ColorBox plugin
					$(this).parent('a.lightbox').colorbox({
						html: $(this).parent('a.lightbox').parent().parent().html(),
						innerWidth: $(this).data('scaled_width') + 20,
						innerHeight: $(this).data('scaled_height') + caption_height,
						maxWidth: $(this).data('scaled_width') + 20,
						current: 'Image {current} of {total}',
						close: 'CLOSE',
						scalePhotos: false
					});

					// Refresh Colorbox slide pool
					$.colorbox.refresh();
				}
			});

			// Add new slide to slideshow
			$slideshow_opts = $('#' + slide.slideshowid + ' div.slides').data('cycle.opts');
			if ($slideshow_opts) {
				$slideshow_opts.addSlide($('#' + slide.id));
			}

			// Activate new slide's thumbnail in carousel
			$full_image = $('#' + slide.id + ' img');
			$('#navigation_' + slide.slideshowid + ' li.thumb a').each(function() {
				if ($full_image.attr('src').indexOf($(this).attr('href')) != -1) {
					$(this).children('img').css('cursor', 'pointer').css('opacity', '1.0').css('filter', 'alpha(opacity=100)');
				}
			});

			// Bootstrap slideshow when able
			if ($('#' + slide.slideshowid + ' div.slides div.slide').length > 1 && !$slideshow_opts) {
				init_slideshow(slide);
			}
		}

		// sub-function to inject a slide into the DOM
		function load_slide(slideshowid) {
			if (slide_queue.length > 0) {
				// Inject next slide (for current slideshow) into DOM
				var slide = slide_queue.shift();
				$('#' + slide.slideshowid + ' div.slides').append(slide.markup);

				// Continue adding slides from queue
				$('#' + slide.id + ' img').bind('imgload', function() {
					slide_loaded(slide);
					if (slide_queue.length > 0) {
						load_slide(slide.slideshowid);
					}
				}).error(function(){
					if (slide_queue.length > 0) {
						load_slide(slide.slideshowid);
					}
				});
			}
		}

		// sub-function to prepare a slide for DOM injection
		function prepare_slide(slide) {
			var slide_markup = '';
			slide_markup += '<div id = "' + slide.id + '" class="slide">';
			slide_markup += '<div class="slide-img-border">';
			slide_markup += '<div class="slide-img">';
			slide_markup += '<a ' + slide.target + ' href="' + slide.href + '" rel="' + slide.rel + '" class="lightbox">';
			slide_markup += '<img src="' + slide.src + '" alt="' + slide.alt + '" /></a></div>';
			slide_markup += '<div class="caption-box ' + slide.caption_classes + '">' + slide.caption + '</div>';
			slide_markup += '</div></div>';
			return slide_markup;
		}

		// sub-function to add slides to queue for loading into slideshow
		function add_slides() {
			for (var i = 0; i < parameters_object.slides.length; i++) {
				var slide = parameters_object.slides[i];
				if (slide) {
					slide.markup = prepare_slide(slide);
					slide_queue.push(slide);
				}
			}
		}
		/* Util Functions }}} */

		// Initialize jCarousel plugin
		if (parameters_object.navigation) {
			$(navid).parents('.switchcontent').show();
			$(navid).jcarousel({
				scroll: 1
			});
			$(navid).width($(navid).width() * 2); // Carousel width fix for Safari 4
			$(navid + ' li.thumb a img').css('cursor', 'default').css('opacity', '0.4').css('filter', 'alpha(opacity=40)').parent().click(function(event) {
				event.preventDefault();
			});
			$(navid).parents('.switchcontent').hide();
		}

		// Determine overall image click behavior
		if (parameters_object.click_behavior == 'lightbox') {
			// When ColorBox opens, before content is loaded
			$(slidesid).bind('cbox_open', function(){
				// Pause Cycle while ColorBox is open
				$(slidesid + ' div.slides').data('cycle.opts').pause = 0;
			});

			// When ColorBox loads a new slide
			$(slidesid).bind('cbox_load', function(){
				$('#cboxClose').css('filter', '');
				$('#cboxCurrent').css('filter', '');
				$('#cboxNext').hide();
				$('#cboxPrevious').hide();
			});

			// When ColorBox completes loading content
			$(slidesid).bind('cbox_complete', function(){
				// Show Current and Close divs (IE)
				$('#cboxClose').css('filter', 'alpha(opacity=100)');
				$('#cboxCurrent').css('filter', 'alpha(opacity=100)');
				$('#cboxContent').css('filter', 'alpha(opacity=100)');
				$('#cboxLoadedContent').css('filter', 'alpha(opacity=100)');

				// Pause Cycle while ColorBox is open
				$(slidesid + ' div.slides').cycle('pause');

				// Disable links from within ColorBox while we are here!
				$('#cboxLoadedContent div.slide-img a').click(function(e){
					e.preventDefault();
				});

				// Scale images in ColorBox and fit caption
				$current_image = $('#cboxLoadedContent img');
				$my_image = $(slidesid + ' div.slides img').filter(function(index) {
					return $current_image.attr('src').indexOf($(this).attr('src')) != -1;
				});
				$current_image.width($my_image.data('scaled_width'));
				$current_image.height($my_image.data('scaled_height'));
				$current_image.css('margin-top', '0px');

				// Position previous/next arrows appropriately
				$('#cboxPrevious, #cboxNext').css('height', $('#cboxLoadedContent div.slide-img').height());
				$('#cboxPrevious, #cboxNext').css('top', $('#cboxLoadedContent').css('margin-top'));
			});

			// When ColorBox is closed
			$(slidesid).bind('cbox_closed', function(){
				// Resume cycle when ColorBox is closed
				if (parameters_object.autoplay == 1) {
					$slides_collection = $(slidesid + ' div.slides');
					$slides_collection.cycle('resume');
					$slides_collection.data('cycle.opts').pause = 1;
				}
			});
		}

		// Disable full-sized images' '#' + id anchors
		else if (parameters_object.click_behavior == 'link') {
			$(slidesid + ' a').live('click', function(e){
				if ($(this).attr('href') == '') {
					e.preventDefault();
				}
			});
		}
	
		// Disable full-sized images' anchors altogether
		else if (parameters_object.click_behavior == 'none') {
			$(slidesid + ' a').live('click', function(e){
				e.preventDefault();
			});
		}

		// Scale thumbs as they load
		$(slidesid + ' div.slide-navigation li.thumb img').each(function(){
			$default_thumb = $(slidesid + ' div.slide-navigation li.thumb:first');
			$(slidesid).parents('.switchcontent').show();
			var target_width = $default_thumb.width();
			var target_height = $default_thumb.height();
			$(slidesid).parents('.switchcontent').hide();
			$(this).one('imgload', function() {
				var native_width = this.naturalWidth;
				var native_height = this.naturalHeight;
				if (!native_width || !native_height) {
					var img = new Image();
					img.src = $(this).attr('src');
					native_width = img.width;
					native_height = img.height;
				}
				var scaling_factor = determineImageScalingFactor(native_width, native_height, target_width, target_height);
				var scaled_width = native_width;
				var scaled_height = native_height;
				if ((native_width > target_width) || (native_height > target_height)) {
					scaled_width *= scaling_factor;
					scaled_height *= scaling_factor;
					$(this).width(scaled_width);
					$(this).height(scaled_height);
				}
				$(this).css('margin-top', (target_height - scaled_height) / 2 + 'px');
			});
		});

		// Populate and boot slideshow
		$firstslide = $(slidesid + ' div.slides div.slide');
		var firstslide = {id: $firstslide.attr('id'), slideshowid: slidesid.substring(1), click_behavior: parameters_object['click_behavior']};
		var slide_queue = new Array();
		$firstslide.find('img').one('imgload', function(){
			slide_loaded(firstslide);
			add_slides();
			load_slide(slidesid.substring(1));
		});

	}

	// Spotlight slideshow
	else if (parameters_object.type == 'denison-spotlight')
	{
		// Scale images appropriately
		$(slidesid + ' div.slides img').each(function(){
			$(this).one('imgload', function() {
				var original_width = this.naturalWidth;
				var original_height = this.naturalHeight;
				if (!original_width || !original_height) {
					var img = new Image();
					img.src = $(this).attr('src');
					original_width = img.width;
					original_height = img.height;
				}
				$my_slide = $(slidesid + ' div.slide');
				var target_width = $my_slide.width();
				var target_height = $my_slide.height();
				var scaling_factor = determineImageScalingFactor(original_width, original_height, target_width, target_height);
				var scaled_width = original_width;
				var scaled_height = original_height;
				if (original_width > target_width + 20 || original_height > target_height + 20) {
					scaled_width *= scaling_factor;
					scaled_height *= scaling_factor;
					$(this).width(scaled_width);
					$(this).height(scaled_height);
				}
				if (!($.browser.msie && parseInt($.browser.version) == 6)) {
					$(this).css('margin-top', (target_height - scaled_height) / 2 + 'px');
				}
			});
		});

		// Initialize Cycle plugin
		$(slidesid + ' div.slides').cycle({
			fx: 'fade',
			speed: 3000,
			pager: navid,
			cleartype: true,
			cleartypeNoBg: true,
			activePagerClass: 'activeSlide fauxshadow',
			pagerAnchorBuilder: function(idx, slide) {
				return navid + ' li:eq(' + idx + ') a';
			}
		});

		// Prevent Cycle from autoplaying if necessary
		if (parameters_object.autoplay == 0) {
				$(slidesid + ' div.slides').cycle('pause');
		}
	}
} //}}}

function du_newwindow_impl() //{{{
{
	$('a.du-new-window').click(function(){
		window.open(this.href);
		return false;
	});

} //}}}

function du_hotkeys_impl() //{{{
{
	$(document).keyup(function(event) {
		// Make sure the escape key clears stuff away
		if(event.keyCode == 27) {
			$(".du-preview-box-link").qtip("hide");
		}
	});
} //}}}

function du_previewbox_impl() //{{{ 
{
	$('.du-preview-box').hide();

	$('.du-preview-box-link').click(function(e) {
		e.preventDefault();
	});
	
	$('.du-preview-box-link').each(function()
	{
		$(this).qtip({
			content: $('#' + $(this).attr("id") + ' ~ div.du-preview-box' ),
			style: {
				border: {
					width: 1,
					radius: 5
				},
				padding: 10, 
				tip: true,
				name: 'light',
				width: {
					min: 0,
					max: 400
				}
			},
			show: { 
				delay: 10,
				when: { 
					event: 'click'
				},
				effect: {
					type: 'grow',
					length: 350
				}
			},
			hide: { 
				effect: {
					type: 'grow'
				},
				when: { 
					event: 'unfocus' 
				} 
			},
			target: 'center'
		});
	});
} //}}}

function du_sharethis_impl() //{{{
{
	$(document).ready(function()
	{
		if (typeof SHARETHIS == "undefined") return false;

		//Create your sharelet with desired properties and set button element to false
		var object = SHARETHIS.addEntry({}, {button:false});
		//Tie customized button to ShareThis button functionality.
		$('#sharethis').show();
		var element = document.getElementById("sharethis");
		if (element != null)
		{
			object.attachButton(element);
		}
	});
} //}}}

function du_expandabletext_impl() //{{{
{
	$(document).ready(function()
	{
		$('.switchcontent').hide();

		$(".faqWidget").children("a").click(function() 
		{
			$(this).next().slideToggle("normal");
			var image = "/css/arrow-down.png";
			if ($(this).find("img").attr("src") == image)
			{
				image = "/css/arrow-right.png";
			}
			$(this).find("img").attr("src", image);
		});
	});
} //}}}

function du_highslidealbum_impl() //{{{
{
	// Cannot proceed unless Highslide library has loaded
	if (typeof hs == "undefined") return false;

	hs.graphicsDir = "/share/highslide/latest/graphics/";
	hs.showCredits = false;
	hs.zIndexCounter = 30001;
	hs.captionOverlay.fade = 0;
} //}}}

function du_embedmedia_impl(element_id, parameters_object) //{{{
{
	// Setup required parameters, assign defaults
	if (element_id == undefined) return false; //Must have an ID!

	// Set up media options
	$.fn.media.defaults.flashvars = { skin: '/share/mediaplayer/snel.swf' };
	var skin_height = 32; // The player skin's control bar height
	$.fn.media.defaults.flvPlayer = '/share/mediaplayer/mediaplayer.swf';
	$.fn.media.defaults.mp3Player = '/share/mediaplayer/singlemp3player.swf';

	// Instantiate the media item
	$('#' + element_id).media({
		width: parameters_object.width,
		height: parameters_object.height + skin_height,
		autoplay: parameters_object.autoplay,
		src: parameters_object.uri,
		params: { scale: 'tofit', wmode: 'transparent', allowfullscreen: 'true' },
		flashvars: { image: parameters_object.thumbnail }
	});
} //}}}

function du_eventwidget() //{{{
{
	// Nothing to do
} //}}}
//}}}

/* ****************************************************************************
// Helper Functions
//	Miscellaneous but useful functions used by any of the design patterns.
//
**************************************************************************{{{*/

/**
* Toggles an event/calendar widget
* 
* @param String elid ID of widget to toggle
*/
function toggleCalWidget(elid) //{{{
{
	var imid = "#image_" + elid;
	var desid = "#description_" + elid;
	var url = $(imid).css("background-image");
	if (url.substr(-10,4) == 'plus')
	{
		$(imid).css("background-image","url(/css/images/calendar_widget/minus3.png)");
		$(desid).css("display","block");
	}
	else
	{
		$(imid).css("background-image","url(/css/images/calendar_widget/plus3.png)");
		$(desid).css("display","none");
	}
} //}}}

/**
* Calculates scaling factor necessary to fit the selected image within the given width and height.
*
* @param int image_width Native width of image to scale
* @param int image_height Native height of image to scale
* @param int container_width Width of container to scale into
* @param int container_height Height of container to scale into
* @return float scaling_factor Factor by which to scale image
*/
function determineImageScalingFactor(image_width, image_height, container_width, container_height) { //{{{
	var hsf = container_width / image_width;
	var vsf = container_height / image_height;
	
	if (hsf < vsf) {
		var scaling_factor = hsf;
	} else {
		var scaling_factor = vsf;
	}
	
	return scaling_factor;
} //}}}

/*************************************************************************
* nl2br: Convert newlines to break tags.
* @param string str String to process for new lines.
* @param bool is_xhtml Bool that indicates whether we're operating in an XHTML context.
*************************************************************************/
function nl2br (str, is_xhtml) { //{{{
	var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';    
	return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
}
// }}}

/*************************************************************************
* strip_newlines: Remove all newlines from a string, optionally replacing 
* 	with value of replacement parameter.
* @param string str String to process for new lines.
* @param string replacement Optional string that replaces newlines.
*************************************************************************/
function strip_newlines (str, replacement) { //{{{
	var newline = (typeof replacement === 'undefined') ? ' ' : replacement;    
	return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ newline);
}
// }}}

/*************************************************************************
* strip_tags: Strips HTML and PHP tags from a string.
* @param string input String to process for tags.
* @param string allowed Comma-delimited list of allowed tags.
*************************************************************************/
function strip_tags (input, allowed) { // {{{
	allowed = (((allowed || "") + "")
		.toLowerCase()
		.match(/<[a-z][a-z0-9]*>/g) || [])
		.join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
	var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
		commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
	return input.replace(commentsAndPhpTags, '').replace(tags, function($0, $1){
		return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
	});
}
// }}}

/*************************************************************************
* substr: Returns part of a string.
* @param string str Input string.
* @param int start Starting position.
* @param int len Length of return string.
*************************************************************************/
function substr (str, start, len) { //{{{
	// Add: (?) Use unicode.runtime_encoding (e.g., with string wrapped in "binary" or "Binary" class) to
	// allow access of binary (see file_get_contents()) by: charCodeAt(x) & 0xFF (see https://developer.mozilla.org/En/Using_XMLHttpRequest ) or require conversion first?

	var i = 0, allBMP = true, es = 0, el = 0, se = 0, ret = '';
	str += '';
	var end = str.length;

	// BEGIN REDUNDANT
	this.php_js = this.php_js || {};
	this.php_js.ini = this.php_js.ini || {};
	// END REDUNDANT
	switch(
		(this.php_js.ini['unicode.semantics'] && 
			this.php_js.ini['unicode.semantics'].local_value.toLowerCase())) {
		case 'on': // Full-blown Unicode including non-Basic-Multilingual-Plane characters
			// strlen()
			for (i=0; i < str.length; i++) {
				if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i+1))) {
					allBMP = false;
					break;
				}
			}

			if (!allBMP) {
				if (start < 0) {
					for (i = end - 1, es = (start += end); i >= es; i--) {
						if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i-1))) {
							start--;
							es--;
						}
					}
				}
				else {
					var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
					while ((surrogatePairs.exec(str)) != null) {
						var li = surrogatePairs.lastIndex;
						if (li - 2 < start) {
							start++;
						}
						else {
							break;
						}
					}
				}

				if (start >= end || start < 0) {
					return false;
				}
				if (len < 0) {
					for (i = end - 1, el = (end += len); i >= el; i--) {
						if (/[\uDC00-\uDFFF]/.test(str.charAt(i)) && /[\uD800-\uDBFF]/.test(str.charAt(i-1))) {
							end--;
							el--;
						}
					}
					if (start > end) {
						return false;
					}
					return str.slice(start, end);
				}
				else {
					se = start + len;
					for (i = start; i < se; i++) {
						ret += str.charAt(i);
						if (/[\uD800-\uDBFF]/.test(str.charAt(i)) && /[\uDC00-\uDFFF]/.test(str.charAt(i+1))) {
							se++; // Go one further, since one of the "characters" is part of a surrogate pair
						}
					}
					return ret;
				}
				break;
			}
			// Fall-through
		case 'off': // assumes there are no non-BMP characters;
						   //	if there may be such characters, then it is best to turn it on (critical in true XHTML/XML)
		default:
			if (start < 0) {
				start += end;
			}
			end = typeof len === 'undefined' ? end : (len < 0 ? len + end : len + start);
			// PHP returns false if start does not fall within the string.
			// PHP returns false if the calculated end comes before the calculated start.
			// PHP returns an empty string if start and end are the same.
			// Otherwise, PHP returns the portion of the string from start to end.
			return start >= str.length || start < 0 || start > end ? !1 : str.slice(start, end);
	}
	return undefined; // Please Netbeans
}
// }}}

/*************************************************************************
* array_filter: Filters elements from the array via the callback.
* @param array arr Input array.
* @param function func Callback function to call on each alement of arr.
*************************************************************************/
function array_filter (arr, func) { //{{{
	var retObj = {}, k;
	if (typeof(arr) !== 'object') return false;
	// Define a default callback (simple true/false test, like PHP)
	if (typeof(func) === 'function') {
		func = func;
	}
	else {
		func = function(val) {
			if (val) {
				return true;
			} else {
				return false;
			}
		}
	}
    
    for (k in arr) {
        if (func(arr[k])) {
            retObj[k] = arr[k];
        }
    }
    
    return retObj;
} //}}}

/*************************************************************************
* propertyCount: returns count (int) of a JavaScript object's properties.
* @param object obj Input object.
*************************************************************************/
function propertyCount(obj) {//{{{
	var count = 0;
	for (var k in obj) {
		if (obj.hasOwnProperty(k)) {
			++count;
		}
	}
	return count;
} //}}}

// Image Load Plugin {{{
/*************************************************************************
* $.event.special.imgload: Special event for image loads.
* @author Andree Hansson <peolanha@gmail.com>
* @link http://github.com/peol/jquery.imgloaded
**************************************************************************/
(function ($) {
	$.event.special.imgload = {
		add: function (hollaback) {
			if ( this.nodeType === 1 && this.tagName.toLowerCase() === 'img' && this.src !== '' ) {
				// Image is already complete, fire the hollaback (fixes browser issues were cached
				// images isn't triggering the load event)
				if ( this.complete || this.readyState === 4 ) {
					hollaback.handler.apply(this);
				}
				// Check if data URI images is supported, fire 'error' event if not
				else if ( this.readyState === 'uninitialized' && this.src.indexOf('data:') === 0 ) {
					$(this).trigger('error');
				}
				
				else {
					$(this).bind('load', hollaback.handler);
				}
			}
		}
	};
}(jQuery));
// }}}

// jQuery event to catch when something is selected {{{
(function($) {
	$.fn.selected = function(fn) {
		return this.each(function() {
			var clicknum = 0;
			$(this).click(function() {
				clicknum++;
				if (clicknum == 2) {
					clicknum = 0;
					fn();
				}
			});
			$(this).keypress(function(event) {
				if (event.keyCode == '13') {
						event.preventDefault(); 
						clicknum++;
						if (clicknum == 2) {
								clicknum = 0;
								fn();
						}
				}
			});
		});
	}
})(jQuery);
//}}}

/*************************************************************************
* ssn validator: adds validator rule to handle US social security numbers.
*************************************************************************/
(function($) { //}}}
  $.validator.addMethod('ssn', function (value) { 
     var re = /^([0-6]\d{2}|7[0-6]\d|77[0-2])([ \-]?)(\d{2})\2(\d{4})$/; 
     if (!re.test(value)) { return false; } 
     var temp = value; 
     if (value.indexOf("-") != -1) { temp = (value.split("-")).join(""); } 
     if (value.indexOf(" ") != -1) { temp = (value.split(" ")).join(""); } 
     if (temp.substring(0, 3) == "000") { return false; } 
     if (temp.substring(3, 5) == "00") { return false; } 
     if (temp.substring(5, 9) == "0000") { return false; } 
     return true;  
  }, 'Please enter a valid US social security number.'); 
})(jQuery);
//}}}

/* ****************************************************************************
//  MyDenison Channel methods
//
//	These methods are responsible for MyDenison channel interaction, e.g.
//  in-channel navigation, etc.
**************************************************************************{{{*/
/********************************************************************
* channelToggleNavigation: Hide in-channel back button if no history
* @param string channel fname
*********************************************************************/
function channelToggleNavigation(channel) { //{{{
	if ($.browser.msie && parseInt($.browser.version) < 8) {
		// Fix div height issue in IE < 8
		$("div[name='" + channel + "'] div.channel-navigation").css("display", "inline-block");
	}

	// Hide navigation if there is no channel history or if user was deep-linked to a channel page
	// or if address bar contains GET variable 'omit_history=true'
	if (!channelHasHistory(channel) || window.location.href.indexOf('uP_fname') != -1 || window.location.href.indexOf('omit_history=true') != -1) {
		$("div[name='" + channel + "'] div.channel-navigation").hide();
	}

	// Show navigation if there is channel history
	else {
		$("div[name='" + channel + "'] div.channel-navigation").show();

		// Disable Home button if on Home page
		var channelHistory = $.parseJSON($.cookie("channelHistory"));
		for (var i = channelHistory.length - 1; i >= 0; i--) {
			var lastItem = channelHistory[i];
			if (lastItem.channel == channel) {
				if (lastItem.page.indexOf(channel + '/#') != -1) {
					$("div[name='" + channel + "'] div.channel-navigation span.channel-home a").button("option", "disabled", true);
				}
				break;
			}
		}
	}
}
//}}}

/*********************************************************
* channelLoadPage: Initialization on in-channel page load
* @param string channel fname
**********************************************************/
function channelLoadPage(channel) { //{{{
	// Read channel history
	var channelHistory = $.parseJSON($.cookie("channelHistory"));

	// Add current page to channel history
	if (!channelHistory) {
		channelHistory = new Array();
	}
	var lastItem = channelHistory[channelHistory.length - 1];
	if (window.location.href.indexOf(channel) != -1 && (!lastItem || (lastItem && (lastItem.channel != channel || lastItem.page != window.location.href)))) {
		channelHistory.push({channel: channel, page: window.location.href});
		$.cookie("channelHistory", $.toJSON(channelHistory));
	}

	// Render navigation buttons
	$("div[name='" + channel + "'] div.channel-navigation span.channel-back a").button({ icons: {primary:'ui-icon-arrowthick-1-w'}, text: false });
	$("div[name='" + channel + "'] div.channel-navigation span.channel-home a").button({ icons: {primary:'ui-icon-home'}, text: false });

	// Enable/disable Back buttons
	channelToggleNavigation(channel);
}
//}}}

/*************************************************************
* channelHasHistory: Determine if current channel has history
* @param string channel fname
**************************************************************/
function channelHasHistory(channel) { //{{{
	var channelHistory = $.parseJSON($.cookie("channelHistory"));
	for (var historyItem in channelHistory) {
		if (channelHistory[historyItem].channel == channel && channelHistory[historyItem].page.indexOf(channel + '/#') == -1) {
			return true;
		}
	}
	return false;
}
//}}}

/*************************************
* channelBack: In-channel Back button
* @param string channel fname
**************************************/
function channelBack(channel) { //{{{
	var channelHistory = $.parseJSON($.cookie("channelHistory"));
	if (channelHistory && channelHistory.length > 0) {
		var removedCurrentPage = 0;
		for (var i = channelHistory.length - 1; i >= 0; i--) {
			var lastItem = channelHistory[i];
			// Found last visited channel page
			if (lastItem.channel == channel) {
				// Remove currently rendered page from history
				if (!removedCurrentPage) {
					removedCurrentPage = 1;
					channelHistory.splice(i, 1);
					$.cookie("channelHistory", $.toJSON(channelHistory));
					continue;
				}
				// Found last visited page, so move there
				if (removedCurrentPage) {
					channelHistory.splice(i, 1);
					$.cookie("channelHistory", $.toJSON(channelHistory));
					window.location = lastItem.page;
					return;
				}
			}
		}
	}
	// There is no history for this channel but we aren't on the index page, so use the Home button
	window.location = $("div[name='" + channel + "'] div.channel-navigation span.channel-home a").attr("href");
}
//}}}
//}}}

