Archive for the ‘ jQuery’ Category

Fight Score Single Page UI App

I asked a question on Twitter last week about jQuery and async calls (thanks @jeefy & @codepo8) – a few folks asked me to post the code I was working on so here it goes.

The app is an HTML page for scoring boxing and MMA fights.

You can play with the UI here : http://koscience.com/apps/scorecard/

This is a mile stone of code samples I’ve posted recently on Dynamic jQuery Accordions and Event Handler Delegation for Dynamic Content.

scorecard-1

The events represented in the application’s UI are data driven by the retrieved JSON file (sample data below)


data.json


[
    {
        "bluefighter"       : "Fighter 1",
        "blueimage"         : "images/silhouette.jpg",
        "redfighter"        : "Fighter 2",
        "redimage"          : "images/silhouette.jpg",
        "numberofrounds"    : "10"
    },
    {
        "bluefighter"       : "Fighter 3",
        "blueimage"         : "images/silhouette.jpg",
        "redfighter"        : "Fighter 4",
        "redimage"          : "images/silhouette.jpg",
        "numberofrounds"    : "3"
    },
    {
        "bluefighter"       : "Fighter 5",
        "blueimage"         : "images/silhouette.jpg",
        "redfighter"        : "Fighter 6",
        "redimage"          : "images/silhouette.jpg",
        "numberofrounds"    : "5"
    },
    {
        "bluefighter"       : "Fighter 7",
        "blueimage"         : "images/silhouette.jpg",
        "redfighter"        : "Fighter 8",
        "redimage"          : "images/silhouette.jpg",
        "numberofrounds"    : "12"
    }
]

You’ll note that the number of bouts in the event are not determined until run time.

Also, for each bout, the number of rounds is not fixed. Each is determined by an entry in the JSON data.

Since each bout will have a VARIABLE number of inputs and outputs, if you think about the mechanics of accomplishing this, it’s an interesting HTML issue.

There are lots of other, perhaps more elegant ways I might have done this (whenever I post code someone comments to tell me I suck :) )

I didn’t use MVC, Event Delegation, or an Object Oriented Data Model. Each of those that I considered just didn’t seem to offer the value in return for the added abstraction or complexity.

(I used to do some work for the SIG Sauer Firearms Academy where we used the acronym SIG = Simple Is Good !)

So I took the simple route. The loop that iterates through the JSON data dynamically adds each content section and since I’m not using event delegation, each “bout” (accordion tab) gets it’s own version of the event handling code to score the bout.

Since the number of bouts is relatively small (less than 15) the performance hit won’t ever be an issue, but if we were dealing with a large number of sections we would need to use delegation of some sort to attach a single event handler at the containing element or document level to avoid unnecessarily duplicating code by hooking the click event for every object / button.


index.html


<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fight Card</title>
<link rel="stylesheet"
 href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link rel="stylesheet" href="css/style.css">
<style>
	/* IE has layout problems when sorting accordion items  */
	.group { zoom: 1 }
</style>

<script>

//-----------------------------------------------------------------------+
// addBout() - Add a single node to the accordion
//-----------------------------------------------------------------------+

function addBout(bout, key){

//-----------------------------------------------------------------------+
// Build the display element for the the scoring display based on the 
// number of rounds for this bout.
//-----------------------------------------------------------------------+
var round_numbers = "";
var round_scores = "";
var round_totals = "";
for (var i=0; i < bout.numberofrounds; i++)
{
	round_numbers += "<td id='roundTitle_" + (key+1) + "_" + (i+1) 
				   + "'>Round #" + (i+1) + "</td>";
	round_scores  += "<td id='bout_" +  (key+1) + "_round_" + (i+1) 
				   + "_roundbox'><span id='bout_" + (key+1) + "_round_" 
				   + (i+1) +  "_blueScore'>00</span>-<span id='bout_" 
				   + (key+1) + "_round_" + (i+1) 
				   +  "_redScore'>00</span></td>";

	round_totals  += "<td id='bout_" +  (key+1) + "_round_" + (i+1) 
				   + "_totalbox'><span id='bout_" + (key+1) + "_round_" 
				   + (i+1) +  "_blueTotal'>00</span>-<span id='bout_" 
				   + (key+1) + "_round_" + (i+1) 
				   +  "_redTotal'>00</span></td>";
}

//-----------------------------------------------------------------------+
// Build the display element for the rest of the current bout.
//-----------------------------------------------------------------------+
var bout =
	"<div id=\"bout_" + (key+1) + "\" class=\"group\">" +
		"<span class=\"handle\"> " +
			"<div class=\"table\">" +
				"<div class=\"row\">" +
					"<span class=\"cell width33pct align-left\">" +
						"<strong>" + bout.bluefighter + "</strong>" +
					"</span>" +
					"<span class=\"cell align-center valign-middle\">" +
						"vs." +
					"</span>" +
					"<span class=\"cell width33pct align-right\">" +
					"<strong>" + bout.redfighter + "</strong>" +
					"</span>" +
				"</div>" +
			"</div>" +
		"</span>" +
		"<div>" +
			"<div class=\"table\">" +
				"<div class=\"row\">" +
					"<span class=\"cell width150 align-center\">" +
						"<img src=\"" + bout.blueimage 
						+ "\" alt=\"\" style='border:2px solid blue'>"
						+ "<br />" +
					"</span>" +
					"<span id=\"test\" "  +
					"class=\"cell align-center valign-middle\">" +
						"<h2>" +
						"<span id='roundLabel_" + (key+1) + 
						"'>Round</span><br />" +
						"<span id=\"current_round_" + (key+1) + 
						"\">1</span><br />" +
						"<input type='number' id='blueRoundScore_" + 
						(key+1) + "' size='2' max='10' min='0' " +
						"value='10' " +
						"style='border:2px solid blue'>" +
						"<input type='number' id='redRoundScore_"  + 
						(key+1) + "' size='2' max='10' min='0' " +
						"value='10' style='border:2px solid red'>" +
						"<br /><br />" +
						"<button id='btnScore_" + (key+1)  + 
						"' class='score_button'>Score</button>" +
						"<span id='boutResult_" + (key+1)+ "' " +
						"class='boutResultClass'></span>" +
						"</h2>" +
					"</span>" +
					"<span class=\"cell width150 align-center\">" +
						"<img src=\"" + bout.redimage + "\" alt=\"\" " +
						"style='border:2px solid red'>" +
					"</span>" +
				"</div>" +
			"</div>" +
			"<div align=\"center\">" +
				"<table>" +
					"<tr>" +
						round_numbers +
					"</tr>" +
					"<tr>" +
						round_scores +
					"</tr>" +
					"<tr>" +
						round_totals +
					"</tr>" +
				"</table>" +
			"</div>" +
		"</div>" +
	"</div>";
return bout;
}

//--------------------------------------------------------------------------+
// DOM READY()
//--------------------------------------------------------------------------+
$(function() {
	//----------------------------------------------------------------------+
	// Wire up the accordion div, specify the header/handle and make 
	// the sections sortable.
	//----------------------------------------------------------------------+
	$( "#accordion" )
			.accordion({
				header: "> .group > .handle",
				heightStyle: "content"
			})
			.sortable({
				axis: "y",
				handle: ".handle",
				stop: function( event, ui ) {
					// IE doesn't register the blur event when sorting
					// so trigger focusout handler to remove .ui-state-focus
					ui.item.children(".handle").triggerHandler("focusout");
				}
			});

	//----------------------------------------------------------------------+
	// Fetch the JSON configuration file and use it to build the 
	// accordion sections
	//----------------------------------------------------------------------+
	$.getJSON("data/event.json", function (data) {
		$.each(data, function (key, val) {
			$("#accordion").append(addBout(val, key)).accordion("refresh");

			//--------------------------------------------------------------+
			// For each bout - dynamically bind the score button event 
			// handler to this dynamic method
			//--------------------------------------------------------------+
			var BlueTotal = 0;
			var RedTotal = 0;
			var BoutNumber = (key+1);
			$( "#boutResult_"+(BoutNumber) ).hide();
			$( "#btnScore_"+(BoutNumber) ).click(function() {
			// Get the current round number.
			var currentRound = 0;
			currentRound = $("#current_round_" + (BoutNumber)).text();

			//----------------------------------------------------------+
			// Fetch the score for the current round and post to 
			// scoring table
			//----------------------------------------------------------+
			var BlueScoreThisRound =  $("#blueRoundScore_" + 
				                         BoutNumber).val();
			var RedScoreThisRound =   $("#redRoundScore_" + 
				                         BoutNumber).val();
			$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
			   "_blueScore").text(BlueScoreThisRound);
			$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
				"_redScore").text(RedScoreThisRound);
			// If it's the FIRST round.
			if (currentRound == 1) {
				$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
				  "_blueTotal").text(BlueScoreThisRound);
				$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
					"_redTotal").text(RedScoreThisRound);
				BlueTotal = BlueScoreThisRound;
				RedTotal = RedScoreThisRound;
			}
			// All except the first round.
			else {

				 BlueTotal = parseInt($("#bout_" + (BoutNumber) + 
				 	"_round_" + (currentRound-1)  + 
				 	"_blueTotal").text());
				 BlueTotal += parseInt(BlueScoreThisRound);
				 $("#bout_" + (BoutNumber) + 
				 	"_round_" + (currentRound)  + 
				 	"_blueTotal").text(BlueTotal);

				 RedTotal = parseInt($("#bout_" + (BoutNumber) + 
				 	"_round_" + (currentRound-1)  + 
				 	"_redTotal").text());
				 RedTotal += parseInt(RedScoreThisRound);
				 $("#bout_" + (BoutNumber) + "_round_" + 
				 	(currentRound)  + "_redTotal").text(RedTotal);
			}

			// Blue wins the round.
			if (BlueScoreThisRound < RedScoreThisRound) {
			  $("#bout_" + (BoutNumber) + "_round_" + currentRound + 
			  	"_roundbox").css("border", "2px solid blue");
			}
			// Red wins the round.
			else if (BlueScoreThisRound > RedScoreThisRound) {
				$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
					"_roundbox").css("border", "2px solid red");
			}
			// Round is a draw
			else if (BlueScoreThisRound == RedScoreThisRound) {
				$("#bout_" + (BoutNumber) + "_round_" + currentRound + 
					"_roundbox").css("border", "2px solid green");
			}

			// Who's winning the fight after this round ?
			if(RedTotal == BlueTotal) {
				$("#roundTitle_" + (BoutNumber) + "_" + 
					currentRound).css("border", "2px solid green");
				$("#bout_" + (BoutNumber) + "_round_" + 
					currentRound + 
					"_totalbox").css("border", "2px solid green");
			}
			if(BlueTotal < RedTotal) {
			   $("#roundTitle_" + (BoutNumber) + "_" + 
			   	currentRound).css("border", "2px solid red");
			   $("#bout_" + (BoutNumber) + "_round_" + 
			   	currentRound + "_totalbox").css("border", "2px solid red");
			}
			if (BlueTotal > RedTotal) {
				$("#roundTitle_" + (BoutNumber) + "_" + 
					currentRound).css("border", "2px solid blue");
				$("#bout_" + (BoutNumber) + "_round_" + 
					currentRound + 
					"_totalbox").css("border", "2px solid blue");
			}


			//----------------------------------------------------------+
			// Reset current round scores t 10-10, hide button if all 
			// rounds scored
			//----------------------------------------------------------+
			$("#blueRoundScore_" + BoutNumber).val(10);
			$("#redRoundScore_" + BoutNumber).val(10);
			currentRound++;
			// The fight is over.
			if (currentRound > val.numberofrounds) {
				$("#blueRoundScore_" + BoutNumber).val(BlueTotal);
				$("#blueRoundScore_" + BoutNumber).prop('disabled', true);
				$("#redRoundScore_" + BoutNumber).val(RedTotal);
				$("#redRoundScore_" + BoutNumber).prop('disabled', true);
				$( "#btnScore_"+(BoutNumber)).hide();
				if(BlueTotal == RedTotal) {
					$( "#boutResult_"+(BoutNumber) ).text("<<<  Draw  >>>");
				}
				else if (BlueTotal > RedTotal) {
					$( "#boutResult_"+(BoutNumber) ).html("&larr; WINNER");
					$( "#boutResult_"+
						(BoutNumber) ).css("background-color", "blue");
					$( "#boutResult_"+(BoutNumber) ).css("color", "white");
				}
				else if (RedTotal > BlueTotal) {
					$( "#boutResult_"+(BoutNumber) ).html("WINNER &rarr;");
					$( "#boutResult_"+
						(BoutNumber) ).css("background-color", "red");
					$( "#boutResult_"+(BoutNumber) ).css("color", "white");
				}

				$( "#roundLabel_"+(BoutNumber) ).text("Fight");
				$( "#current_round_"+(BoutNumber) ).text("Complete");
				$( "#boutResult_"+(BoutNumber) ).show();

			}
			// On to another round.
			else {
				$("#current_round_" + (key+1)).text(currentRound);
			}
			});
		});

	});

});

</script>
</head>

<body>
<div id="main-container" class="main-container">
	<div id="accordion">
	<!-- Bouts will be inserted here -->
	</div>


</div>
</body>
</html>


style.css


body {
	font-family: "Trebuchet MS","Helvetica","Arial","Verdana","sans-serif";
	font-size: 62.5%;
    background: url('../images/background.gif') repeat;
}

td {
    text-align: center;
    vertical-align: middle;
    border: 1px solid black;
    width: 90px;
}

input {
    text-align: center;
}


.main-container {
    width: 96%;
    max-width: 960px;
    min-width: 300px;
    height: 100px;
    position: absolute;
    top:20px;
    left: 0;
    right: 0;
    margin: auto;
}

/*---------------------------------------*/
/*   Styles for table like formatting.   */
/*---------------------------------------*/
.table {
    display: table;
    width: 100%;
}
.row {
    display: table-row;
}
.cell {
    display: table-cell;
}

/*---------------------------------------*/
/*   Styles for score area.              */
/*---------------------------------------*/

.score_box {
    border:2px solid black;
    padding: 5px;
}

.score_button {
    width: 130px;
    height: 40px;
}

.boutResultClass {
    border: 2px solid black;
    background-color: yellow;
    padding-left: 20px;
    padding-right: 20px;
    padding-top: 10px;
    padding-bottom: 10px;
}

/*---------------------------------------*/
/*   Styles for width specification.     */
/*---------------------------------------*/
.width150 {
    width: 150px;
}

.width33pct {
    width: 33%;
}

.width34pct {
    width: 34%;
}

.width100pct {
    width: 100%;
}

/*---------------------------------------*/
/*   Styles for various alignments.      */
/*---------------------------------------*/
.align-right {
    text-align: right;
}
.align-left {
    text-align: left;
}
.align-center {
    text-align: center;
}

.valign-middle {
    vertical-align: middle;
}

/*-------------------------------------------*/
/*   Style overrides for jQuery accordion.   */
/*-------------------------------------------*/
.ui-state-default{
    background-color: #3173a5;
    background-image: none;
}
.ui-accordion-header {
    background-color: #333333;
    color:  #BDC3C7;
    font-size: 16;
}

.ui-accordion-header.ui-state-active {
    background-color: #BDC3C7;
    color: #333333;
    font-size: 16;
}

You can download a .zip file without the funky source code formatting that my blog requires [ HERE ]


So what’s next ?

Next I’ll create services so that users can all score an event in real time, collaboratively while the event is happening live.

After I create the services and update the client to send scores, I’ll build iOS, Android & Windows clients !

PATTERN : Dynamic HTML elements and context specific access via jQuery.

I think all web developers have a love / hate relationship with HTML.

HTML is by it’s very definition a MARKUP language. Markup meaning it’s category of utility is to represent data. HTML is fine for representing data for display but less perfect when it comes to use case’s that require the manipulation of that data once it’s been rendered. As a “markup” language, the semantic values are not innately coupled to the markup items that contain them.

The software development industry continuously invents new ways to improve the ways that we solve this relationship problem.

I’ve been working on a Single Page HTML App which will be data drivel via a JSON file retrieved from the server.

That JSON file will contain some number of data records and the app will need to create one container div for each of those records. Since the number of those records is variable, the App won’t know until run time (when the page is loaded) how many of those sections will be needed.

Each of the container divs will contain HTML elements that will need to be manipulated at run time. (In fact, in the app I’m forking on each container will have a variable number elements, also dynamically created at run-time but for the purposes of this sample we’ll keep thinks to a single level of dynamics).

Dynamically naming elements can quickly become complex with dynamic HTML pages and, as is always there are many ways to solve the same problem. (Yes, I know, your way is better :) )

Here is a documented example of ONE way to accomplish this content / data dynamics using jQuery (though you could use the same pattern in plain old JavaScript).

It takes very little code, but several people have questioned me as to how to do this so I thought I’m post a sample.


<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script 
   src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">
</script>

<script>
var numberOfDivsToCreate=10;
//---------------------------------------------------------------------------+
// Note the id of the div to be appended is dynamic comprised of the static
// text "DIV-NUMBER" and the current value of the i variable of the for loop.
//---------------------------------------------------------------------------+
$(document).ready(function () {
    //-----------------------------------------------------------------------+
    // for loop create the total number of divs specified in the
    // numberOfDivsToCreate variable above. In a real app this would probably
    // be determined at run time
    //-----------------------------------------------------------------------+
    for (var i = 1; i <= numberOfDivsToCreate; i++) {
        $('#mainpage').append("<div id='DIV-NUMBER-" + i + "'>" +
                          "<span id='myInput''>" + i + "</span>" +
                          "&nbsp;--&nbsp;<span id='myVal'></span></div>");
    }

    //-----------------------------------------------------------------------+
    // Use the jQuery.on method to specify an event delegate to handle click
    // events for all the divs inside the div who's id="mainpage"
    // Note: In this sample we arw catching the click event for ALL divs
    // In a real world app your mainpage div may contain divs that you do not
    // want to fire a click event on, In that case use a class on the
    // clickable ones and change the jQuery selector below accordingly,
    //-----------------------------------------------------------------------+
    $( "#mainpage" ).on( "click", "div", function() {

        //-------------------------------------------------------------------+
        // The for loop above creates 10 divs and this click event delegate
        // is a SINGLE method (lives in memory once) to handle the click
        // events for all 10 divs
        // $this is a jQuery reference to the element that threw the click
        // event in our case one of the 10 divs
        //-------------------------------------------------------------------+
        // we'll use .find() to look inside the div that threw the click
        // event and find the elements we wish to manipulate, note that
        // those elements are not dynamically named (myInput & myVal) so
        // there are 10 of each on our page and we are using context to
        // determine which to manipulate
        //-------------------------------------------------------------------+
        // jQuery .find() can be a performance problem if misused, make
        // sure to minimise the find scope as much as possible
        //-------------------------------------------------------------------+
        var MyInput =$(this).find("#myInput");
        var MyDisplay = $(this).find("#myVal");

        //-------------------------------------------------------------------+
        // Note that MyInput & MyDisplay local variables that we cast to
        // jQuery objects on order to access the text properties via jQuery
        // syntax.
        //-------------------------------------------------------------------+
        $(MyDisplay).text($(this).attr("id") +
                "   -   Value = " + $(MyInput).text())
    });
});
</script>

</head>
<body>
<div id="mainpage">
</div>
</body>
</html>

jQuery Accordion and Dynamic Runtime Population

As I mentioned in my last post I’m playing with this idea of building a scoring application for boxing / mma events.

I want it to be a single page web application that scales to fit phones, tablets, etc.

An event contains a number of “bouts” and each bout will be a section in a jQuery UI Accordion control.

However, as is often the case, there are a couple of real world conditions that I couldn’t find documentation of sample to demonstrate.

1.) Event event can have a different number bouts.

This means that the accordion sections have to be dynamically built at runtime in the html page.

2.) The order of the events can change right up to the event time.

This means that the USER needs to be able to change the visual sequence of the bouts.

3.) The click-able header needs to be multiple elements.

All the demos I found assumed the headers were simple H3 elements.

You can play with a working version by clicking the image below.

Note that you can not only open and close the “bouts” but you can re-order them using drag-n-drop on the title bars.

– - – THIS IS A UI PROTOTYPE – - –

FightCard- 001

Built this way I can now add the AJAX logix fo recieve a JSON package that contains the event detail and use that data to populate the event.

Here is the code as it exists so far.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Fight Card</title>
<link rel="stylesheet"
 href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<link rel="stylesheet" href="css/style.css">
<style>
    /* IE has layout problems when sorting  */
    .group { zoom: 1 }
</style>

<script>

//-----------------------------------------------------------+
// addBout() - Add a single node to the accordian
// TODO: add JSON object as input parameter and build the
//       bout with that data,
//-----------------------------------------------------------+
function addBout(){
    var bout =
        "<div class=\"group\">" +
            "<span class=\"handle\"> " +
                "<div class=\"table\">" +
                    "<div class=\"row\">" +
                        "<span class=\"cell width33pct align-left\">" +
                            "<strong>Blue Fighter TBD</strong>" +
                        "</span>" +
                        "<span class=\"cell align-center valign-middle\">" +
                            "vs." +
                        "</span>" +
                        "<span class=\"cell width33pct align-right\">" +
                            "<strong>Red Fighter TBD</strong>"+
                        "</span>" +
                    "</div>" +
                "</div>" +
            "</span>" +
            "<div>" +
                "<div class=\"table\">" +
                    "<div class=\"row\">" +
                        "<span class=\"cell width150 align-center\">" +
                            "<img src=\"images/silhouette.jpg\" alt=\"\">" +
                        "</span>" +
                        "<span class=\"cell align-center valign-middle\">" +
                            "Round<br />0" +
                        "</span>" +
                        "<span class=\"cell width150 align-center\">" +
                            "<img src=\"images/silhouette.jpg\" alt=\"\">" +
                        "</span>" +
                    "</div>" +
                "</div>" +
                "<span>" +
                "Mauris mauris ante, blandit et, ultrices a, suscipit , " +
                "quam. Integerut neque. <br /> Vivamus nisi metus molestie" +
                " vel, gravida in, condimentum sit amet, nunc. Nam a nibh." +
                "accordion .ui- iconDonec suscipit eros. Nam mi. Proin " +
                " viverra leo ut odio. Curabitur malesuada. Vestibulum a " +
                "velit eu ante scelerisque vulputate." +
                "</span>" +
            "</div>" +
        "</div>";
    return bout;
}

$(function() {

    $( "#accordion" )
            .accordion({
                header: "> .group > .handle",
                heightStyle: "content"
            })
            .sortable({
                axis: "y",
                handle: ".handle",
                stop: function( event, ui ) {
                    // IE doesn't register the blur event when sorting
                    // so trigger focusout handler to remove .ui-state-focus
                    ui.item.children(".handle").triggerHandler("focusout");
                }
            });

    //-----------------------------------------------------------+
    // This for loop is just for testing.
    // The real app will iterate a JSON collection and send
    // each bout node to the addBout function for insertion
    // into the accordion
    //-----------------------------------------------------------+
    for (var i=0;i<5;i++) {
    $("#accordion").append(addBout()).accordion("refresh");
    }
});
</script>

</head>

<body>

<div id="main-container" class="main-container">
    <div id="accordion">
    <!-- Bouts will be inserted here -->
    </div>
</div>

</body>
</html>

And the CSS

body {
   font-family: "Trebuchet MS","Helvetica","Arial","Verdana","sans-serif";
   font-size: 62.5%;
   background: url('../images/background.gif') repeat;
}

.main-container {
    width: 96%;
    max-width: 960px;
    min-width: 300px;
    height: 100px;
    position: absolute;
    top:20px;
    left: 0;
    right: 0;
    margin: auto;
}

/*---------------------------------------*/
/*   Styles for table like formatting.   */
/*---------------------------------------*/
.table {
    display: table;
    width: 100%;
}
.row {
    display: table-row;
}
.cell {
    display: table-cell;
}

/*---------------------------------------*/
/*   Styles for width specification.     */
/*---------------------------------------*/
.width150 {
    width: 150px;
}

.width33pct {
    width: 33%;
}

.width34pct {
    width: 34%;
}

/*---------------------------------------*/
/*   Styles for various alignments.      */
/*---------------------------------------*/
.align-right {
    text-align: right;
}
.align-left {
    text-align: left;
}
.align-center {
    text-align: center;
}

.valign-middle {
    vertical-align: middle;
}

/*-------------------------------------------*/
/*   Style overrides for jQuery accordion.   */
/*-------------------------------------------*/
.ui-state-default{
    background-color: #3173a5;
    background-image: none;body {
	font-family: "Trebuchet MS","Helvetica","Arial","Verdana","sans-serif";
	font-size: 62.5%;
    background: url('../images/background.gif') repeat;
}

.main-container {
    width: 96%;
    max-width: 960px;
    min-width: 300px;
    height: 100px;
    position: absolute;
    top:20px;
    left: 0;
    right: 0;
    margin: auto;
}

/*---------------------------------------*/
/*   Styles for table like formatting.   */
/*---------------------------------------*/
.table {
    display: table;
    width: 100%;
}
.row {
    display: table-row;
}
.cell {
    display: table-cell;
}

/*---------------------------------------*/
/*   Styles for width specification.     */
/*---------------------------------------*/
.width150 {
    width: 150px;
}

.width33pct {
    width: 33%;
}

.width34pct {
    width: 34%;
}

/*---------------------------------------*/
/*   Styles for various alignments.      */
/*---------------------------------------*/
.align-right {
    text-align: right;
}
.align-left {
    text-align: left;
}
.align-center {
    text-align: center;
}

.valign-middle {
    vertical-align: middle;
}

/*-------------------------------------------*/
/*   Style overrides for jQuery accordion.   */
/*-------------------------------------------*/
.ui-state-default{
    background-color: #3173a5;
    background-image: none;
}
.ui-accordion-header {
    background-color: #333333;
    color:  #BDC3C7;
    font-size: 16;
}

.ui-accordion-header.ui-state-active {
    background-color: #BDC3C7;
    color: #333333;
    font-size: 16;
}

}
.ui-accordion-header {
    background-color: #333333;
    color:  #BDC3C7;
    font-size: 16;
}

.ui-accordion-header.ui-state-active {
    background-color: #BDC3C7;
    color: #333333;
    font-size: 16;
}