// JavaScript Document/*Warnings:---------This class requires JQuery, so don't forget to include the JQuery library like this:<script type="text/javascript" src="path/to/jquery-file.9.9.9.js"></script>Remember also that the JQuery include must be before the include of this file.Likewise, you'll need the SWFObject library, which can be included like sewww...<script type="text/javascript" src="/scripts/swfobject.js"></script>General Notes:--------------Created by Action Jackson Gabbard, March 20th, 2005This is an unobtrusive alternative to the procedural JS previously used to achieve discography functionality. This class does the following:1) 	Cleans up funky linking (i.e. links missing a protocol)	and adds the iTunes badge to iTunes links	-------------------------------------------------------	Function(s):		sanitizeLinks	Parameters: 		None	Class Variables: 	buyLinkClass, itunesURL, itunesImageHtml		Usage:	First set the class variable, buyLinkClass, to	the class name you are using for links generated by echotools.	When you call the function, all the links in the page with a class	name matching the one you set will be analyzed and modified (if possible)	depending on whether or not the link is malformed or an iTunes link.		The itunesURL is the URL that will be searched for when the class	looks for iTunes links. If the href attribute of a given link	has that string contained itunesUrl anywhere in it, the link's html will 	be replaced with the itunesImageHtml variable's contents.		2)	Establishes hide/show functionality for lyrics lists	--------------------------------------------------------	Function(s):		setupLyricsControls, expandLyrics, collapseLyrics	Parameters: 		None, 1, 1	Class Variables:  	expandLinkHtml, collapseLinkHtml, 						collapsedLyricsContainerClass, lyricsContainerClass						lyricsControllerClass		Usage:		Warning // For the setupLyricsControls function to work properly the lyricsControllerClass	elements and the lyricsContainerClass elements MUST be in the same order. The lyricsContainerClass	elements may precede the controllers in the HTML, but there must be a one-to-one relationship in 	the same order or the expand/collapse functions will reference the wrong elements. //end Warning		Prior to running the setupLyricsControls, the class variables listed	above will need to be either implemented in your HTML or modified	on the class instance to match your HTML. That is to say,	you can either change your HTML or set the property when you run the page.		Example of Changing the Class Instance Properties:	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -	<html>	...	<script type="text/javascript">		// de is a class instance		var de = new DiscographyEnhancer (true);		// this is the site builder changing the properties of the class instance without modifying the JS file		de.expandLinkHtml = "<strong>I want the user to click this text to open the lyrics</strong>";		de.collapseLinkHtml = "<strong>Once the lyrics are open, the user should click this to close them.</strong>";		de.lyricsContainerClass = "theNameInMyCSSForTheBoxThatHasLyricsInIt";		de.lyricsControllerClass = "theNameInMyCSSForWhateverTheUserClicksToOpenAndCloseTheLyrics";				// etc.			</script>	<body>	...	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -		Once you have configured things so that the JS and HTML/CSS match up, you'll probably want	to customize the expandLyrics and collapseLyrics functions.		These functions accept one parameter, which will be a jQuery object of the HTML element	containing the lyrics (actually the element with the class name which should also contain the	lyrics). By default, the function do jQuery fadeIn and fadeOut functions, respectively. However,	there's plenty of room in the jQuery effects library to almost anything you would like to do with the lyrics container.		Example of Overriding the Class expandLyrics/collapseLyrics function:	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -	<html>	...	<script type="text/javascript">		// de is a class instance		var de = new DiscographyEnhancer (true);		...		de.expandLyrics = function (jqObj) {			jqObj.slideDown(2000);		}		de.collapseLyrics = function (jqObj) {			jqObj.fadeOut(2000);		}		// etc.			</script>	<body>	...	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -		Changing this function this way allows you to use the DiscographyEnhancer class	and still implement the design uniquely. You should practically NEVER have to 	modify the DiscographyEnahncer JS file unless functionality is required that	does not exist in the class (i.e. the ability to have unordered lyrics	container classes and controller classes or something similar).	3)	Embeds and adds external interface functionality to Flash single MP3 players	----------------------------------------------------------------------------	Function(s):		buildPlayers	Parameters: 		None	Class Variables:  	audioPlayerClass, audioPlayerVariables, audioPlayerSwfPath						audioPlayerSwfWidth, audioPlayerSwfHeight		Usage:	Prior to running the buildPlayers function, the HTML will have to be modified slightly	to accomodate the player. The SWF will be embedded in any HTML element that is classed	as whatever audioPlayerClass is set to. So, div, span, td, p, whatever you want can work fine.		Whatever element type you choose, you will have to set the title attribute to be the path to the MP3.		When you've got your HTML sorted out and the title attribute set properly, calling the buildPlayers	function will cause the DE to walk through the HTML, finding any audiPlayerClass element and looking	at their title attribute. If it is not null, the attribute value will be extracted and used in creating	an instance of the single mp3 player class.		The player IDs are loaded into an array and using the default SWF, when the user clicks the play button	in the SWF, the SWF will call an external interface and stop all other players.		To keep the encapsulation of the DE class, your implementation of the DE should also include setting 	up a function called stopPlayers that references your instance of the DE.		Example of Creating a Global function to Stop Players:	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -	<html>	...	<script type="text/javascript">		// de is a class instance		var de = new DiscographyEnhancer (true);		...		function stopTracks (track) {			de.stopTracks(track);		}			</script>	<body>	...	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -		Creating the global this way allows the flash player and other things	to use the DE without needing a reference to it. 4)	Adds Leopard Striping to the Track Listing	----------------------------------------------------------------------------	Function(s):		addStriping	Parameters: 		None	Class Variables:  	leopardStripeElligibiltyClass, leopardStripingAltClass, stripeEvens		Usage:	Prior to running the addStriping function, the rows (or divs!) will have to have a class	assigned to them that either matches the preset value (.leopardMe) in the DE prototype or	set the instance property leopardStripeElligibilityClass to match the class in the html.		Example of Setting the Instance Property for Leopard Striping:	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -	<html>	...	<script type="text/javascript">		// de is a class instance		var de = new DiscographyEnhancer (true);		de.leopardStripingElligibilityClass = "theClassNameImUsingForTheRowsTheTracksAreListedIn"		...	</script>	<body>	...	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -		Once the HTML and JS are in sync, the addStriping function can be called to walk the HTML	adding the striping class (leopardStripingAltClass) to every other element.		The stripeEvens property can be set true or false to stripe either the even rows or the	odd rows.		5)	Adds hover responses to 	----------------------------------------------------------------------------	Function(s):		addHovering	Parameters: 		None	Class Variables:  	hoverElligibilityClass, hoverStateClass		Usage:	Prior to running the addHoveringfunction, the rows (or divs!) will have to have a class	assigned to them that either matches the preset value (.hover) in the DE prototype or	set the instance property hoverElligibilityClass to match the class in the html.		Example of Setting the Instance Property for Leopard Striping:	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -	<html>	...	<script type="text/javascript">		// de is a class instance		var de = new DiscographyEnhancer (true);		de.hoverElligibilityClass = "theClassNameImUsingForTheStuffThatCanBeHoveredOver		...	</script>	<body>	...	- - - - - - - - - - - - - - - - - - - - - - - - - - - - -		Once the HTML and JS are in sync, the addHovering function can be called to walk the HTML	adding the striping class (hoverStateClass) to every other element.*/// constructorfunction DiscographyEnhancer (enableLogging) { 	this.loggingEnabled = Boolean(enableLogging);	this.log("DiscographyEnhancer instantiated"); }// class varsDiscographyEnhancer.prototype.itunesImageHtml = '<img src="/images/itunes_btn.gif" alt="iTunes" title="get album from iTunes" border="0" />';DiscographyEnhancer.prototype.buyLinkClass = "buyLink";DiscographyEnhancer.prototype.itunesUrl = "phobos.apple.com";DiscographyEnhancer.prototype.expandLinkHtml = 'show lyrics';DiscographyEnhancer.prototype.collapseLinkHtml = 'hide lyrics';DiscographyEnhancer.prototype.collapsedLyricsContainerClass = "collapsed";DiscographyEnhancer.prototype.lyricsContainerClass = "lyricsContainer";DiscographyEnhancer.prototype.lyricsControllerClass = "lyricsController";DiscographyEnhancer.prototype.audioPlayerClass = "de_audioPlayer";DiscographyEnhancer.prototype.audioPlayerVariables = [];DiscographyEnhancer.prototype.audioPlayerSwfPath = "/fws/singleMp3Player/echo_single_mp3_button_with_preloader.swf";DiscographyEnhancer.prototype.audioPlayerSwfWidth = 109;DiscographyEnhancer.prototype.audioPlayerSwfHeight = 19;DiscographyEnhancer.prototype.leopardStripeElligibiltyClass = "leopardMe"; // yes.DiscographyEnhancer.prototype.leopardStripingAltClass = "ls_alt";DiscographyEnhancer.prototype.stripeEvens = false;DiscographyEnhancer.prototype.hoverElligibilityClass = "hover";DiscographyEnhancer.prototype.hoverStateClass = "over";// util functionsDiscographyEnhancer.prototype.log = function (str) {	if (this.loggingEnabled) {		try {			console.log(str);		} catch (e) {			// nu'en		}	}}// page manipulation functionsDiscographyEnhancer.prototype.sanitizeLinks = function () {	/* 		This function attempts to clean up sloppily posted URLs.	If an URL has been posted without a protocol, this function	will automagically assign it the HTTP://		If the link is empty, this function will remove it.		If the link's href attribute contains the itunesUrl string,	the link's innerHTML will be replaced with the itunesImageHtml	string.		All links that are picked up by this function are given a target 	of _blank.		*/	var de = this;	$("a."+this.buyLinkClass).each(function (i) {		var link = $(this);		var linkHref = $(this).attr("href") || "";		if (linkHref.length == 0) {			de.log("Removing empty a.buyLink");			link.replaceWith("");			return;		}		if (linkHref.indexOf("http://")==-1) { // if the wizard who entered the link didn't add the protocol...			$(this).attr("href","http://"+linkHref); // add it for him/her.		}		if (linkHref.indexOf(de.itunesUrl)!= -1) { // if it's an itunes link, replace the link text with an iTunes link image.			link.html(de.itunesImageHtml);		}		link.attr("target","_blank"); // for good measure, explicitly set the target to a blank winder	});}DiscographyEnhancer.prototype.collapseAllLyrics = function () {	/* 	This function walks through the HTML looking for elements	classed with the lyricsContainerClass value. Where those are	found, they are collapsed and given the 	collapsedLyricsContainerClass value. The collapseLyricsContainerClass	is used to toggle the expanded/collapsed state when the user clicks the controller.	*/	var de = this;	$("."+de.lyricsContainerClass).each(function (i) {		$(this).hide();		$(this).addClass(de.collapsedLyricsContainerClass);	});}DiscographyEnhancer.prototype.createExpandLyricsLinks = function () {	/*	Walk through all the lyricsControllerClass-ed elements, with each:		1) 	Change the HTML (which probably should be null by default for good unobstrusiveness)			to whatever value is set as the expandLinkHtml		2)	Setup the click event on the controller to call the toggle function		3) 	If the lyricsContainer that corresponds with the controller has no			HTML, empty the controller of HTML so that the user doesn't see it			and do not set up click events	*/	this.log("createExpandLyricsLinks called (setting up lyrics show/hide functionality)");	var de = this;	$("."+this.lyricsControllerClass).each(function (i) {		de.log("Lyrics controller found, number "+i+" "+this.className); 			var lc = $(this);		var targetLyricsContainer = $("."+de.collapsedLyricsContainerClass).get(i); // get the next item in the set		de.log(typeof(targetLyricsContainer));				if ($(targetLyricsContainer).html().length) {			de.log("Enabled hiding and showing of the lyrics for lyrics controller "+i+".");			lc.html('<a href="#">'+de.expandLinkHtml+'</a>');			$(lc.children("a").get(0)).click(function () {				de.toggleLyricsContainer(targetLyricsContainer,this);				return false; 			});		} else {			lc.empty();		}	});}DiscographyEnhancer.prototype.toggleLyricsContainer = function (targ,caller) {	// just in case, make them jQuery objects 	targ = $(targ);	caller = $(caller);		// if the container is already collapsed, 	if (targ.hasClass(this.collapsedLyricsContainerClass)) {		// change the controller to show the collapseLinkHtml		caller.html(this.collapseLinkHtml);		// remove the flag-class from the container		targ.removeClass(this.collapsedLyricsContainerClass);		// expand the lyrics container using the expandFunction		this.expandLyrics(targ);	} else {		// change the controller to show the collapseLinkHtml		caller.html(this.expandLinkHtml);		// add the flag-class to the lyrics container		targ.addClass(this.collapsedLyricsContainerClass);		// collapse the container using the collapseLyrics function		this.collapseLyrics(targ);	}}DiscographyEnhancer.prototype.setupLyricsControls = function () {	/*	Function to call to do all the lyrics container/controller setup work	*/	this.collapseAllLyrics();	this.createExpandLyricsLinks();}DiscographyEnhancer.prototype.expandLyrics = function (jqObj) {	// this method should be overrided per implementation, all	// it needs to do is show the lyrics for base functionality	jqObj.fadeIn("slow");}DiscographyEnhancer.prototype.collapseLyrics = function (jqObj) {	// see the preceding, but go the other way	jqObj.fadeOut("slow");}// flash handling functionsDiscographyEnhancer.prototype.players = []; // an array to store the player IDs inDiscographyEnhancer.prototype.stopTracks = function(track) {	/* External interface function that walks the players array	calling the stopTrack method of each that has an id	other than that passed */	this.log("Stopping all tracks but "+track);					for (var i =0 ; i < this.players.length ; i ++) {		if( this.players[i] != track) {			this.thisMovie(this.players[i]).stopTrack();		}	}				}DiscographyEnhancer.prototype.thisMovie = function (movieName) {	// Ye oade Macromedia thisMovie method	if (navigator.appName.indexOf("Microsoft") != -1) {		return window[movieName];	} else {		return document[movieName];	}}DiscographyEnhancer.prototype.buildPlayers = function () {	/* 	Function responsible for walking the HTML looking for elements	class as audioPlayerClass. If the elements found have a non-empty	title attribute, it will have a SWF embedded in it that attempts	to load and play whatever path is in the title attribute.	*/	var de = this;	de.log("Building Flash audio players...");	$("."+this.audioPlayerClass).each(function (i) {		var ap = $(this);		if (ap.attr("title") != undefined && ap.attr("title") != null) {			this.id = "player"+i;			var track = "p"+i;			de.players.push(track);			de.log("Building player "+track+" for URL "+ap.attr("title")+".");			var fo = new SWFObject(de.audioPlayerSwfPath, track, de.audioPlayerSwfWidth, de.audioPlayerSwfHeight, "7", "#ffffff");			fo.addVariable("mp3",ap.attr("title"));			fo.addVariable("trackNum",track);			fo.addParam("wmode","transparent");			fo.addParam("allowScriptAccess","always");			for (var i in de.audioPlayerVariables) {				fo.addVariable(de.audioPlayerVariables[i].param,de.audioPlayerVariables[i].value);			}			fo.write(this.id);		}	});	de.log(this.players.length+" players added. ("+this.players.join(",")+").");}// add leopard striping to the tracksDiscographyEnhancer.prototype.addStriping = function () {	var de = this;	$("."+this.leopardStripeElligibiltyClass).each(function (i) {		var container = $(this);		var stripeDecider;		if (de.stripeEvens) {						stripeDecider = function (c) {				if (c % 2 == 1) { // if it's an odd numbered row					return true;				} else {					return false;				}			}					} else {						stripeDecider = function (c) {				if (c % 2 == 0) { // if it's an even numbered row					return true;				} else {					return false;				}			}					}				if (stripeDecider(i)) {			de.log("Adding striping to row "+i+".");			container.addClass(de.leopardStripingAltClass);		}	});}// add hover abilityDiscographyEnhancer.prototype.addHovering = function () {	var de = this;	$("."+this.hoverElligibilityClass).each(function (i) {				$(this).hover(			function () { 				de.doHover($(this)); 			},			function () { 				de.doUnhover($(this)); 			} 		);			});}DiscographyEnhancer.prototype.doHover = function (jqObj) {	jqObj.addClass(this.hoverStateClass);}DiscographyEnhancer.prototype.doUnhover = function (jqObj) {	jqObj.removeClass(this.hoverStateClass);}