diff --git a/.zfproject.xml b/.zfproject.xml
index 9c7094a03..36b2bb957 100644
--- a/.zfproject.xml
+++ b/.zfproject.xml
@@ -76,6 +76,10 @@
+
+
+
+
@@ -89,7 +93,9 @@
-
+
+
+
@@ -237,6 +243,12 @@
+
+
+
+
+
+
@@ -279,6 +291,7 @@
+
diff --git a/application/configs/ACL.php b/application/configs/ACL.php
index c625fd01e..092957d14 100644
--- a/application/configs/ACL.php
+++ b/application/configs/ACL.php
@@ -18,6 +18,7 @@ $ccAcl->add(new Zend_Acl_Resource('library'))
->add(new Zend_Acl_Resource('plupload'))
->add(new Zend_Acl_Resource('schedule'))
->add(new Zend_Acl_Resource('api'))
+ ->add(new Zend_Acl_Resource('nowplaying'))
->add(new Zend_Acl_Resource('search'));
/** Creating permissions */
@@ -25,6 +26,7 @@ $ccAcl->allow('guest', 'index')
->allow('guest', 'login')
->allow('guest', 'error')
->allow('guest', 'library')
+ ->allow('guest', 'nowplaying')
->allow('guest', 'search')
->allow('guest', 'api')
->allow('host', 'plupload')
diff --git a/application/configs/navigation.php b/application/configs/navigation.php
index d727466b6..6ccfe4c96 100644
--- a/application/configs/navigation.php
+++ b/application/configs/navigation.php
@@ -48,8 +48,8 @@ $pages = array(
array(
'label' => 'Now Playing',
'module' => 'default',
- 'controller' => 'Schedule',
- 'action' => 'view-playlist'
+ 'controller' => 'Nowplaying',
+ 'action' => 'index'
),
array(
'label' => 'Schedule',
diff --git a/application/controllers/NowplayingController.php b/application/controllers/NowplayingController.php
new file mode 100644
index 000000000..fb30479de
--- /dev/null
+++ b/application/controllers/NowplayingController.php
@@ -0,0 +1,35 @@
+_helper->getHelper('AjaxContext');
+ $ajaxContext->addActionContext('get-data-grid-data', 'json')->initContext();
+ }
+
+ public function indexAction()
+ {
+ $this->view->headScript()->appendFile('/js/playlist/playlist.js','text/javascript');
+ $this->view->headScript()->appendFile('/js/datatables/js/jquery.dataTables.min.js','text/javascript');
+ $this->view->headScript()->appendFile('/js/progressbar/jquery.progressbar.min.js','text/javascript');
+
+ $this->view->headLink()->appendStylesheet('/css/datatables/css/demo_page.css');
+ $this->view->headLink()->appendStylesheet('/css/datatables/css/demo_table.css');
+
+ $this->_helper->viewRenderer->setResponseSegment('nowplaying');
+ }
+
+ public function getDataGridDataAction()
+ {
+ $this->view->entries = Application_Model_Nowplaying::GetDataGridData();
+ }
+
+
+}
+
+
+
+
+
diff --git a/application/controllers/ScheduleController.php b/application/controllers/ScheduleController.php
index adceae712..300a693e1 100644
--- a/application/controllers/ScheduleController.php
+++ b/application/controllers/ScheduleController.php
@@ -193,13 +193,18 @@ class ScheduleController extends Zend_Controller_Action
}
}
+/*
public function viewPlaylistAction()
{
$this->view->headScript()->appendFile('/js/playlist/playlist.js','text/javascript');
$this->view->headScript()->appendFile('/js/progressbar/jquery.progressbar.min.js','text/javascript');
$this->_helper->viewRenderer->setResponseSegment('nowplaying');
+
+ this->_helper->actionStack('', '');
+
}
+*/
public function getCurrentPlaylistAction()
{
diff --git a/application/models/Nowplaying.php b/application/models/Nowplaying.php
new file mode 100644
index 000000000..c704c9a0f
--- /dev/null
+++ b/application/models/Nowplaying.php
@@ -0,0 +1,43 @@
+"Date"),
+ array("sTitle"=>"Start"),
+ array("sTitle"=>"End"),
+ array("sTitle"=>"Duration"),
+ array("sTitle"=>"Song"),
+ array("sTitle"=>"Artist"),
+ array("sTitle"=>"Album"),
+ array("sTitle"=>"Creator"),
+ array("sTitle"=>"Playlist"));
+ $rows = array();
+
+ foreach ($previous as $item){
+ array_push($rows, array(substr($item["starts"], 0, strpos($item["starts"], " ")), $item["starts"], $item["ends"], $item["clip_length"], $item["track_title"], $item["artist_name"],
+ $item["album_title"], "x" , "y"));
+ }
+
+
+ foreach ($current as $item){
+ array_push($rows, array($item["starts"], $item["starts"], $item["ends"], $item["clip_length"], $item["track_title"], $item["artist_name"],
+ $item["album_title"], "x" , "y"));
+ }
+
+ foreach ($next as $item){
+ array_push($rows, array($item["starts"], $item["starts"], $item["ends"], $item["clip_length"], $item["track_title"], $item["artist_name"],
+ $item["album_title"], "x" , "y"));
+ }
+
+ return array("columnHeaders"=>$columnHeaders, "rows"=>$rows);
+ }
+
+}
+
diff --git a/application/models/Schedule.php b/application/models/Schedule.php
index 2ed61f8b9..715006b2c 100644
--- a/application/models/Schedule.php
+++ b/application/models/Schedule.php
@@ -477,7 +477,7 @@ class Schedule {
"next"=>Schedule::GetNextItems($timeNow));
}
- private static function GetPreviousItems($timeNow, $prevCount = 1){
+ public static function GetPreviousItems($timeNow, $prevCount = 1){
global $CC_CONFIG, $CC_DBC;
$sql = "SELECT * FROM $CC_CONFIG[scheduleTable] st, $CC_CONFIG[filesTable] ft"
." WHERE (st.ends < TIMESTAMP '$timeNow')"
@@ -488,7 +488,7 @@ class Schedule {
return $rows;
}
- private static function GetCurrentlyPlaying($timeNow){
+ public static function GetCurrentlyPlaying($timeNow){
global $CC_CONFIG, $CC_DBC;
$sql = "SELECT *, pt.name as playlistName FROM $CC_CONFIG[scheduleTable] st, $CC_CONFIG[filesTable] ft, $CC_CONFIG[playListTable] pt"
@@ -500,7 +500,7 @@ class Schedule {
return $rows;
}
- private static function GetNextItems($timeNow, $nextCount = 1) {
+ public static function GetNextItems($timeNow, $nextCount = 1) {
global $CC_CONFIG, $CC_DBC;
$sql = "SELECT * FROM $CC_CONFIG[scheduleTable] st, $CC_CONFIG[filesTable] ft"
." WHERE (st.starts > TIMESTAMP '$timeNow')"
diff --git a/application/views/scripts/nowplaying/get-data-grid-data.phtml b/application/views/scripts/nowplaying/get-data-grid-data.phtml
new file mode 100644
index 000000000..789c0e6d5
--- /dev/null
+++ b/application/views/scripts/nowplaying/get-data-grid-data.phtml
@@ -0,0 +1,3 @@
+entries;
+?>
diff --git a/application/views/scripts/nowplaying/index.phtml b/application/views/scripts/nowplaying/index.phtml
new file mode 100644
index 000000000..cccadd021
--- /dev/null
+++ b/application/views/scripts/nowplaying/index.phtml
@@ -0,0 +1,52 @@
+
+
+
+
Show:
+
Playlist:
+
Host:
+
+
+
+
Previous:
+
Current:
+
Upcoming:
+
+
+
+ Start:
+ End:
+ |
+
+
+
diff --git a/public/css/datatables/css/demo_page.css b/public/css/datatables/css/demo_page.css
new file mode 100644
index 000000000..bee7b0d99
--- /dev/null
+++ b/public/css/datatables/css/demo_page.css
@@ -0,0 +1,93 @@
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * General page setup
+ */
+#dt_example {
+ font: 80%/1.45em "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
+ margin: 0;
+ padding: 0;
+ color: #333;
+ background-color: #fff;
+}
+
+
+#dt_example #container {
+ width: 800px;
+ margin: 30px auto;
+ padding: 0;
+}
+
+
+#dt_example #footer {
+ margin: 50px auto 0 auto;
+ padding: 0;
+}
+
+#dt_example #demo {
+ margin: 30px auto 0 auto;
+}
+
+#dt_example .demo_jui {
+ margin: 30px auto 0 auto;
+}
+
+#dt_example .big {
+ font-size: 1.3em;
+ font-weight: bold;
+ line-height: 1.6em;
+ color: #4E6CA3;
+}
+
+#dt_example .spacer {
+ height: 20px;
+ clear: both;
+}
+
+#dt_example .clear {
+ clear: both;
+}
+
+#dt_example pre {
+ padding: 15px;
+ background-color: #F5F5F5;
+ border: 1px solid #CCCCCC;
+}
+
+#dt_example h1 {
+ margin-top: 2em;
+ font-size: 1.3em;
+ font-weight: normal;
+ line-height: 1.6em;
+ color: #4E6CA3;
+ border-bottom: 1px solid #B0BED9;
+ clear: both;
+}
+
+#dt_example h2 {
+ font-size: 1.2em;
+ font-weight: normal;
+ line-height: 1.6em;
+ color: #4E6CA3;
+ clear: both;
+}
+
+#dt_example a {
+ color: #0063DC;
+ text-decoration: none;
+}
+
+#dt_example a:hover {
+ text-decoration: underline;
+}
+
+#dt_example ul {
+ color: #4E6CA3;
+}
+
+.css_right {
+ float: right;
+}
+
+.css_left {
+ float: left;
+}
\ No newline at end of file
diff --git a/public/css/datatables/css/demo_table.css b/public/css/datatables/css/demo_table.css
new file mode 100644
index 000000000..3bc043379
--- /dev/null
+++ b/public/css/datatables/css/demo_table.css
@@ -0,0 +1,538 @@
+/*
+ * File: demo_table.css
+ * CVS: $Id$
+ * Description: CSS descriptions for DataTables demo pages
+ * Author: Allan Jardine
+ * Created: Tue May 12 06:47:22 BST 2009
+ * Modified: $Date$ by $Author$
+ * Language: CSS
+ * Project: DataTables
+ *
+ * Copyright 2009 Allan Jardine. All Rights Reserved.
+ *
+ * ***************************************************************************
+ * DESCRIPTION
+ *
+ * The styles given here are suitable for the demos that are used with the standard DataTables
+ * distribution (see www.datatables.net). You will most likely wish to modify these styles to
+ * meet the layout requirements of your site.
+ *
+ * Common issues:
+ * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
+ * no conflict between the two pagination types. If you want to use full_numbers pagination
+ * ensure that you either have "example_alt_pagination" as a body class name, or better yet,
+ * modify that selector.
+ * Note that the path used for Images is relative. All images are by default located in
+ * ../images/ - relative to this CSS file.
+ */
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables features
+ */
+
+.dataTables_wrapper {
+ position: relative;
+ min-height: 302px;
+ clear: both;
+ _height: 302px;
+ zoom: 1; /* Feeling sorry for IE */
+}
+
+.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 250px;
+ height: 30px;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px 0;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 14px;
+ background-color: white;
+}
+
+.dataTables_length {
+ width: 40%;
+ float: left;
+}
+
+.dataTables_filter {
+ width: 50%;
+ float: right;
+ text-align: right;
+}
+
+.dataTables_info {
+ width: 60%;
+ float: left;
+}
+
+.dataTables_paginate {
+ width: 44px;
+ * width: 50px;
+ float: right;
+ text-align: right;
+}
+
+/* Pagination nested */
+.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next {
+ height: 19px;
+ width: 19px;
+ margin-left: 3px;
+ float: left;
+}
+
+.paginate_disabled_previous {
+ background-image: url('../images/back_disabled.jpg');
+}
+
+.paginate_enabled_previous {
+ background-image: url('../images/back_enabled.jpg');
+}
+
+.paginate_disabled_next {
+ background-image: url('../images/forward_disabled.jpg');
+}
+
+.paginate_enabled_next {
+ background-image: url('../images/forward_enabled.jpg');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables display
+ */
+table.display {
+ margin: 0 auto;
+ clear: both;
+ width: 100%;
+
+ /* Note Firefox 3.5 and before have a bug with border-collapse
+ * ( https://bugzilla.mozilla.org/show%5Fbug.cgi?id=155955 )
+ * border-spacing: 0; is one possible option. Conditional-css.com is
+ * useful for this kind of thing
+ *
+ * Further note IE 6/7 has problems when calculating widths with border width.
+ * It subtracts one px relative to the other browsers from the first column, and
+ * adds one to the end...
+ *
+ * If you want that effect I'd suggest setting a border-top/left on th/td's and
+ * then filling in the gaps with other borders.
+ */
+}
+
+table.display thead th {
+ padding: 3px 18px 3px 10px;
+ border-bottom: 1px solid black;
+ font-weight: bold;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+table.display tfoot th {
+ padding: 3px 18px 3px 10px;
+ border-top: 1px solid black;
+ font-weight: bold;
+}
+
+table.display tr.heading2 td {
+ border-bottom: 1px solid #aaa;
+}
+
+table.display td {
+ padding: 3px 10px;
+}
+
+table.display td.center {
+ text-align: center;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables sorting
+ */
+
+.sorting_asc {
+ background: url('../images/sort_asc.png') no-repeat center right;
+}
+
+.sorting_desc {
+ background: url('../images/sort_desc.png') no-repeat center right;
+}
+
+.sorting {
+ background: url('../images/sort_both.png') no-repeat center right;
+}
+
+.sorting_asc_disabled {
+ background: url('../images/sort_asc_disabled.png') no-repeat center right;
+}
+
+.sorting_desc_disabled {
+ background: url('../images/sort_desc_disabled.png') no-repeat center right;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables row classes
+ */
+table.display tr.odd.gradeA {
+ background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+ background-color: #eeffee;
+}
+
+table.display tr.odd.gradeC {
+ background-color: #ddddff;
+}
+
+table.display tr.even.gradeC {
+ background-color: #eeeeff;
+}
+
+table.display tr.odd.gradeX {
+ background-color: #ffdddd;
+}
+
+table.display tr.even.gradeX {
+ background-color: #ffeeee;
+}
+
+table.display tr.odd.gradeU {
+ background-color: #ddd;
+}
+
+table.display tr.even.gradeU {
+ background-color: #eee;
+}
+
+
+tr.odd {
+ background-color: #E2E4FF;
+}
+
+tr.even {
+ background-color: white;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Misc
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.dataTables_scrollBody {
+ *margin-top: -1px;
+}
+
+.top, .bottom {
+ padding: 15px;
+ background-color: #F5F5F5;
+ border: 1px solid #CCCCCC;
+}
+
+.top .dataTables_info {
+ float: none;
+}
+
+.clear {
+ clear: both;
+}
+
+.dataTables_empty {
+ text-align: center;
+}
+
+tfoot input {
+ margin: 0.5em 0;
+ width: 100%;
+ color: #444;
+}
+
+tfoot input.search_init {
+ color: #999;
+}
+
+td.group {
+ background-color: #d1cfd0;
+ border-bottom: 2px solid #A19B9E;
+ border-top: 2px solid #A19B9E;
+}
+
+td.details {
+ background-color: #d1cfd0;
+ border: 2px solid #A19B9E;
+}
+
+
+.example_alt_pagination div.dataTables_info {
+ width: 40%;
+}
+
+.paging_full_numbers {
+ width: 400px;
+ height: 22px;
+ line-height: 22px;
+}
+
+.paging_full_numbers span.paginate_button,
+ .paging_full_numbers span.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+.paging_full_numbers span.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers span.paginate_button:hover {
+ background-color: #ccc;
+}
+
+.paging_full_numbers span.paginate_active {
+ background-color: #99B3FF;
+}
+
+table.display tr.even.row_selected td {
+ background-color: #B0BED9;
+}
+
+table.display tr.odd.row_selected td {
+ background-color: #9FAFD1;
+}
+
+
+/*
+ * Sorting classes for columns
+ */
+/* For the standard odd/even */
+tr.odd td.sorting_1 {
+ background-color: #D3D6FF;
+}
+
+tr.odd td.sorting_2 {
+ background-color: #DADCFF;
+}
+
+tr.odd td.sorting_3 {
+ background-color: #E0E2FF;
+}
+
+tr.even td.sorting_1 {
+ background-color: #EAEBFF;
+}
+
+tr.even td.sorting_2 {
+ background-color: #F2F3FF;
+}
+
+tr.even td.sorting_3 {
+ background-color: #F9F9FF;
+}
+
+
+/* For the Conditional-CSS grading rows */
+/*
+ Colour calculations (based off the main row colours)
+ Level 1:
+ dd > c4
+ ee > d5
+ Level 2:
+ dd > d1
+ ee > e2
+ */
+tr.odd.gradeA td.sorting_1 {
+ background-color: #c4ffc4;
+}
+
+tr.odd.gradeA td.sorting_2 {
+ background-color: #d1ffd1;
+}
+
+tr.odd.gradeA td.sorting_3 {
+ background-color: #d1ffd1;
+}
+
+tr.even.gradeA td.sorting_1 {
+ background-color: #d5ffd5;
+}
+
+tr.even.gradeA td.sorting_2 {
+ background-color: #e2ffe2;
+}
+
+tr.even.gradeA td.sorting_3 {
+ background-color: #e2ffe2;
+}
+
+tr.odd.gradeC td.sorting_1 {
+ background-color: #c4c4ff;
+}
+
+tr.odd.gradeC td.sorting_2 {
+ background-color: #d1d1ff;
+}
+
+tr.odd.gradeC td.sorting_3 {
+ background-color: #d1d1ff;
+}
+
+tr.even.gradeC td.sorting_1 {
+ background-color: #d5d5ff;
+}
+
+tr.even.gradeC td.sorting_2 {
+ background-color: #e2e2ff;
+}
+
+tr.even.gradeC td.sorting_3 {
+ background-color: #e2e2ff;
+}
+
+tr.odd.gradeX td.sorting_1 {
+ background-color: #ffc4c4;
+}
+
+tr.odd.gradeX td.sorting_2 {
+ background-color: #ffd1d1;
+}
+
+tr.odd.gradeX td.sorting_3 {
+ background-color: #ffd1d1;
+}
+
+tr.even.gradeX td.sorting_1 {
+ background-color: #ffd5d5;
+}
+
+tr.even.gradeX td.sorting_2 {
+ background-color: #ffe2e2;
+}
+
+tr.even.gradeX td.sorting_3 {
+ background-color: #ffe2e2;
+}
+
+tr.odd.gradeU td.sorting_1 {
+ background-color: #c4c4c4;
+}
+
+tr.odd.gradeU td.sorting_2 {
+ background-color: #d1d1d1;
+}
+
+tr.odd.gradeU td.sorting_3 {
+ background-color: #d1d1d1;
+}
+
+tr.even.gradeU td.sorting_1 {
+ background-color: #d5d5d5;
+}
+
+tr.even.gradeU td.sorting_2 {
+ background-color: #e2e2e2;
+}
+
+tr.even.gradeU td.sorting_3 {
+ background-color: #e2e2e2;
+}
+
+
+/*
+ * Row highlighting example
+ */
+.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
+ background-color: #ECFFB3;
+}
+
+.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
+ background-color: #E6FF99;
+}
+
+.ex_highlight_row #example tr.even:hover {
+ background-color: #ECFFB3;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_1 {
+ background-color: #DDFF75;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_2 {
+ background-color: #E7FF9E;
+}
+
+.ex_highlight_row #example tr.even:hover td.sorting_3 {
+ background-color: #E2FF89;
+}
+
+.ex_highlight_row #example tr.odd:hover {
+ background-color: #E6FF99;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_1 {
+ background-color: #D6FF5C;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_2 {
+ background-color: #E0FF84;
+}
+
+.ex_highlight_row #example tr.odd:hover td.sorting_3 {
+ background-color: #DBFF70;
+}
+
+
+/*
+ * KeyTable
+ */
+table.KeyTable td {
+ border: 3px solid transparent;
+}
+
+table.KeyTable td.focus {
+ border: 3px solid #3366FF;
+}
+
+table.display tr.gradeA {
+ background-color: #eeffee;
+}
+
+table.display tr.gradeC {
+ background-color: #ddddff;
+}
+
+table.display tr.gradeX {
+ background-color: #ffdddd;
+}
+
+table.display tr.gradeU {
+ background-color: #ddd;
+}
+
+div.box {
+ height: 100px;
+ padding: 10px;
+ overflow: auto;
+ border: 1px solid #8080FF;
+ background-color: #E5E5FF;
+}
diff --git a/public/css/datatables/css/demo_table_jui.css b/public/css/datatables/css/demo_table_jui.css
new file mode 100644
index 000000000..b81a1cf99
--- /dev/null
+++ b/public/css/datatables/css/demo_table_jui.css
@@ -0,0 +1,513 @@
+/*
+ * File: demo_table_jui.css
+ * CVS: $Id$
+ * Description: CSS descriptions for DataTables demo pages
+ * Author: Allan Jardine
+ * Created: Tue May 12 06:47:22 BST 2009
+ * Modified: $Date$ by $Author$
+ * Language: CSS
+ * Project: DataTables
+ *
+ * Copyright 2009 Allan Jardine. All Rights Reserved.
+ *
+ * ***************************************************************************
+ * DESCRIPTION
+ *
+ * The styles given here are suitable for the demos that are used with the standard DataTables
+ * distribution (see www.datatables.net). You will most likely wish to modify these styles to
+ * meet the layout requirements of your site.
+ *
+ * Common issues:
+ * 'full_numbers' pagination - I use an extra selector on the body tag to ensure that there is
+ * no conflict between the two pagination types. If you want to use full_numbers pagination
+ * ensure that you either have "example_alt_pagination" as a body class name, or better yet,
+ * modify that selector.
+ * Note that the path used for Images is relative. All images are by default located in
+ * ../images/ - relative to this CSS file.
+ */
+
+
+/*
+ * jQuery UI specific styling
+ */
+
+.paging_two_button .ui-button {
+ float: left;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+.paging_full_numbers .ui-button {
+ padding: 2px 6px;
+ margin: 0;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+.ui-buttonset .ui-button {
+ margin-right: -0.1em !important;
+}
+
+.paging_full_numbers {
+ width: 350px !important;
+}
+
+.ui-toolbar {
+ padding: 5px;
+}
+
+.dataTables_paginate {
+ width: auto;
+}
+
+.dataTables_info {
+ padding-top: 3px;
+}
+
+table.display thead th {
+ padding: 3px 0px 3px 10px;
+ cursor: pointer;
+ * cursor: hand;
+}
+
+div.dataTables_wrapper .ui-widget-header {
+ font-weight: normal;
+}
+
+
+/*
+ * Sort arrow icon positioning
+ */
+table.display thead th div.DataTables_sort_wrapper {
+ position: relative;
+ padding-right: 20px;
+ padding-right: 20px;
+}
+
+table.display thead th div.DataTables_sort_wrapper span {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+ right: 0;
+}
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * Everything below this line is the same as demo_table.css. This file is
+ * required for 'cleanliness' of the markup
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables features
+ */
+
+.dataTables_wrapper {
+ position: relative;
+ min-height: 302px;
+ _height: 302px;
+ clear: both;
+}
+
+.dataTables_processing {
+ position: absolute;
+ top: 0px;
+ left: 50%;
+ width: 250px;
+ margin-left: -125px;
+ border: 1px solid #ddd;
+ text-align: center;
+ color: #999;
+ font-size: 11px;
+ padding: 2px 0;
+}
+
+.dataTables_length {
+ width: 40%;
+ float: left;
+}
+
+.dataTables_filter {
+ width: 50%;
+ float: right;
+ text-align: right;
+}
+
+.dataTables_info {
+ width: 50%;
+ float: left;
+}
+
+.dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+
+/* Pagination nested */
+.paginate_disabled_previous, .paginate_enabled_previous, .paginate_disabled_next, .paginate_enabled_next {
+ height: 19px;
+ width: 19px;
+ margin-left: 3px;
+ float: left;
+}
+
+.paginate_disabled_previous {
+ background-image: url('../images/back_disabled.jpg');
+}
+
+.paginate_enabled_previous {
+ background-image: url('../images/back_enabled.jpg');
+}
+
+.paginate_disabled_next {
+ background-image: url('../images/forward_disabled.jpg');
+}
+
+.paginate_enabled_next {
+ background-image: url('../images/forward_enabled.jpg');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables display
+ */
+table.display {
+ margin: 0 auto;
+ width: 100%;
+ clear: both;
+ border-collapse: collapse;
+}
+
+table.display tfoot th {
+ padding: 3px 0px 3px 10px;
+ font-weight: bold;
+ font-weight: normal;
+}
+
+table.display tr.heading2 td {
+ border-bottom: 1px solid #aaa;
+}
+
+table.display td {
+ padding: 3px 10px;
+}
+
+table.display td.center {
+ text-align: center;
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables sorting
+ */
+
+.sorting_asc {
+ background: url('../images/sort_asc.jpg') no-repeat center right;
+}
+
+.sorting_desc {
+ background: url('../images/sort_desc.jpg') no-repeat center right;
+}
+
+.sorting {
+ background: url('../images/sort_both.jpg') no-repeat center right;
+}
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables row classes
+ */
+table.display tr.odd.gradeA {
+ background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+ background-color: #eeffee;
+}
+
+
+
+
+table.display tr.odd.gradeA {
+ background-color: #ddffdd;
+}
+
+table.display tr.even.gradeA {
+ background-color: #eeffee;
+}
+
+table.display tr.odd.gradeC {
+ background-color: #ddddff;
+}
+
+table.display tr.even.gradeC {
+ background-color: #eeeeff;
+}
+
+table.display tr.odd.gradeX {
+ background-color: #ffdddd;
+}
+
+table.display tr.even.gradeX {
+ background-color: #ffeeee;
+}
+
+table.display tr.odd.gradeU {
+ background-color: #ddd;
+}
+
+table.display tr.even.gradeU {
+ background-color: #eee;
+}
+
+
+tr.odd {
+ background-color: #E2E4FF;
+}
+
+tr.even {
+ background-color: white;
+}
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Misc
+ */
+.dataTables_scroll {
+ clear: both;
+}
+
+.top, .bottom {
+ padding: 15px;
+ background-color: #F5F5F5;
+ border: 1px solid #CCCCCC;
+}
+
+.top .dataTables_info {
+ float: none;
+}
+
+.clear {
+ clear: both;
+}
+
+.dataTables_empty {
+ text-align: center;
+}
+
+tfoot input {
+ margin: 0.5em 0;
+ width: 100%;
+ color: #444;
+}
+
+tfoot input.search_init {
+ color: #999;
+}
+
+td.group {
+ background-color: #d1cfd0;
+ border-bottom: 2px solid #A19B9E;
+ border-top: 2px solid #A19B9E;
+}
+
+td.details {
+ background-color: #d1cfd0;
+ border: 2px solid #A19B9E;
+}
+
+
+.example_alt_pagination div.dataTables_info {
+ width: 40%;
+}
+
+.paging_full_numbers span.paginate_button,
+ .paging_full_numbers span.paginate_active {
+ border: 1px solid #aaa;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ padding: 2px 5px;
+ margin: 0 3px;
+ cursor: pointer;
+ *cursor: hand;
+}
+
+.paging_full_numbers span.paginate_button {
+ background-color: #ddd;
+}
+
+.paging_full_numbers span.paginate_button:hover {
+ background-color: #ccc;
+}
+
+.paging_full_numbers span.paginate_active {
+ background-color: #99B3FF;
+}
+
+table.display tr.even.row_selected td {
+ background-color: #B0BED9;
+}
+
+table.display tr.odd.row_selected td {
+ background-color: #9FAFD1;
+}
+
+
+/*
+ * Sorting classes for columns
+ */
+/* For the standard odd/even */
+tr.odd td.sorting_1 {
+ background-color: #D3D6FF;
+}
+
+tr.odd td.sorting_2 {
+ background-color: #DADCFF;
+}
+
+tr.odd td.sorting_3 {
+ background-color: #E0E2FF;
+}
+
+tr.even td.sorting_1 {
+ background-color: #EAEBFF;
+}
+
+tr.even td.sorting_2 {
+ background-color: #F2F3FF;
+}
+
+tr.even td.sorting_3 {
+ background-color: #F9F9FF;
+}
+
+
+/* For the Conditional-CSS grading rows */
+/*
+ Colour calculations (based off the main row colours)
+ Level 1:
+ dd > c4
+ ee > d5
+ Level 2:
+ dd > d1
+ ee > e2
+ */
+tr.odd.gradeA td.sorting_1 {
+ background-color: #c4ffc4;
+}
+
+tr.odd.gradeA td.sorting_2 {
+ background-color: #d1ffd1;
+}
+
+tr.odd.gradeA td.sorting_3 {
+ background-color: #d1ffd1;
+}
+
+tr.even.gradeA td.sorting_1 {
+ background-color: #d5ffd5;
+}
+
+tr.even.gradeA td.sorting_2 {
+ background-color: #e2ffe2;
+}
+
+tr.even.gradeA td.sorting_3 {
+ background-color: #e2ffe2;
+}
+
+tr.odd.gradeC td.sorting_1 {
+ background-color: #c4c4ff;
+}
+
+tr.odd.gradeC td.sorting_2 {
+ background-color: #d1d1ff;
+}
+
+tr.odd.gradeC td.sorting_3 {
+ background-color: #d1d1ff;
+}
+
+tr.even.gradeC td.sorting_1 {
+ background-color: #d5d5ff;
+}
+
+tr.even.gradeC td.sorting_2 {
+ background-color: #e2e2ff;
+}
+
+tr.even.gradeC td.sorting_3 {
+ background-color: #e2e2ff;
+}
+
+tr.odd.gradeX td.sorting_1 {
+ background-color: #ffc4c4;
+}
+
+tr.odd.gradeX td.sorting_2 {
+ background-color: #ffd1d1;
+}
+
+tr.odd.gradeX td.sorting_3 {
+ background-color: #ffd1d1;
+}
+
+tr.even.gradeX td.sorting_1 {
+ background-color: #ffd5d5;
+}
+
+tr.even.gradeX td.sorting_2 {
+ background-color: #ffe2e2;
+}
+
+tr.even.gradeX td.sorting_3 {
+ background-color: #ffe2e2;
+}
+
+tr.odd.gradeU td.sorting_1 {
+ background-color: #c4c4c4;
+}
+
+tr.odd.gradeU td.sorting_2 {
+ background-color: #d1d1d1;
+}
+
+tr.odd.gradeU td.sorting_3 {
+ background-color: #d1d1d1;
+}
+
+tr.even.gradeU td.sorting_1 {
+ background-color: #d5d5d5;
+}
+
+tr.even.gradeU td.sorting_2 {
+ background-color: #e2e2e2;
+}
+
+tr.even.gradeU td.sorting_3 {
+ background-color: #e2e2e2;
+}
+
+
+/*
+ * Row highlighting example
+ */
+.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
+ background-color: #ECFFB3;
+}
+
+.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
+ background-color: #E6FF99;
+}
\ No newline at end of file
diff --git a/public/css/datatables/images/Sorting icons.psd b/public/css/datatables/images/Sorting icons.psd
new file mode 100644
index 000000000..53b2e0685
Binary files /dev/null and b/public/css/datatables/images/Sorting icons.psd differ
diff --git a/public/css/datatables/images/back_disabled.jpg b/public/css/datatables/images/back_disabled.jpg
new file mode 100644
index 000000000..1e73a546e
Binary files /dev/null and b/public/css/datatables/images/back_disabled.jpg differ
diff --git a/public/css/datatables/images/back_enabled.jpg b/public/css/datatables/images/back_enabled.jpg
new file mode 100644
index 000000000..a6d764c79
Binary files /dev/null and b/public/css/datatables/images/back_enabled.jpg differ
diff --git a/public/css/datatables/images/favicon.ico b/public/css/datatables/images/favicon.ico
new file mode 100644
index 000000000..6eeaa2a0d
Binary files /dev/null and b/public/css/datatables/images/favicon.ico differ
diff --git a/public/css/datatables/images/forward_disabled.jpg b/public/css/datatables/images/forward_disabled.jpg
new file mode 100644
index 000000000..28a9dc53f
Binary files /dev/null and b/public/css/datatables/images/forward_disabled.jpg differ
diff --git a/public/css/datatables/images/forward_enabled.jpg b/public/css/datatables/images/forward_enabled.jpg
new file mode 100644
index 000000000..598c075f1
Binary files /dev/null and b/public/css/datatables/images/forward_enabled.jpg differ
diff --git a/public/css/datatables/images/sort_asc.png b/public/css/datatables/images/sort_asc.png
new file mode 100644
index 000000000..a56d0e219
Binary files /dev/null and b/public/css/datatables/images/sort_asc.png differ
diff --git a/public/css/datatables/images/sort_asc_disabled.png b/public/css/datatables/images/sort_asc_disabled.png
new file mode 100644
index 000000000..b7e621ef1
Binary files /dev/null and b/public/css/datatables/images/sort_asc_disabled.png differ
diff --git a/public/css/datatables/images/sort_both.png b/public/css/datatables/images/sort_both.png
new file mode 100644
index 000000000..839ac4bb5
Binary files /dev/null and b/public/css/datatables/images/sort_both.png differ
diff --git a/public/css/datatables/images/sort_desc.png b/public/css/datatables/images/sort_desc.png
new file mode 100644
index 000000000..90b295159
Binary files /dev/null and b/public/css/datatables/images/sort_desc.png differ
diff --git a/public/css/datatables/images/sort_desc_disabled.png b/public/css/datatables/images/sort_desc_disabled.png
new file mode 100644
index 000000000..2409653dc
Binary files /dev/null and b/public/css/datatables/images/sort_desc_disabled.png differ
diff --git a/public/images/datatables/Sorting icons.psd b/public/images/datatables/Sorting icons.psd
new file mode 100644
index 000000000..53b2e0685
Binary files /dev/null and b/public/images/datatables/Sorting icons.psd differ
diff --git a/public/images/datatables/back_disabled.jpg b/public/images/datatables/back_disabled.jpg
new file mode 100644
index 000000000..1e73a546e
Binary files /dev/null and b/public/images/datatables/back_disabled.jpg differ
diff --git a/public/images/datatables/back_enabled.jpg b/public/images/datatables/back_enabled.jpg
new file mode 100644
index 000000000..a6d764c79
Binary files /dev/null and b/public/images/datatables/back_enabled.jpg differ
diff --git a/public/images/datatables/favicon.ico b/public/images/datatables/favicon.ico
new file mode 100644
index 000000000..6eeaa2a0d
Binary files /dev/null and b/public/images/datatables/favicon.ico differ
diff --git a/public/images/datatables/forward_disabled.jpg b/public/images/datatables/forward_disabled.jpg
new file mode 100644
index 000000000..28a9dc53f
Binary files /dev/null and b/public/images/datatables/forward_disabled.jpg differ
diff --git a/public/images/datatables/forward_enabled.jpg b/public/images/datatables/forward_enabled.jpg
new file mode 100644
index 000000000..598c075f1
Binary files /dev/null and b/public/images/datatables/forward_enabled.jpg differ
diff --git a/public/images/datatables/sort_asc.png b/public/images/datatables/sort_asc.png
new file mode 100644
index 000000000..a56d0e219
Binary files /dev/null and b/public/images/datatables/sort_asc.png differ
diff --git a/public/images/datatables/sort_asc_disabled.png b/public/images/datatables/sort_asc_disabled.png
new file mode 100644
index 000000000..b7e621ef1
Binary files /dev/null and b/public/images/datatables/sort_asc_disabled.png differ
diff --git a/public/images/datatables/sort_both.png b/public/images/datatables/sort_both.png
new file mode 100644
index 000000000..839ac4bb5
Binary files /dev/null and b/public/images/datatables/sort_both.png differ
diff --git a/public/images/datatables/sort_desc.png b/public/images/datatables/sort_desc.png
new file mode 100644
index 000000000..90b295159
Binary files /dev/null and b/public/images/datatables/sort_desc.png differ
diff --git a/public/images/datatables/sort_desc_disabled.png b/public/images/datatables/sort_desc_disabled.png
new file mode 100644
index 000000000..2409653dc
Binary files /dev/null and b/public/images/datatables/sort_desc_disabled.png differ
diff --git a/public/js/datatables/js/jquery.dataTables.js b/public/js/datatables/js/jquery.dataTables.js
new file mode 100644
index 000000000..4ba698de5
--- /dev/null
+++ b/public/js/datatables/js/jquery.dataTables.js
@@ -0,0 +1,6848 @@
+/*
+ * File: jquery.dataTables.js
+ * Version: 1.7.5
+ * Description: Paginate, search and sort HTML tables
+ * Author: Allan Jardine (www.sprymedia.co.uk)
+ * Created: 28/3/2008
+ * Language: Javascript
+ * License: GPL v2 or BSD 3 point style
+ * Project: Mtaala
+ * Contact: allan.jardine@sprymedia.co.uk
+ *
+ * Copyright 2008-2010 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, as supplied with this software.
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*
+ * When considering jsLint, we need to allow eval() as it it is used for reading cookies and
+ * building the dynamic multi-column sort functions.
+ */
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/
+
+(function($, window, document) {
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Section - DataTables variables
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Variable: dataTableSettings
+ * Purpose: Store the settings for each dataTables instance
+ * Scope: jQuery.fn
+ */
+ $.fn.dataTableSettings = [];
+ var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */
+
+ /*
+ * Variable: dataTableExt
+ * Purpose: Container for customisable parts of DataTables
+ * Scope: jQuery.fn
+ */
+ $.fn.dataTableExt = {};
+ var _oExt = $.fn.dataTableExt;
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Section - DataTables extensible objects
+ *
+ * The _oExt object is used to provide an area where user dfined plugins can be
+ * added to DataTables. The following properties of the object are used:
+ * oApi - Plug-in API functions
+ * aTypes - Auto-detection of types
+ * oSort - Sorting functions used by DataTables (based on the type)
+ * oPagination - Pagination functions for different input styles
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Variable: sVersion
+ * Purpose: Version string for plug-ins to check compatibility
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: Allowed format is a.b.c.d.e where:
+ * a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional
+ */
+ _oExt.sVersion = "1.7.5";
+
+ /*
+ * Variable: sErrMode
+ * Purpose: How should DataTables report an error. Can take the value 'alert' or 'throw'
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.sErrMode = "alert";
+
+ /*
+ * Variable: iApiIndex
+ * Purpose: Index for what 'this' index API functions should use
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.iApiIndex = 0;
+
+ /*
+ * Variable: oApi
+ * Purpose: Container for plugin API functions
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oApi = { };
+
+ /*
+ * Variable: aFiltering
+ * Purpose: Container for plugin filtering functions
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.afnFiltering = [ ];
+
+ /*
+ * Variable: aoFeatures
+ * Purpose: Container for plugin function functions
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: Array of objects with the following parameters:
+ * fnInit: Function for initialisation of Feature. Takes oSettings and returns node
+ * cFeature: Character that will be matched in sDom - case sensitive
+ * sFeature: Feature name - just for completeness :-)
+ */
+ _oExt.aoFeatures = [ ];
+
+ /*
+ * Variable: ofnSearch
+ * Purpose: Container for custom filtering functions
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: This is an object (the name should match the type) for custom filtering function,
+ * which can be used for live DOM checking or formatted text filtering
+ */
+ _oExt.ofnSearch = { };
+
+ /*
+ * Variable: afnSortData
+ * Purpose: Container for custom sorting data source functions
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: Array (associative) of functions which is run prior to a column of this
+ * 'SortDataType' being sorted upon.
+ * Function input parameters:
+ * object:oSettings- DataTables settings object
+ * int:iColumn - Target column number
+ * Return value: Array of data which exactly matched the full data set size for the column to
+ * be sorted upon
+ */
+ _oExt.afnSortData = [ ];
+
+ /*
+ * Variable: oStdClasses
+ * Purpose: Storage for the various classes that DataTables uses
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oStdClasses = {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "paginate_enabled_previous",
+ "sPagePrevDisabled": "paginate_disabled_previous",
+ "sPageNextEnabled": "paginate_enabled_next",
+ "sPageNextDisabled": "paginate_disabled_next",
+ "sPageJUINext": "",
+ "sPageJUIPrev": "",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "paginate_button",
+ "sPageButtonActive": "paginate_active",
+ "sPageButtonStaticDisabled": "paginate_button",
+ "sPageFirst": "first",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last",
+
+ /* Stripping classes */
+ "sStripOdd": "odd",
+ "sStripEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "sorting_asc",
+ "sSortDesc": "sorting_desc",
+ "sSortable": "sorting", /* Sortable in both directions */
+ "sSortableAsc": "sorting_asc_disabled",
+ "sSortableDesc": "sorting_desc_disabled",
+ "sSortableNone": "sorting_disabled",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "",
+ "sSortJUIDesc": "",
+ "sSortJUI": "",
+ "sSortJUIAscAllowed": "",
+ "sSortJUIDescAllowed": "",
+ "sSortJUIWrapper": "",
+
+ /* Scrolling */
+ "sScrollWrapper": "dataTables_scroll",
+ "sScrollHead": "dataTables_scrollHead",
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
+ "sScrollBody": "dataTables_scrollBody",
+ "sScrollFoot": "dataTables_scrollFoot",
+ "sScrollFootInner": "dataTables_scrollFootInner",
+
+ /* Misc */
+ "sFooterTH": ""
+ };
+
+ /*
+ * Variable: oJUIClasses
+ * Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oJUIClasses = {
+ /* Two buttons buttons */
+ "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
+ "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+ "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
+ "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
+ "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+ "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+
+ /* Full numbers paging buttons */
+ "sPageButton": "fg-button ui-button ui-state-default",
+ "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
+ "sPageFirst": "first ui-corner-tl ui-corner-bl",
+ "sPagePrevious": "previous",
+ "sPageNext": "next",
+ "sPageLast": "last ui-corner-tr ui-corner-br",
+
+ /* Stripping classes */
+ "sStripOdd": "odd",
+ "sStripEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "ui-state-default",
+ "sSortDesc": "ui-state-default",
+ "sSortable": "ui-state-default",
+ "sSortableAsc": "ui-state-default",
+ "sSortableDesc": "ui-state-default",
+ "sSortableNone": "ui-state-default",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+ "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+ "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+ "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
+ "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
+ "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
+ "sSortJUIWrapper": "DataTables_sort_wrapper",
+
+ /* Scrolling */
+ "sScrollWrapper": "dataTables_scroll",
+ "sScrollHead": "dataTables_scrollHead ui-state-default",
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
+ "sScrollBody": "dataTables_scrollBody",
+ "sScrollFoot": "dataTables_scrollFoot ui-state-default",
+ "sScrollFootInner": "dataTables_scrollFootInner",
+
+ /* Misc */
+ "sFooterTH": "ui-state-default"
+ };
+
+ /*
+ * Variable: oPagination
+ * Purpose: Container for the various type of pagination that dataTables supports
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt.oPagination = {
+ /*
+ * Variable: two_button
+ * Purpose: Standard two button (forward/back) pagination
+ * Scope: jQuery.fn.dataTableExt.oPagination
+ */
+ "two_button": {
+ /*
+ * Function: oPagination.two_button.fnInit
+ * Purpose: Initalise dom elements required for pagination with forward/back buttons only
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:nPaging - the DIV which contains this pagination control
+ * function:fnCallbackDraw - draw function which must be called on update
+ */
+ "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+ {
+ var nPrevious, nNext, nPreviousInner, nNextInner;
+
+ /* Store the next and previous elements in the oSettings object as they can be very
+ * usful for automation - particularly testing
+ */
+ if ( !oSettings.bJUI )
+ {
+ nPrevious = document.createElement( 'div' );
+ nNext = document.createElement( 'div' );
+ }
+ else
+ {
+ nPrevious = document.createElement( 'a' );
+ nNext = document.createElement( 'a' );
+
+ nNextInner = document.createElement('span');
+ nNextInner.className = oSettings.oClasses.sPageJUINext;
+ nNext.appendChild( nNextInner );
+
+ nPreviousInner = document.createElement('span');
+ nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
+ nPrevious.appendChild( nPreviousInner );
+ }
+
+ nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
+ nNext.className = oSettings.oClasses.sPageNextDisabled;
+
+ nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
+ nNext.title = oSettings.oLanguage.oPaginate.sNext;
+
+ nPaging.appendChild( nPrevious );
+ nPaging.appendChild( nNext );
+
+ $(nPrevious).click( function() {
+ if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
+ {
+ /* Only draw when the page has actually changed */
+ fnCallbackDraw( oSettings );
+ }
+ } );
+
+ $(nNext).click( function() {
+ if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
+ {
+ fnCallbackDraw( oSettings );
+ }
+ } );
+
+ /* Take the brutal approach to cancelling text selection */
+ $(nPrevious).bind( 'selectstart', function () { return false; } );
+ $(nNext).bind( 'selectstart', function () { return false; } );
+
+ /* ID the first elements only */
+ if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
+ {
+ nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
+ nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
+ nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
+ }
+ },
+
+ /*
+ * Function: oPagination.two_button.fnUpdate
+ * Purpose: Update the two button pagination at the end of the draw
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * function:fnCallbackDraw - draw function to call on page change
+ */
+ "fnUpdate": function ( oSettings, fnCallbackDraw )
+ {
+ if ( !oSettings.aanFeatures.p )
+ {
+ return;
+ }
+
+ /* Loop over each instance of the pager */
+ var an = oSettings.aanFeatures.p;
+ for ( var i=0, iLen=an.length ; i= (iPages - iPageCountHalf))
+ {
+ iStartButton = iPages - iPageCount + 1;
+ iEndButton = iPages;
+ }
+ else
+ {
+ iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+ iEndButton = iStartButton + iPageCount - 1;
+ }
+ }
+ }
+
+ /* Build the dynamic list */
+ for ( i=iStartButton ; i<=iEndButton ; i++ )
+ {
+ if ( iCurrentPage != i )
+ {
+ sList += ''+i+'';
+ }
+ else
+ {
+ sList += ''+i+'';
+ }
+ }
+
+ /* Loop over each instance of the pager */
+ var an = oSettings.aanFeatures.p;
+ var anButtons, anStatic, nPaginateList;
+ var fnClick = function() {
+ /* Use the information in the element to jump to the required page */
+ var iTarget = (this.innerHTML * 1) - 1;
+ oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
+ fnCallbackDraw( oSettings );
+ return false;
+ };
+ var fnFalse = function () { return false; };
+
+ for ( i=0, iLen=an.length ; i y) ? 1 : 0));
+ },
+
+ "string-desc": function ( a, b )
+ {
+ var x = a.toLowerCase();
+ var y = b.toLowerCase();
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * html sorting (ignore html tags)
+ */
+ "html-asc": function ( a, b )
+ {
+ var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+ var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "html-desc": function ( a, b )
+ {
+ var x = a.replace( /<.*?>/g, "" ).toLowerCase();
+ var y = b.replace( /<.*?>/g, "" ).toLowerCase();
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ },
+
+
+ /*
+ * date sorting
+ */
+ "date-asc": function ( a, b )
+ {
+ var x = Date.parse( a );
+ var y = Date.parse( b );
+
+ if ( isNaN(x) || x==="" )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ if ( isNaN(y) || y==="" )
+ {
+ y = Date.parse( "01/01/1970 00:00:00" );
+ }
+
+ return x - y;
+ },
+
+ "date-desc": function ( a, b )
+ {
+ var x = Date.parse( a );
+ var y = Date.parse( b );
+
+ if ( isNaN(x) || x==="" )
+ {
+ x = Date.parse( "01/01/1970 00:00:00" );
+ }
+ if ( isNaN(y) || y==="" )
+ {
+ y = Date.parse( "01/01/1970 00:00:00" );
+ }
+
+ return y - x;
+ },
+
+
+ /*
+ * numerical sorting
+ */
+ "numeric-asc": function ( a, b )
+ {
+ var x = (a=="-" || a==="") ? 0 : a*1;
+ var y = (b=="-" || b==="") ? 0 : b*1;
+ return x - y;
+ },
+
+ "numeric-desc": function ( a, b )
+ {
+ var x = (a=="-" || a==="") ? 0 : a*1;
+ var y = (b=="-" || b==="") ? 0 : b*1;
+ return y - x;
+ }
+ };
+
+
+ /*
+ * Variable: aTypes
+ * Purpose: Container for the various type of type detection that dataTables supports
+ * Scope: jQuery.fn.dataTableExt
+ * Notes: The functions in this array are expected to parse a string to see if it is a data
+ * type that it recognises. If so then the function should return the name of the type (a
+ * corresponding sort function should be defined!), if the type is not recognised then the
+ * function should return null such that the parser and move on to check the next type.
+ * Note that ordering is important in this array - the functions are processed linearly,
+ * starting at index 0.
+ * Note that the input for these functions is always a string! It cannot be any other data
+ * type
+ */
+ _oExt.aTypes = [
+ /*
+ * Function: -
+ * Purpose: Check to see if a string is numeric
+ * Returns: string:'numeric' or null
+ * Inputs: string:sText - string to check
+ */
+ function ( sData )
+ {
+ /* Allow zero length strings as a number */
+ if ( sData.length === 0 )
+ {
+ return 'numeric';
+ }
+
+ var sValidFirstChars = "0123456789-";
+ var sValidChars = "0123456789.";
+ var Char;
+ var bDecimal = false;
+
+ /* Check for a valid first char (no period and allow negatives) */
+ Char = sData.charAt(0);
+ if (sValidFirstChars.indexOf(Char) == -1)
+ {
+ return null;
+ }
+
+ /* Check all the other characters are valid */
+ for ( var i=1 ; i') != -1 )
+ {
+ return 'html';
+ }
+ return null;
+ }
+ ];
+
+ /*
+ * Function: fnVersionCheck
+ * Purpose: Check a version string against this version of DataTables. Useful for plug-ins
+ * Returns: bool:true -this version of DataTables is greater or equal to the required version
+ * false -this version of DataTales is not suitable
+ * Inputs: string:sVersion - the version to check against. May be in the following formats:
+ * "a", "a.b" or "a.b.c"
+ * Notes: This function will only check the first three parts of a version string. It is
+ * assumed that beta and dev versions will meet the requirements. This might change in future
+ */
+ _oExt.fnVersionCheck = function( sVersion )
+ {
+ /* This is cheap, but very effective */
+ var fnZPad = function (Zpad, count)
+ {
+ while(Zpad.length < count) {
+ Zpad += '0';
+ }
+ return Zpad;
+ };
+ var aThis = _oExt.sVersion.split('.');
+ var aThat = sVersion.split('.');
+ var sThis = '', sThat = '';
+
+ for ( var i=0, iLen=aThat.length ; i= parseInt(sThat, 10);
+ };
+
+ /*
+ * Variable: _oExternConfig
+ * Purpose: Store information for DataTables to access globally about other instances
+ * Scope: jQuery.fn.dataTableExt
+ */
+ _oExt._oExternConfig = {
+ /* int:iNextUnique - next unique number for an instance */
+ "iNextUnique": 0
+ };
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Section - DataTables prototype
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+ /*
+ * Function: dataTable
+ * Purpose: DataTables information
+ * Returns: -
+ * Inputs: object:oInit - initalisation options for the table
+ */
+ $.fn.dataTable = function( oInit )
+ {
+ /*
+ * Function: classSettings
+ * Purpose: Settings container function for all 'class' properties which are required
+ * by dataTables
+ * Returns: -
+ * Inputs: -
+ */
+ function classSettings ()
+ {
+ this.fnRecordsTotal = function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsTotal, 10);
+ } else {
+ return this.aiDisplayMaster.length;
+ }
+ };
+
+ this.fnRecordsDisplay = function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ return parseInt(this._iRecordsDisplay, 10);
+ } else {
+ return this.aiDisplay.length;
+ }
+ };
+
+ this.fnDisplayEnd = function ()
+ {
+ if ( this.oFeatures.bServerSide ) {
+ if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
+ return this._iDisplayStart+this.aiDisplay.length;
+ } else {
+ return Math.min( this._iDisplayStart+this._iDisplayLength,
+ this._iRecordsDisplay );
+ }
+ } else {
+ return this._iDisplayEnd;
+ }
+ };
+
+ /*
+ * Variable: oInstance
+ * Purpose: The DataTables object for this table
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oInstance = null;
+
+ /*
+ * Variable: sInstance
+ * Purpose: Unique idendifier for each instance of the DataTables object
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sInstance = null;
+
+ /*
+ * Variable: oFeatures
+ * Purpose: Indicate the enablement of key dataTable features
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oFeatures = {
+ "bPaginate": true,
+ "bLengthChange": true,
+ "bFilter": true,
+ "bSort": true,
+ "bInfo": true,
+ "bAutoWidth": true,
+ "bProcessing": false,
+ "bSortClasses": true,
+ "bStateSave": false,
+ "bServerSide": false
+ };
+
+ /*
+ * Variable: oScroll
+ * Purpose: Container for scrolling options
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oScroll = {
+ "sX": "",
+ "sXInner": "",
+ "sY": "",
+ "bCollapse": false,
+ "bInfinite": false,
+ "iLoadGap": 100,
+ "iBarWidth": 0,
+ "bAutoCss": true
+ };
+
+ /*
+ * Variable: aanFeatures
+ * Purpose: Array referencing the nodes which are used for the features
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: The parameters of this object match what is allowed by sDom - i.e.
+ * 'l' - Length changing
+ * 'f' - Filtering input
+ * 't' - The table!
+ * 'i' - Information
+ * 'p' - Pagination
+ * 'r' - pRocessing
+ */
+ this.aanFeatures = [];
+
+ /*
+ * Variable: oLanguage
+ * Purpose: Store the language strings used by dataTables
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: The words in the format _VAR_ are variables which are dynamically replaced
+ * by javascript
+ */
+ this.oLanguage = {
+ "sProcessing": "Processing...",
+ "sLengthMenu": "Show _MENU_ entries",
+ "sZeroRecords": "No matching records found",
+ "sEmptyTable": "No data available in table",
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
+ "sInfoPostFix": "",
+ "sSearch": "Search:",
+ "sUrl": "",
+ "oPaginate": {
+ "sFirst": "First",
+ "sPrevious": "Previous",
+ "sNext": "Next",
+ "sLast": "Last"
+ },
+ "fnInfoCallback": null
+ };
+
+ /*
+ * Variable: aoData
+ * Purpose: Store data information
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: This is an array of objects with the following parameters:
+ * int: _iId - internal id for tracking
+ * array: _aData - internal data - used for sorting / filtering etc
+ * node: nTr - display node
+ * array node: _anHidden - hidden TD nodes
+ * string: _sRowStripe
+ */
+ this.aoData = [];
+
+ /*
+ * Variable: aiDisplay
+ * Purpose: Array of indexes which are in the current display (after filtering etc)
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.aiDisplay = [];
+
+ /*
+ * Variable: aiDisplayMaster
+ * Purpose: Array of indexes for display - no filtering
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.aiDisplayMaster = [];
+
+ /*
+ * Variable: aoColumns
+ * Purpose: Store information about each column that is in use
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.aoColumns = [];
+
+ /*
+ * Variable: iNextId
+ * Purpose: Store the next unique id to be used for a new row
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.iNextId = 0;
+
+ /*
+ * Variable: asDataSearch
+ * Purpose: Search data array for regular expression searching
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.asDataSearch = [];
+
+ /*
+ * Variable: oPreviousSearch
+ * Purpose: Store the previous search incase we want to force a re-search
+ * or compare the old search to a new one
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oPreviousSearch = {
+ "sSearch": "",
+ "bRegex": false,
+ "bSmart": true
+ };
+
+ /*
+ * Variable: aoPreSearchCols
+ * Purpose: Store the previous search for each column
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.aoPreSearchCols = [];
+
+ /*
+ * Variable: aaSorting
+ * Purpose: Sorting information
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: Index 0 - column number
+ * Index 1 - current sorting direction
+ * Index 2 - index of asSorting for this column
+ */
+ this.aaSorting = [ [0, 'asc', 0] ];
+
+ /*
+ * Variable: aaSortingFixed
+ * Purpose: Sorting information that is always applied
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.aaSortingFixed = null;
+
+ /*
+ * Variable: asStripClasses
+ * Purpose: Classes to use for the striping of a table
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.asStripClasses = [];
+
+ /*
+ * Variable: asDestoryStrips
+ * Purpose: If restoring a table - we should restore it's striping classes as well
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.asDestoryStrips = [];
+
+ /*
+ * Variable: sDestroyWidth
+ * Purpose: If restoring a table - we should restore it's width
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sDestroyWidth = 0;
+
+ /*
+ * Variable: fnRowCallback
+ * Purpose: Call this function every time a row is inserted (draw)
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnRowCallback = null;
+
+ /*
+ * Variable: fnHeaderCallback
+ * Purpose: Callback function for the header on each draw
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnHeaderCallback = null;
+
+ /*
+ * Variable: fnFooterCallback
+ * Purpose: Callback function for the footer on each draw
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnFooterCallback = null;
+
+ /*
+ * Variable: aoDrawCallback
+ * Purpose: Array of callback functions for draw callback functions
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: Each array element is an object with the following parameters:
+ * function:fn - function to call
+ * string:sName - name callback (feature). useful for arranging array
+ */
+ this.aoDrawCallback = [];
+
+ /*
+ * Variable: fnInitComplete
+ * Purpose: Callback function for when the table has been initalised
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnInitComplete = null;
+
+ /*
+ * Variable: sTableId
+ * Purpose: Cache the table ID for quick access
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sTableId = "";
+
+ /*
+ * Variable: nTable
+ * Purpose: Cache the table node for quick access
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.nTable = null;
+
+ /*
+ * Variable: nTHead
+ * Purpose: Permanent ref to the thead element
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.nTHead = null;
+
+ /*
+ * Variable: nTFoot
+ * Purpose: Permanent ref to the tfoot element - if it exists
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.nTFoot = null;
+
+ /*
+ * Variable: nTBody
+ * Purpose: Permanent ref to the tbody element
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.nTBody = null;
+
+ /*
+ * Variable: nTableWrapper
+ * Purpose: Cache the wrapper node (contains all DataTables controlled elements)
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.nTableWrapper = null;
+
+ /*
+ * Variable: bInitialised
+ * Purpose: Indicate if all required information has been read in
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.bInitialised = false;
+
+ /*
+ * Variable: aoOpenRows
+ * Purpose: Information about open rows
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: Has the parameters 'nTr' and 'nParent'
+ */
+ this.aoOpenRows = [];
+
+ /*
+ * Variable: sDom
+ * Purpose: Dictate the positioning that the created elements will take
+ * Scope: jQuery.dataTable.classSettings
+ * Notes:
+ * The following options are allowed:
+ * 'l' - Length changing
+ * 'f' - Filtering input
+ * 't' - The table!
+ * 'i' - Information
+ * 'p' - Pagination
+ * 'r' - pRocessing
+ * The following constants are allowed:
+ * 'H' - jQueryUI theme "header" classes
+ * 'F' - jQueryUI theme "footer" classes
+ * The following syntax is expected:
+ * '<' and '>' - div elements
+ * '<"class" and '>' - div with a class
+ * Examples:
+ * '<"wrapper"flipt>', 'ip>'
+ */
+ this.sDom = 'lfrtip';
+
+ /*
+ * Variable: sPaginationType
+ * Purpose: Note which type of sorting should be used
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sPaginationType = "two_button";
+
+ /*
+ * Variable: iCookieDuration
+ * Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.iCookieDuration = 60 * 60 * 2;
+
+ /*
+ * Variable: sCookiePrefix
+ * Purpose: The cookie name prefix
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sCookiePrefix = "SpryMedia_DataTables_";
+
+ /*
+ * Variable: fnCookieCallback
+ * Purpose: Callback function for cookie creation
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnCookieCallback = null;
+
+ /*
+ * Variable: aoStateSave
+ * Purpose: Array of callback functions for state saving
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: Each array element is an object with the following parameters:
+ * function:fn - function to call. Takes two parameters, oSettings and the JSON string to
+ * save that has been thus far created. Returns a JSON string to be inserted into a
+ * json object (i.e. '"param": [ 0, 1, 2]')
+ * string:sName - name of callback
+ */
+ this.aoStateSave = [];
+
+ /*
+ * Variable: aoStateLoad
+ * Purpose: Array of callback functions for state loading
+ * Scope: jQuery.dataTable.classSettings
+ * Notes: Each array element is an object with the following parameters:
+ * function:fn - function to call. Takes two parameters, oSettings and the object stored.
+ * May return false to cancel state loading.
+ * string:sName - name of callback
+ */
+ this.aoStateLoad = [];
+
+ /*
+ * Variable: oLoadedState
+ * Purpose: State that was loaded from the cookie. Useful for back reference
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.oLoadedState = null;
+
+ /*
+ * Variable: sAjaxSource
+ * Purpose: Source url for AJAX data for the table
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.sAjaxSource = null;
+
+ /*
+ * Variable: bAjaxDataGet
+ * Purpose: Note if draw should be blocked while getting data
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.bAjaxDataGet = true;
+
+ /*
+ * Variable: fnServerData
+ * Purpose: Function to get the server-side data - can be overruled by the developer
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnServerData = function ( url, data, callback ) {
+ $.ajax( {
+ "url": url,
+ "data": data,
+ "success": callback,
+ "dataType": "json",
+ "cache": false,
+ "error": function (xhr, error, thrown) {
+ if ( error == "parsererror" ) {
+ alert( "DataTables warning: JSON data from server could not be parsed. "+
+ "This is caused by a JSON formatting error." );
+ }
+ }
+ } );
+ };
+
+ /*
+ * Variable: fnFormatNumber
+ * Purpose: Format numbers for display
+ * Scope: jQuery.dataTable.classSettings
+ */
+ this.fnFormatNumber = function ( iIn )
+ {
+ if ( iIn < 1000 )
+ {
+ /* A small optimisation for what is likely to be the vast majority of use cases */
+ return iIn;
+ }
+ else
+ {
+ var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
+
+ for ( var i=0 ; i= oSettings.aiDisplay.length )
+ {
+ oSettings._iDisplayStart -= oSettings._iDisplayLength;
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+
+ if ( typeof bRedraw == 'undefined' || bRedraw )
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+
+ return oData;
+ };
+
+ /*
+ * Function: fnClearTable
+ * Purpose: Quickly and simply clear a table
+ * Returns: -
+ * Inputs: bool:bRedraw - redraw the table or not - default true
+ * Notes: Thanks to Yekimov Denis for contributing the basis for this function!
+ */
+ this.fnClearTable = function( bRedraw )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+ _fnClearTable( oSettings );
+
+ if ( typeof bRedraw == 'undefined' || bRedraw )
+ {
+ _fnDraw( oSettings );
+ }
+ };
+
+ /*
+ * Function: fnOpen
+ * Purpose: Open a display row (append a row after the row in question)
+ * Returns: node:nNewRow - the row opened
+ * Inputs: node:nTr - the table row to 'open'
+ * string:sHtml - the HTML to put into the row
+ * string:sClass - class to give the new TD cell
+ */
+ this.fnOpen = function( nTr, sHtml, sClass )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ /* the old open one if there is one */
+ this.fnClose( nTr );
+
+ var nNewRow = document.createElement("tr");
+ var nNewCell = document.createElement("td");
+ nNewRow.appendChild( nNewCell );
+ nNewCell.className = sClass;
+ nNewCell.colSpan = _fnVisbleColumns( oSettings );
+ nNewCell.innerHTML = sHtml;
+
+ /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
+ var nTrs = $('tr', oSettings.nTBody);
+ if ( $.inArray(nTr, nTrs) != -1 )
+ {
+ $(nNewRow).insertAfter(nTr);
+ }
+
+ oSettings.aoOpenRows.push( {
+ "nTr": nNewRow,
+ "nParent": nTr
+ } );
+
+ return nNewRow;
+ };
+
+ /*
+ * Function: fnClose
+ * Purpose: Close a display row
+ * Returns: int: 0 (success) or 1 (failed)
+ * Inputs: node:nTr - the table row to 'close'
+ */
+ this.fnClose = function( nTr )
+ {
+ /* Find settings from table node */
+ var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
+
+ for ( var i=0 ; itr', oSettings.nTHead)[0];
+ var nTrFoot = $('>tr', oSettings.nTFoot)[0];
+ var anTheadTh = [];
+ var anTfootTh = [];
+ for ( i=0 ; i= _fnVisbleColumns( oSettings ) )
+ {
+ nTrHead.appendChild( anTheadTh[iCol] );
+ anTrs = $('>tr', oSettings.nTHead);
+ for ( i=1, iLen=anTrs.length ; itr', oSettings.nTFoot);
+ for ( i=1, iLen=anTrs.length ; itr', oSettings.nTHead);
+ for ( i=1, iLen=anTrs.length ; itr', oSettings.nTFoot);
+ for ( i=1, iLen=anTrs.length ; itd:eq('+iBefore+')',
+ oSettings.aoData[i].nTr)[0] );
+ }
+ }
+
+ oSettings.aoColumns[iCol].bVisible = true;
+ }
+ else
+ {
+ /* Remove a column from display */
+ nTrHead.removeChild( anTheadTh[iCol] );
+ for ( i=0, iLen=oSettings.aoColumns[iCol].anThExtra.length ; itr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
+
+ /* When scrolling we had to break the table up - restore it */
+ if ( oSettings.nTable != oSettings.nTHead.parentNode )
+ {
+ $('>thead', oSettings.nTable).remove();
+ oSettings.nTable.appendChild( oSettings.nTHead );
+ }
+
+ if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
+ {
+ $('>tfoot', oSettings.nTable).remove();
+ oSettings.nTable.appendChild( oSettings.nTFoot );
+ }
+
+ /* Remove the DataTables generated nodes, events and classes */
+ oSettings.nTable.parentNode.removeChild( oSettings.nTable );
+ $(oSettings.nTableWrapper).remove();
+
+ oSettings.aaSorting = [];
+ oSettings.aaSortingFixed = [];
+ _fnSortingClasses( oSettings );
+
+ $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripClasses.join(' ') );
+
+ if ( !oSettings.bJUI )
+ {
+ $('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
+ _oExt.oStdClasses.sSortableAsc,
+ _oExt.oStdClasses.sSortableDesc,
+ _oExt.oStdClasses.sSortableNone ].join(' ')
+ );
+ }
+ else
+ {
+ $('th', oSettings.nTHead).removeClass( [ _oExt.oStdClasses.sSortable,
+ _oExt.oJUIClasses.sSortableAsc,
+ _oExt.oJUIClasses.sSortableDesc,
+ _oExt.oJUIClasses.sSortableNone ].join(' ')
+ );
+ $('th span', oSettings.nTHead).remove();
+ }
+
+ /* Add the TR elements back into the table in their original order */
+ nOrig.appendChild( oSettings.nTable );
+ for ( i=0, iLen=oSettings.aoData.length ; itr:even', nBody).addClass( oSettings.asDestoryStrips[0] );
+ $('>tr:odd', nBody).addClass( oSettings.asDestoryStrips[1] );
+
+ /* Remove the settings object from the settings array */
+ for ( i=0, iLen=_aoSettings.length ; i=0 if successful (index of new aoData entry), -1 if failed
+ * Inputs: object:oSettings - dataTables settings object
+ * array:aData - data array to be added
+ * Notes: There are two basic methods for DataTables to get data to display - a JS array
+ * (which is dealt with by this function), and the DOM, which has it's own optimised
+ * function (_fnGatherData). Be careful to make the same changes here as there and vice-versa
+ */
+ function _fnAddData ( oSettings, aDataSupplied )
+ {
+ /* Sanity check the length of the new array */
+ if ( aDataSupplied.length != oSettings.aoColumns.length &&
+ oSettings.iDrawError != oSettings.iDraw )
+ {
+ _fnLog( oSettings, 0, "Added data (size "+aDataSupplied.length+") does not match known "+
+ "number of columns ("+oSettings.aoColumns.length+")" );
+ oSettings.iDrawError = oSettings.iDraw;
+ return -1;
+ }
+
+
+ /* Create the object for storing information about this new row */
+ var aData = aDataSupplied.slice();
+ var iThisIndex = oSettings.aoData.length;
+ oSettings.aoData.push( {
+ "nTr": document.createElement('tr'),
+ "_iId": oSettings.iNextId++,
+ "_aData": aData,
+ "_anHidden": [],
+ "_sRowStripe": ''
+ } );
+
+ /* Create the cells */
+ var nTd, sThisType;
+ for ( var i=0 ; i= oSettings.fnRecordsDisplay()) ?
+ 0 : oSettings.iInitDisplayStart;
+ }
+ oSettings.iInitDisplayStart = -1;
+ _fnCalculateEnd( oSettings );
+ }
+
+ /* If we are dealing with Ajax - do it here */
+ if ( !oSettings.bDestroying && oSettings.oFeatures.bServerSide &&
+ !_fnAjaxUpdate( oSettings ) )
+ {
+ return;
+ }
+ else if ( !oSettings.oFeatures.bServerSide )
+ {
+ oSettings.iDraw++;
+ }
+
+ if ( oSettings.aiDisplay.length !== 0 )
+ {
+ var iStart = oSettings._iDisplayStart;
+ var iEnd = oSettings._iDisplayEnd;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ iStart = 0;
+ iEnd = oSettings.aoData.length;
+ }
+
+ for ( var j=iStart ; jtr', oSettings.nTHead)[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
+ oSettings.aiDisplay );
+ }
+
+ if ( typeof oSettings.fnFooterCallback == 'function' )
+ {
+ oSettings.fnFooterCallback.call( oSettings.oInstance, $('>tr', oSettings.nTFoot)[0],
+ _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(),
+ oSettings.aiDisplay );
+ }
+
+ /*
+ * Need to remove any old row from the display - note we can't just empty the tbody using
+ * $().html('') since this will unbind the jQuery event handlers (even although the node
+ * still exists!) - equally we can't use innerHTML, since IE throws an exception.
+ */
+ var
+ nAddFrag = document.createDocumentFragment(),
+ nRemoveFrag = document.createDocumentFragment(),
+ nBodyPar, nTrs;
+
+ if ( oSettings.nTBody )
+ {
+ nBodyPar = oSettings.nTBody.parentNode;
+ nRemoveFrag.appendChild( oSettings.nTBody );
+
+ /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
+ * up. When not infinite scroll, always do it.
+ */
+ if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
+ oSettings.bSorted || oSettings.bFiltered )
+ {
+ nTrs = oSettings.nTBody.childNodes;
+ for ( i=nTrs.length-1 ; i>=0 ; i-- )
+ {
+ nTrs[i].parentNode.removeChild( nTrs[i] );
+ }
+ }
+
+ /* Put the draw table into the dom */
+ for ( i=0, iLen=anRows.length ; i=0 ; i-- )
+ {
+ oSettings.aoDrawCallback[i].fn.call( oSettings.oInstance, oSettings );
+ }
+
+ /* Draw is complete, sorting and filtering must be as well */
+ oSettings.bSorted = false;
+ oSettings.bFiltered = false;
+ oSettings.bDrawing = false;
+
+ if ( oSettings.oFeatures.bServerSide )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ if ( typeof oSettings._bInitComplete == 'undefined' )
+ {
+ _fnInitComplete( oSettings );
+ }
+ }
+ }
+
+ /*
+ * Function: _fnReDraw
+ * Purpose: Redraw the table - taking account of the various features which are enabled
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnReDraw( oSettings )
+ {
+ if ( oSettings.oFeatures.bSort )
+ {
+ /* Sorting will refilter and draw for us */
+ _fnSort( oSettings, oSettings.oPreviousSearch );
+ }
+ else if ( oSettings.oFeatures.bFilter )
+ {
+ /* Filtering will redraw for us */
+ _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+ }
+ else
+ {
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+
+ /*
+ * Function: _fnAjaxUpdate
+ * Purpose: Update the table using an Ajax call
+ * Returns: bool: block the table drawing or not
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnAjaxUpdate( oSettings )
+ {
+ if ( oSettings.bAjaxDataGet )
+ {
+ _fnProcessingDisplay( oSettings, true );
+ var iColumns = oSettings.aoColumns.length;
+ var aoData = [];
+ var i;
+
+ /* Paging and general */
+ oSettings.iDraw++;
+ aoData.push( { "name": "sEcho", "value": oSettings.iDraw } );
+ aoData.push( { "name": "iColumns", "value": iColumns } );
+ aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } );
+ aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } );
+ aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
+ oSettings._iDisplayLength : -1 } );
+
+ /* Filtering */
+ if ( oSettings.oFeatures.bFilter !== false )
+ {
+ aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
+ aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } );
+ for ( i=0 ; i' )
+ {
+ /* End container div */
+ nInsertNode = nInsertNode.parentNode;
+ }
+ else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+ {
+ /* Length */
+ nTmp = _fnFeatureHtmlLength( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+ {
+ /* Filter */
+ nTmp = _fnFeatureHtmlFilter( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+ {
+ /* pRocessing */
+ nTmp = _fnFeatureHtmlProcessing( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ nTmp = _fnFeatureHtmlTable( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'i' && oSettings.oFeatures.bInfo )
+ {
+ /* Info */
+ nTmp = _fnFeatureHtmlInfo( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+ {
+ /* Pagination */
+ nTmp = _fnFeatureHtmlPaginate( oSettings );
+ iPushFeature = 1;
+ }
+ else if ( _oExt.aoFeatures.length !== 0 )
+ {
+ /* Plug-in features */
+ var aoFeatures = _oExt.aoFeatures;
+ for ( var k=0, kLen=aoFeatures.length ; kcaption', oSettings.nTable);
+ for ( var i=0, iLen=nCaptions.length ; i
+ $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
+ {
+ /* Only do the redraw if we have to - we might be at the end of the data */
+ if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
+ {
+ _fnPageChange( oSettings, 'next' );
+ _fnCalculateEnd( oSettings );
+ _fnDraw( oSettings );
+ }
+ }
+ }
+ } );
+ }
+
+ oSettings.nScrollHead = nScrollHead;
+ oSettings.nScrollFoot = nScrollFoot;
+
+ return nScroller;
+ }
+
+ /*
+ * Function: _fnScrollDraw
+ * Purpose: Update the various tables for resizing
+ * Returns: node: - Node to add to the DOM
+ * Inputs: object:o - dataTables settings object
+ * Notes: It's a bit of a pig this function, but basically the idea to:
+ * 1. Re-create the table inside the scrolling div
+ * 2. Take live measurements from the DOM
+ * 3. Apply the measurements
+ * 4. Clean up
+ */
+ function _fnScrollDraw ( o )
+ {
+ var
+ nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
+ nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
+ nScrollBody = o.nTable.parentNode,
+ i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+ iWidth, aApplied=[], iSanityWidth;
+
+ /*
+ * 1. Re-create the table inside the scrolling div
+ */
+
+ /* Remove the old minimised thead and tfoot elements in the inner table */
+ var nTheadSize = o.nTable.getElementsByTagName('thead');
+ if ( nTheadSize.length > 0 )
+ {
+ o.nTable.removeChild( nTheadSize[0] );
+ }
+
+ if ( o.nTFoot !== null )
+ {
+ /* Remove the old minimised footer element in the cloned header */
+ var nTfootSize = o.nTable.getElementsByTagName('tfoot');
+ if ( nTfootSize.length > 0 )
+ {
+ o.nTable.removeChild( nTfootSize[0] );
+ }
+ }
+
+ /* Clone the current header and footer elements and then place it into the inner table */
+ nTheadSize = o.nTHead.cloneNode(true);
+ o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
+
+ if ( o.nTFoot !== null )
+ {
+ nTfootSize = o.nTFoot.cloneNode(true);
+ o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
+ }
+
+ /*
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
+ */
+
+ /* Remove old sizing and apply the calculated column widths
+ * Get the unique column headers in the newly created (cloned) header. We want to apply the
+ * calclated sizes to this header
+ */
+ var nThs = _fnGetUniqueThs( nTheadSize );
+ for ( i=0, iLen=nThs.length ; i iSanityWidth-o.oScroll.iBarWidth )
+ {
+ /* Not possible to take account of it */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+ else
+ {
+ /* All else fails */
+ o.nTable.style.width = _fnStringToCss( iSanityWidth );
+ }
+ }
+
+ /* Recalculate the sanity width - now that we've applied the required width, before it was
+ * a temporary variable. This is required because the column width calculation is done
+ * before this table DOM is created.
+ */
+ iSanityWidth = $(o.nTable).outerWidth();
+
+ /* We want the hidden header to have zero height, so remove padding and borders. Then
+ * set the width based on the real headers
+ */
+ anHeadToSize = o.nTHead.getElementsByTagName('tr');
+ anHeadSizers = nTheadSize.getElementsByTagName('tr');
+
+ _fnApplyToChildren( function(nSizer, nToSize) {
+ oStyle = nSizer.style;
+ oStyle.paddingTop = "0";
+ oStyle.paddingBottom = "0";
+ oStyle.borderTopWidth = "0";
+ oStyle.borderBottomWidth = "0";
+ oStyle.height = 0;
+
+ iWidth = $(nSizer).width();
+ nToSize.style.width = _fnStringToCss( iWidth );
+ aApplied.push( iWidth );
+ }, anHeadSizers, anHeadToSize );
+ $(anHeadSizers).height(0);
+
+ if ( o.nTFoot !== null )
+ {
+ /* Clone the current footer and then place it into the body table as a "hidden header" */
+ anFootSizers = nTfootSize.getElementsByTagName('tr');
+ anFootToSize = o.nTFoot.getElementsByTagName('tr');
+
+ _fnApplyToChildren( function(nSizer, nToSize) {
+ oStyle = nSizer.style;
+ oStyle.paddingTop = "0";
+ oStyle.paddingBottom = "0";
+ oStyle.borderTopWidth = "0";
+ oStyle.borderBottomWidth = "0";
+
+ iWidth = $(nSizer).width();
+ nToSize.style.width = _fnStringToCss( iWidth );
+ aApplied.push( iWidth );
+ }, anFootSizers, anFootToSize );
+ $(anFootSizers).height(0);
+ }
+
+ /*
+ * 3. Apply the measurements
+ */
+
+ /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
+ * to what they currently are
+ */
+ _fnApplyToChildren( function(nSizer) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = _fnStringToCss( aApplied.shift() );
+ }, anHeadSizers );
+
+ if ( o.nTFoot !== null )
+ {
+ _fnApplyToChildren( function(nSizer) {
+ nSizer.innerHTML = "";
+ nSizer.style.width = _fnStringToCss( aApplied.shift() );
+ }, anFootSizers );
+ }
+
+ /* Sanity check that the table is of a sensible width. If not then we are going to get
+ * misalignment
+ */
+ if ( $(o.nTable).outerWidth() < iSanityWidth )
+ {
+ if ( o.oScroll.sX === "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. It is suggested that you enable x-scrolling or increase the width"+
+ " the table has in which to be drawn" );
+ }
+ else if ( o.oScroll.sXInner !== "" )
+ {
+ _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+ " misalignment. It is suggested that you increase the sScrollXInner property to"+
+ " allow it to draw in a larger area, or simply remove that parameter to allow"+
+ " automatic calculation" );
+ }
+ }
+
+
+ /*
+ * 4. Clean up
+ */
+
+ if ( o.oScroll.sY === "" )
+ {
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+ * the scrollbar height from the visible display, rather than adding it on. We need to
+ * set the height in order to sort this. Don't want to do it in any other browsers.
+ */
+ if ( $.browser.msie && $.browser.version <= 7 )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
+ }
+ }
+
+ if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
+ {
+ nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
+
+ var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
+ o.oScroll.iBarWidth : 0;
+ if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
+ {
+ nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
+ }
+ }
+
+ /* Finally set the width's of the header and footer tables */
+ var iOuterWidth = $(o.nTable).outerWidth();
+ nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth+o.oScroll.iBarWidth );
+ nScrollHeadInner.parentNode.style.width = _fnStringToCss( $(nScrollBody).width() );
+
+ if ( o.nTFoot !== null )
+ {
+ var
+ nScrollFootInner = o.nScrollFoot.getElementsByTagName('div')[0],
+ nScrollFootTable = nScrollFootInner.getElementsByTagName('table')[0];
+
+ nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth+o.oScroll.iBarWidth );
+ nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
+ }
+
+ /* If sorting or filtering has occured, jump the scrolling back to the top */
+ if ( o.bSorted || o.bFiltered )
+ {
+ nScrollBody.scrollTop = 0;
+ }
+ }
+
+ /*
+ * Function: _fnAjustColumnSizing
+ * Purpose: Ajust the table column widths for new data
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * Notes: You would probably want to do a redraw after calling this function!
+ */
+ function _fnAjustColumnSizing ( oSettings )
+ {
+ /* Not interested in doing column width calculation if autowidth is disabled */
+ if ( oSettings.oFeatures.bAutoWidth === false )
+ {
+ return false;
+ }
+
+ _fnCalculateColumnWidths( oSettings );
+ for ( var i=0 , iLen=oSettings.aoColumns.length ; i';
+
+ var jqFilter = $("input", nFilter);
+ jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','"') );
+ jqFilter.keyup( function(e) {
+ /* Update all other filter input elements for the new display */
+ var n = oSettings.aanFeatures.f;
+ for ( var i=0, iLen=n.length ; i=0 ; i-- )
+ {
+ var sData = _fnDataToSearch( oSettings.aoData[ oSettings.aiDisplay[i] ]._aData[iColumn],
+ oSettings.aoColumns[iColumn].sType );
+ if ( ! rpSearch.test( sData ) )
+ {
+ oSettings.aiDisplay.splice( i, 1 );
+ iIndexCorrector++;
+ }
+ }
+ }
+
+ /*
+ * Function: _fnFilter
+ * Purpose: Filter the data table based on user input and draw the table
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * string:sInput - string to filter on
+ * int:iForce - optional - force a research of the master array (1) or not (undefined or 0)
+ * bool:bRegex - treat as a regular expression or not
+ * bool:bSmart - perform smart filtering or not
+ */
+ function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart )
+ {
+ var i;
+ var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart );
+
+ /* Check if we are forcing or not - optional parameter */
+ if ( typeof iForce == 'undefined' || iForce === null )
+ {
+ iForce = 0;
+ }
+
+ /* Need to take account of custom filtering functions - always filter */
+ if ( _oExt.afnFiltering.length !== 0 )
+ {
+ iForce = 1;
+ }
+
+ /*
+ * If the input is blank - we want the full data set
+ */
+ if ( sInput.length <= 0 )
+ {
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ }
+ else
+ {
+ /*
+ * We are starting a new search or the new search string is smaller
+ * then the old one (i.e. delete). Search from the master array
+ */
+ if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+ oSettings.oPreviousSearch.sSearch.length > sInput.length || iForce == 1 ||
+ sInput.indexOf(oSettings.oPreviousSearch.sSearch) !== 0 )
+ {
+ /* Nuke the old display array - we are going to rebuild it */
+ oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+
+ /* Force a rebuild of the search array */
+ _fnBuildSearchArray( oSettings, 1 );
+
+ /* Search through all records to populate the search array
+ * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1
+ * mapping
+ */
+ for ( i=0 ; i tag - remove it */
+ sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
+ }
+
+ return sSearch;
+ }
+
+ /*
+ * Function: _fnFilterCreateSearch
+ * Purpose: Build a regular expression object suitable for searching a table
+ * Returns: RegExp: - constructed object
+ * Inputs: string:sSearch - string to search for
+ * bool:bRegex - treat as a regular expression or not
+ * bool:bSmart - perform smart filtering or not
+ */
+ function _fnFilterCreateSearch( sSearch, bRegex, bSmart )
+ {
+ var asSearch, sRegExpString;
+
+ if ( bSmart )
+ {
+ /* Generate the regular expression to use. Something along the lines of:
+ * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+ */
+ asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
+ sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+ return new RegExp( sRegExpString, "i" );
+ }
+ else
+ {
+ sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
+ return new RegExp( sSearch, "i" );
+ }
+ }
+
+ /*
+ * Function: _fnDataToSearch
+ * Purpose: Convert raw data into something that the user can search on
+ * Returns: string: - search string
+ * Inputs: string:sData - data to be modified
+ * string:sType - data type
+ */
+ function _fnDataToSearch ( sData, sType )
+ {
+ if ( typeof _oExt.ofnSearch[sType] == "function" )
+ {
+ return _oExt.ofnSearch[sType]( sData );
+ }
+ else if ( sType == "html" )
+ {
+ return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
+ }
+ else if ( typeof sData == "string" )
+ {
+ return sData.replace(/\n/g," ");
+ }
+ return sData;
+ }
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Section - Feature: Sorting
+ */
+
+ /*
+ * Function: _fnSort
+ * Purpose: Change the order of the table
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * bool:bApplyClasses - optional - should we apply classes or not
+ * Notes: We always sort the master array and then apply a filter again
+ * if it is needed. This probably isn't optimal - but atm I can't think
+ * of any other way which is (each has disadvantages). we want to sort aiDisplayMaster -
+ * but according to aoData[]._aData
+ */
+ function _fnSort ( oSettings, bApplyClasses )
+ {
+ var
+ iDataSort, iDataType,
+ i, iLen, j, jLen,
+ aaSort = [],
+ aiOrig = [],
+ oSort = _oExt.oSort,
+ aoData = oSettings.aoData,
+ aoColumns = oSettings.aoColumns;
+
+ /* No sorting required if server-side or no sorting array */
+ if ( !oSettings.oFeatures.bServerSide &&
+ (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
+ {
+ if ( oSettings.aaSortingFixed !== null )
+ {
+ aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+ }
+ else
+ {
+ aaSort = oSettings.aaSorting.slice();
+ }
+
+ /* If there is a sorting data type, and a fuction belonging to it, then we need to
+ * get the data from the developer's function and apply it for this column
+ */
+ for ( i=0 ; i= iColumns )
+ {
+ for ( i=0 ; i=0 ?
+ oSettings._iDisplayStart - oSettings._iDisplayLength :
+ 0;
+
+ /* Correct for underrun */
+ if ( oSettings._iDisplayStart < 0 )
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( sAction == "next" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ /* Make sure we are not over running the display array */
+ if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+ {
+ oSettings._iDisplayStart += oSettings._iDisplayLength;
+ }
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else if ( sAction == "last" )
+ {
+ if ( oSettings._iDisplayLength >= 0 )
+ {
+ var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+ oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+ }
+ else
+ {
+ oSettings._iDisplayStart = 0;
+ }
+ }
+ else
+ {
+ _fnLog( oSettings, 0, "Unknown paging action: "+sAction );
+ }
+
+ return iOldStart != oSettings._iDisplayStart;
+ }
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Section - Feature: HTML info
+ */
+
+ /*
+ * Function: _fnFeatureHtmlInfo
+ * Purpose: Generate the node required for the info display
+ * Returns: node
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnFeatureHtmlInfo ( oSettings )
+ {
+ var nInfo = document.createElement( 'div' );
+ nInfo.className = oSettings.oClasses.sInfo;
+
+ /* Actions that are to be taken once only for this feature */
+ if ( typeof oSettings.aanFeatures.i == "undefined" )
+ {
+ /* Add draw callback */
+ oSettings.aoDrawCallback.push( {
+ "fn": _fnUpdateInfo,
+ "sName": "information"
+ } );
+
+ /* Add id */
+ if ( oSettings.sTableId !== '' )
+ {
+ nInfo.setAttribute( 'id', oSettings.sTableId+'_info' );
+ }
+ }
+
+ return nInfo;
+ }
+
+ /*
+ * Function: _fnUpdateInfo
+ * Purpose: Update the information elements in the display
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnUpdateInfo ( oSettings )
+ {
+ /* Show information about the table */
+ if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
+ {
+ return;
+ }
+
+ var
+ iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
+ iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
+ sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
+ sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
+ sOut;
+
+ /* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ * internally
+ */
+ if ( oSettings.oScroll.bInfinite )
+ {
+ sStart = oSettings.fnFormatNumber( 1 );
+ }
+
+ if ( oSettings.fnRecordsDisplay() === 0 &&
+ oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+ {
+ /* Empty record set */
+ sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
+ }
+ else if ( oSettings.fnRecordsDisplay() === 0 )
+ {
+ /* Rmpty record set after filtering */
+ sOut = oSettings.oLanguage.sInfoEmpty +' '+
+ oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
+ oSettings.oLanguage.sInfoPostFix;
+ }
+ else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+ {
+ /* Normal record set */
+ sOut = oSettings.oLanguage.sInfo.
+ replace('_START_', sStart).
+ replace('_END_', sEnd).
+ replace('_TOTAL_', sTotal)+
+ oSettings.oLanguage.sInfoPostFix;
+ }
+ else
+ {
+ /* Record set after filtering */
+ sOut = oSettings.oLanguage.sInfo.
+ replace('_START_', sStart).
+ replace('_END_', sEnd).
+ replace('_TOTAL_', sTotal) +' '+
+ oSettings.oLanguage.sInfoFiltered.replace('_MAX_',
+ oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+
+ oSettings.oLanguage.sInfoPostFix;
+ }
+
+ if ( oSettings.oLanguage.fnInfoCallback !== null )
+ {
+ sOut = oSettings.oLanguage.fnInfoCallback( oSettings, iStart, iEnd, iMax, iTotal, sOut );
+ }
+
+ var n = oSettings.aanFeatures.i;
+ for ( var i=0, iLen=n.length ; i';
+ var i, iLen;
+
+ if ( oSettings.aLengthMenu.length == 2 && typeof oSettings.aLengthMenu[0] == 'object' &&
+ typeof oSettings.aLengthMenu[1] == 'object' )
+ {
+ for ( i=0, iLen=oSettings.aLengthMenu[0].length ; i'+
+ oSettings.aLengthMenu[1][i]+'';
+ }
+ }
+ else
+ {
+ for ( i=0, iLen=oSettings.aLengthMenu.length ; i'+
+ oSettings.aLengthMenu[i]+'';
+ }
+ }
+ sStdMenu += '';
+
+ var nLength = document.createElement( 'div' );
+ if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.l == "undefined" )
+ {
+ nLength.setAttribute( 'id', oSettings.sTableId+'_length' );
+ }
+ nLength.className = oSettings.oClasses.sLength;
+ nLength.innerHTML = oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu );
+
+ /*
+ * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+ * and Stefan Skopnik for fixing the fix!
+ */
+ $('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);
+
+ $('select', nLength).change( function(e) {
+ var iVal = $(this).val();
+
+ /* Update all other length options for the new display */
+ var n = oSettings.aanFeatures.l;
+ for ( i=0, iLen=n.length ; i oSettings.aiDisplay.length ||
+ oSettings._iDisplayLength == -1 )
+ {
+ oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+ }
+ else
+ {
+ oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+ }
+ }
+ }
+
+ /*
+ * Function: _fnConvertToWidth
+ * Purpose: Convert a CSS unit width to pixels (e.g. 2em)
+ * Returns: int:iWidth - width in pixels
+ * Inputs: string:sWidth - width to be converted
+ * node:nParent - parent to get the with for (required for
+ * relative widths) - optional
+ */
+ function _fnConvertToWidth ( sWidth, nParent )
+ {
+ if ( !sWidth || sWidth === null || sWidth === '' )
+ {
+ return 0;
+ }
+
+ if ( typeof nParent == "undefined" )
+ {
+ nParent = document.getElementsByTagName('body')[0];
+ }
+
+ var iWidth;
+ var nTmp = document.createElement( "div" );
+ nTmp.style.width = sWidth;
+
+ nParent.appendChild( nTmp );
+ iWidth = nTmp.offsetWidth;
+ nParent.removeChild( nTmp );
+
+ return ( iWidth );
+ }
+
+ /*
+ * Function: _fnCalculateColumnWidths
+ * Purpose: Calculate the width of columns for the table
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnCalculateColumnWidths ( oSettings )
+ {
+ var iTableWidth = oSettings.nTable.offsetWidth;
+ var iUserInputs = 0;
+ var iTmpWidth;
+ var iVisibleColumns = 0;
+ var iColums = oSettings.aoColumns.length;
+ var i;
+ var oHeaders = $('th', oSettings.nTHead);
+
+ /* Convert any user input sizes into pixel sizes */
+ for ( i=0 ; itd', nCalcTmp);
+ }
+ jqColSizing.each( function (i) {
+ this.style.width = "";
+
+ var iIndex = _fnVisibleToColumnIndex( oSettings, i );
+ if ( iIndex !== null && oSettings.aoColumns[iIndex].sWidthOrig !== "" )
+ {
+ this.style.width = oSettings.aoColumns[iIndex].sWidthOrig;
+ }
+ } );
+
+ /* Find the biggest td for each column and put it into the table */
+ for ( i=0 ; itd", nCalcTmp);
+ if ( oNodes.length === 0 )
+ {
+ oNodes = $("thead tr:eq(0)>th", nCalcTmp);
+ }
+
+ var iIndex, iCorrector = 0, iWidth;
+ for ( i=0 ; i 0 )
+ {
+ oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
+ }
+ iCorrector++;
+ }
+ }
+
+ oSettings.nTable.style.width = _fnStringToCss( $(nCalcTmp).outerWidth() );
+ nCalcTmp.parentNode.removeChild( nCalcTmp );
+ }
+ }
+
+ /*
+ * Function: _fnScrollingWidthAdjust
+ * Purpose: Adjust a table's width to take account of scrolling
+ * Returns: -
+ * Inputs: object:oSettings - dataTables settings object
+ * node:n - table node
+ */
+ function _fnScrollingWidthAdjust ( oSettings, n )
+ {
+ if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
+ {
+ /* When y-scrolling only, we want to remove the width of the scroll bar so the table
+ * + scroll bar will fit into the area avaialble.
+ */
+ var iOrigWidth = $(n).width();
+ n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
+ }
+ else if ( oSettings.oScroll.sX !== "" )
+ {
+ /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
+ n.style.width = _fnStringToCss( $(n).outerWidth() );
+ }
+ }
+
+ /*
+ * Function: _fnGetWidestNode
+ * Purpose: Get the widest node
+ * Returns: string: - max strlens for each column
+ * Inputs: object:oSettings - dataTables settings object
+ * int:iCol - column of interest
+ * boolean:bFast - Should we use fast (but non-accurate) calculation - optional,
+ * default true
+ * Notes: This operation is _expensive_ (!!!). It requires a lot of DOM interaction, but
+ * this is the only way to reliably get the widest string. For example 'mmm' would be wider
+ * than 'iiii' so we can't just ocunt characters. If this can be optimised it would be good
+ * to do so!
+ */
+ function _fnGetWidestNode( oSettings, iCol, bFast )
+ {
+ /* Use fast not non-accurate calculate based on the strlen */
+ if ( typeof bFast == 'undefined' || bFast )
+ {
+ var iMaxLen = _fnGetMaxLenString( oSettings, iCol );
+ var iFastVis = _fnColumnIndexToVisible( oSettings, iCol);
+ if ( iMaxLen < 0 )
+ {
+ return null;
+ }
+ return oSettings.aoData[iMaxLen].nTr.getElementsByTagName('td')[iFastVis];
+ }
+
+ /* Use the slow approach, but get high quality answers - note that this code is not actually
+ * used by DataTables by default. If you want to use it you can alter the call to
+ * _fnGetWidestNode to pass 'false' as the third argument
+ */
+ var
+ iMax = -1, i, iLen,
+ iMaxIndex = -1,
+ n = document.createElement('div');
+
+ n.style.visibility = "hidden";
+ n.style.position = "absolute";
+ document.body.appendChild( n );
+
+ for ( i=0, iLen=oSettings.aoData.length ; i iMax )
+ {
+ iMax = n.offsetWidth;
+ iMaxIndex = i;
+ }
+ }
+ document.body.removeChild( n );
+
+ if ( iMaxIndex >= 0 )
+ {
+ var iVis = _fnColumnIndexToVisible( oSettings, iCol);
+ var nRet = oSettings.aoData[iMaxIndex].nTr.getElementsByTagName('td')[iVis];
+ if ( nRet )
+ {
+ return nRet;
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Function: _fnGetMaxLenString
+ * Purpose: Get the maximum strlen for each data column
+ * Returns: string: - max strlens for each column
+ * Inputs: object:oSettings - dataTables settings object
+ * int:iCol - column of interest
+ */
+ function _fnGetMaxLenString( oSettings, iCol )
+ {
+ var iMax = -1;
+ var iMaxIndex = -1;
+
+ for ( var i=0 ; i iMax )
+ {
+ iMax = s.length;
+ iMaxIndex = i;
+ }
+ }
+
+ return iMaxIndex;
+ }
+
+ /*
+ * Function: _fnStringToCss
+ * Purpose: Append a CSS unit (only if required) to a string
+ * Returns: 0 if match, 1 if length is different, 2 if no match
+ * Inputs: array:aArray1 - first array
+ * array:aArray2 - second array
+ */
+ function _fnStringToCss( s )
+ {
+ if ( s === null )
+ {
+ return "0px";
+ }
+
+ if ( typeof s == 'number' )
+ {
+ if ( s < 0 )
+ {
+ return "0px";
+ }
+ return s+"px";
+ }
+
+ /* Check if the last character is not 0-9 */
+ var c = s.charCodeAt( s.length-1 );
+ if (c < 0x30 || c > 0x39)
+ {
+ return s;
+ }
+ return s+"px";
+ }
+
+ /*
+ * Function: _fnArrayCmp
+ * Purpose: Compare two arrays
+ * Returns: 0 if match, 1 if length is different, 2 if no match
+ * Inputs: array:aArray1 - first array
+ * array:aArray2 - second array
+ */
+ function _fnArrayCmp( aArray1, aArray2 )
+ {
+ if ( aArray1.length != aArray2.length )
+ {
+ return 1;
+ }
+
+ for ( var i=0 ; i iTarget )
+ {
+ a[i]--;
+ }
+ }
+
+ if ( iTargetIndex != -1 )
+ {
+ a.splice( iTargetIndex, 1 );
+ }
+ }
+
+ /*
+ * Function: _fnReOrderIndex
+ * Purpose: Figure out how to reorder a display list
+ * Returns: array int:aiReturn - index list for reordering
+ * Inputs: object:oSettings - dataTables settings object
+ */
+ function _fnReOrderIndex ( oSettings, sColumns )
+ {
+ var aColumns = sColumns.split(',');
+ var aiReturn = [];
+
+ for ( var i=0, iLen=oSettings.aoColumns.length ; i 4096 ) /* Magic 10 for padding */
+ {
+ var aCookies =document.cookie.split(';');
+ for ( var i=0, iLen=aCookies.length ; itr', this);
+ for ( i=0, iLen=oSettings.asStripClasses.length ; i=0 ; i-- )
+ {
+ /* Each column def can target multiple columns, as it is an array */
+ var aTargets = oInit.aoColumnDefs[i].aTargets;
+ if ( !$.isArray( aTargets ) )
+ {
+ _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
+ }
+ for ( j=0, jLen=aTargets.length ; j= 0 )
+ {
+ /* 0+ integer, left to right column counting. We add columns which are unknown
+ * automatically. Is this the right behaviour for this? We should at least
+ * log it in future. We cannot do this for the negative or class targets, only here.
+ */
+ while( oSettings.aoColumns.length <= aTargets[j] )
+ {
+ _fnAddColumn( oSettings );
+ }
+ _fnColumnOptions( oSettings, aTargets[j], oInit.aoColumnDefs[i] );
+ }
+ else if ( typeof aTargets[j] == 'number' && aTargets[j] < 0 )
+ {
+ /* Negative integer, right to left column counting */
+ _fnColumnOptions( oSettings, oSettings.aoColumns.length+aTargets[j],
+ oInit.aoColumnDefs[i] );
+ }
+ else if ( typeof aTargets[j] == 'string' )
+ {
+ /* Class name matching on TH element */
+ for ( k=0, kLen=oSettings.aoColumns.length ; k= oSettings.aoColumns.length )
+ {
+ oSettings.aaSorting[i][0] = 0;
+ }
+ var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
+
+ /* Add a default sorting index */
+ if ( typeof oSettings.aaSorting[i][2] == 'undefined' )
+ {
+ oSettings.aaSorting[i][2] = 0;
+ }
+
+ /* If aaSorting is not defined, then we use the first indicator in asSorting */
+ if ( typeof oInit.aaSorting == "undefined" &&
+ typeof oSettings.saved_aaSorting == "undefined" )
+ {
+ oSettings.aaSorting[i][1] = oColumn.asSorting[0];
+ }
+
+ /* Set the current sorting index based on aoColumns.asSorting */
+ for ( j=0, jLen=oColumn.asSorting.length ; j 0 )
+ {
+ oSettings.nTFoot = this.getElementsByTagName('tfoot')[0];
+ }
+
+ /* Check if there is data passing into the constructor */
+ if ( bUsePassedData )
+ {
+ for ( i=0 ; i=w-s){s=w-r+1;x=w}else{s=y-Math.ceil(r/2)+1;x=s+r-1}for(r=s;r<=
+x;r++)F+=y!=r?''+r+"":''+r+"";x=g.aanFeatures.p;var z,U=function(){g._iDisplayStart=(this.innerHTML*1-1)*g._iDisplayLength;m(g);return false},C=function(){return false};r=0;for(s=x.length;rm?1:0},"string-desc":function(g,m){g=g.toLowerCase();m=m.toLowerCase();return gm?-1:0},"html-asc":function(g,m){g=g.replace(/<.*?>/g,"").toLowerCase();m=m.replace(/<.*?>/g,"").toLowerCase();return gm?1:0},"html-desc":function(g,m){g=g.replace(/<.*?>/g,"").toLowerCase();m=m.replace(/<.*?>/g,"").toLowerCase();return gm?-1:0},"date-asc":function(g,m){g=Date.parse(g);m=Date.parse(m);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(m)||
+m==="")m=Date.parse("01/01/1970 00:00:00");return g-m},"date-desc":function(g,m){g=Date.parse(g);m=Date.parse(m);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(m)||m==="")m=Date.parse("01/01/1970 00:00:00");return m-g},"numeric-asc":function(g,m){return(g=="-"||g===""?0:g*1)-(m=="-"||m===""?0:m*1)},"numeric-desc":function(g,m){return(m=="-"||m===""?0:m*1)-(g=="-"||g===""?0:g*1)}};n.aTypes=[function(g){if(g.length===0)return"numeric";var m,r=false;m=g.charAt(0);if("0123456789-".indexOf(m)==
+-1)return null;for(var s=1;s")!=-1)return"html";return null}];n.fnVersionCheck=function(g){var m=function(x,v){for(;x.length=parseInt(w,10)};n._oExternConfig={iNextUnique:0};j.fn.dataTable=function(g){function m(){this.fnRecordsTotal=function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsTotal,10):this.aiDisplayMaster.length};this.fnRecordsDisplay=function(){return this.oFeatures.bServerSide?parseInt(this._iRecordsDisplay,10):this.aiDisplay.length};this.fnDisplayEnd=function(){return this.oFeatures.bServerSide?this.oFeatures.bPaginate===false||this._iDisplayLength==-1?
+this._iDisplayStart+this.aiDisplay.length:Math.min(this._iDisplayStart+this._iDisplayLength,this._iRecordsDisplay):this._iDisplayEnd};this.sInstance=this.oInstance=null;this.oFeatures={bPaginate:true,bLengthChange:true,bFilter:true,bSort:true,bInfo:true,bAutoWidth:true,bProcessing:false,bSortClasses:true,bStateSave:false,bServerSide:false};this.oScroll={sX:"",sXInner:"",sY:"",bCollapse:false,bInfinite:false,iLoadGap:100,iBarWidth:0,bAutoCss:true};this.aanFeatures=[];this.oLanguage={sProcessing:"Processing...",
+sLengthMenu:"Show _MENU_ entries",sZeroRecords:"No matching records found",sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sSearch:"Search:",sUrl:"",oPaginate:{sFirst:"First",sPrevious:"Previous",sNext:"Next",sLast:"Last"},fnInfoCallback:null};this.aoData=[];this.aiDisplay=[];this.aiDisplayMaster=[];this.aoColumns=[];this.iNextId=0;this.asDataSearch=
+[];this.oPreviousSearch={sSearch:"",bRegex:false,bSmart:true};this.aoPreSearchCols=[];this.aaSorting=[[0,"asc",0]];this.aaSortingFixed=null;this.asStripClasses=[];this.asDestoryStrips=[];this.sDestroyWidth=0;this.fnFooterCallback=this.fnHeaderCallback=this.fnRowCallback=null;this.aoDrawCallback=[];this.fnInitComplete=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=false;this.aoOpenRows=[];this.sDom="lfrtip";this.sPaginationType="two_button";
+this.iCookieDuration=7200;this.sCookiePrefix="SpryMedia_DataTables_";this.fnCookieCallback=null;this.aoStateSave=[];this.aoStateLoad=[];this.sAjaxSource=this.oLoadedState=null;this.bAjaxDataGet=true;this.fnServerData=function(a,b,c){j.ajax({url:a,data:b,success:c,dataType:"json",cache:false,error:function(d,f){f=="parsererror"&&alert("DataTables warning: JSON data from server could not be parsed. This is caused by a JSON formatting error.")}})};this.fnFormatNumber=function(a){if(a<1E3)return a;else{var b=
+a+"";a=b.split("");var c="";b=b.length;for(var d=0;d=a.fnRecordsDisplay()?0:a.iInitDisplayStart;a.iInitDisplayStart=-1;E(a)}if(!(!a.bDestroying&&a.oFeatures.bServerSide&&!sa(a))){a.oFeatures.bServerSide||a.iDraw++;if(a.aiDisplay.length!==0){var i=a._iDisplayStart,h=a._iDisplayEnd;if(a.oFeatures.bServerSide){i=0;h=a.aoData.length}for(i=
+i;itr",a.nTHead)[0],V(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);
+typeof a.fnFooterCallback=="function"&&a.fnFooterCallback.call(a.oInstance,j(">tr",a.nTFoot)[0],V(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);f=p.createDocumentFragment();b=p.createDocumentFragment();if(a.nTBody){e=a.nTBody.parentNode;b.appendChild(a.nTBody);if(!a.oScroll.bInfinite||!a._bInitComplete||a.bSorted||a.bFiltered){c=a.nTBody.childNodes;for(b=c.length-1;b>=0;b--)c[b].parentNode.removeChild(c[b])}b=0;for(c=d.length;b=0;b--)a.aoDrawCallback[b].fn.call(a.oInstance,a);a.bSorted=false;a.bFiltered=false;a.bDrawing=false;if(a.oFeatures.bServerSide){K(a,false);typeof a._bInitComplete=="undefined"&&w(a)}}}function W(a){if(a.oFeatures.bSort)O(a,a.oPreviousSearch);else if(a.oFeatures.bFilter)P(a,a.oPreviousSearch);else{E(a);C(a)}}function sa(a){if(a.bAjaxDataGet){K(a,true);var b=a.aoColumns.length,c=[],d;a.iDraw++;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",
+value:ca(a)});c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",value:a.oFeatures.bPaginate!==false?a._iDisplayLength:-1});if(a.oFeatures.bFilter!==false){c.push({name:"sSearch",value:a.oPreviousSearch.sSearch});c.push({name:"bRegex",value:a.oPreviousSearch.bRegex});for(d=0;d")c=c.parentNode;
+else if(i=="l"&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange){f=va(a);e=1}else if(i=="f"&&a.oFeatures.bFilter){f=wa(a);e=1}else if(i=="r"&&a.oFeatures.bProcessing){f=xa(a);e=1}else if(i=="t"){f=ya(a);e=1}else if(i=="i"&&a.oFeatures.bInfo){f=za(a);e=1}else if(i=="p"&&a.oFeatures.bPaginate){f=Aa(a);e=1}else if(n.aoFeatures.length!==0){h=n.aoFeatures;q=0;for(k=h.length;qcaption",a.nTable);i=0;for(k=d.length;ij(a.nTable).height()-a.oScroll.iLoadGap)if(a.fnDisplayEnd()0&&a.nTable.removeChild(i[0]);if(a.nTFoot!==null){k=a.nTable.getElementsByTagName("tfoot");k.length>0&&a.nTable.removeChild(k[0])}i=a.nTHead.cloneNode(true);a.nTable.insertBefore(i,a.nTable.childNodes[0]);if(a.nTFoot!==null){k=a.nTFoot.cloneNode(true);a.nTable.insertBefore(k,a.nTable.childNodes[1])}var J=fa(i);f=0;for(e=J.length;ff-a.oScroll.iBarWidth)a.nTable.style.width=u(f)}else a.nTable.style.width=
+u(f);f=j(a.nTable).outerWidth();e=a.nTHead.getElementsByTagName("tr");i=i.getElementsByTagName("tr");L(function(B,I){l=B.style;l.paddingTop="0";l.paddingBottom="0";l.borderTopWidth="0";l.borderBottomWidth="0";l.height=0;t=j(B).width();I.style.width=u(t);G.push(t)},i,e);j(i).height(0);if(a.nTFoot!==null){h=k.getElementsByTagName("tr");k=a.nTFoot.getElementsByTagName("tr");L(function(B,I){l=B.style;l.paddingTop="0";l.paddingBottom="0";l.borderTopWidth="0";l.borderBottomWidth="0";t=j(B).width();I.style.width=
+u(t);G.push(t)},h,k);j(h).height(0)}L(function(B){B.innerHTML="";B.style.width=u(G.shift())},i);a.nTFoot!==null&&L(function(B){B.innerHTML="";B.style.width=u(G.shift())},h);if(j(a.nTable).outerWidth()d.offsetWidth?a.oScroll.iBarWidth:0;if(a.nTable.offsetHeight';var c=j("input",b);c.val(a.oPreviousSearch.sSearch.replace('"',"""));c.keyup(function(){for(var d=a.aanFeatures.f,f=0,e=d.length;f=0;d--){f=ja(a.aoData[a.aiDisplay[d]]._aData[c],a.aoColumns[c].sType);if(!b.test(f)){a.aiDisplay.splice(d,1);e++}}}}function Ca(a,b,c,d,f){var e=ia(b,d,f);if(typeof c=="undefined"||c===null)c=0;if(n.afnFiltering.length!==0)c=1;if(b.length<=0){a.aiDisplay.splice(0,a.aiDisplay.length);a.aiDisplay=a.aiDisplayMaster.slice()}else if(a.aiDisplay.length==a.aiDisplayMaster.length||a.oPreviousSearch.sSearch.length>b.length||c==1||b.indexOf(a.oPreviousSearch.sSearch)!==
+0){a.aiDisplay.splice(0,a.aiDisplay.length);ha(a,1);for(c=0;c/g,"");else if(typeof a=="string")return a.replace(/\n/g," ");return a}function O(a,b){var c,d,f,e,i,h,k=[],l=[],q=n.oSort,t=a.aoData,G=a.aoColumns;if(!a.oFeatures.bServerSide&&(a.aaSorting.length!==0||a.aaSortingFixed!==null)){k=a.aaSortingFixed!==null?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(f=0;f=i)for(b=0;b=0?a._iDisplayStart-a._iDisplayLength:0;if(a._iDisplayStart<0)a._iDisplayStart=0}else if(b=="next")if(a._iDisplayLength>=0){if(a._iDisplayStart+a._iDisplayLength=0){b=parseInt((a.fnRecordsDisplay()-1)/a._iDisplayLength,10)+1;a._iDisplayStart=(b-1)*a._iDisplayLength}else a._iDisplayStart=0;else H(a,0,"Unknown paging action: "+b);return c!=a._iDisplayStart}function za(a){var b=p.createElement("div");b.className=a.oClasses.sInfo;if(typeof a.aanFeatures.i=="undefined"){a.aoDrawCallback.push({fn:Fa,sName:"information"});a.sTableId!==""&&b.setAttribute("id",a.sTableId+"_info")}return b}
+function Fa(a){if(!(!a.oFeatures.bInfo||a.aanFeatures.i.length===0)){var b=a._iDisplayStart+1,c=a.fnDisplayEnd(),d=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),e=a.fnFormatNumber(b),i=a.fnFormatNumber(c),h=a.fnFormatNumber(d),k=a.fnFormatNumber(f);if(a.oScroll.bInfinite)e=a.fnFormatNumber(1);e=a.fnRecordsDisplay()===0&&a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfoEmpty+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()===0?a.oLanguage.sInfoEmpty+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",
+h)+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfo.replace("_START_",e).replace("_END_",i).replace("_TOTAL_",k)+a.oLanguage.sInfoPostFix:a.oLanguage.sInfo.replace("_START_",e).replace("_END_",i).replace("_TOTAL_",k)+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+a.oLanguage.sInfoPostFix;if(a.oLanguage.fnInfoCallback!==null)e=a.oLanguage.fnInfoCallback(a,b,c,d,f,e);a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d;if(a.aLengthMenu.length==2&&typeof a.aLengthMenu[0]=="object"&&typeof a.aLengthMenu[1]=="object"){c=0;for(d=a.aLengthMenu[0].length;c'+a.aLengthMenu[1][c]+""}else{c=0;for(d=a.aLengthMenu.length;c'+a.aLengthMenu[c]+""}b+="";var f=p.createElement("div");
+a.sTableId!==""&&typeof a.aanFeatures.l=="undefined"&&f.setAttribute("id",a.sTableId+"_length");f.className=a.oClasses.sLength;f.innerHTML=a.oLanguage.sLengthMenu.replace("_MENU_",b);j('select option[value="'+a._iDisplayLength+'"]',f).attr("selected",true);j("select",f).change(function(){var e=j(this).val(),i=a.aanFeatures.l;c=0;for(d=i.length;ca.aiDisplay.length||a._iDisplayLength==-1?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Ga(a,b){if(!a||a===null||a==="")return 0;if(typeof b=="undefined")b=p.getElementsByTagName("body")[0];var c=p.createElement("div");c.style.width=a;b.appendChild(c);a=c.offsetWidth;
+b.removeChild(c);return a}function $(a){var b=0,c,d=0,f=a.aoColumns.length,e,i=j("th",a.nTHead);for(e=0;etd",b);e.each(function(h){this.style.width="";h=ga(a,h);if(h!==null&&a.aoColumns[h].sWidthOrig!=="")this.style.width=a.aoColumns[h].sWidthOrig});for(e=0;etd",b);if(f.length===0)f=j("thead tr:eq(0)>th",b);for(e=c=0;e
+0)a.aoColumns[e].sWidth=u(d);c++}a.nTable.style.width=u(j(b).outerWidth());b.parentNode.removeChild(b)}}function Ia(a,b){if(a.oScroll.sX===""&&a.oScroll.sY!==""){j(b).width();b.style.width=u(j(b).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sX!=="")b.style.width=u(j(b).outerWidth())}function Ha(a,b,c){if(typeof c=="undefined"||c){c=Ja(a,b);b=M(a,b);if(c<0)return null;return a.aoData[c].nTr.getElementsByTagName("td")[b]}var d=-1,f,e;c=-1;var i=p.createElement("div");i.style.visibility="hidden";
+i.style.position="absolute";p.body.appendChild(i);f=0;for(e=a.aoData.length;fd){d=i.offsetWidth;c=f}}p.body.removeChild(i);if(c>=0){b=M(a,b);if(a=a.aoData[c].nTr.getElementsByTagName("td")[b])return a}return null}function Ja(a,b){for(var c=-1,d=-1,f=0;fc){c=e.length;d=f}}return d}function u(a){if(a===null)return"0px";if(typeof a=="number"){if(a<0)return"0px";return a+"px"}var b=
+a.charCodeAt(a.length-1);if(b<48||b>57)return a;return a+"px"}function Oa(a,b){if(a.length!=b.length)return 1;for(var c=0;cb&&a[d]--;c!=-1&&a.splice(c,1)}function ua(a,b){b=b.split(",");for(var c=[],d=0,f=a.aoColumns.length;d4096){a=p.cookie.split(";");for(var h=0,k=a.length;h=d.aiDisplay.length){d._iDisplayStart-=d._iDisplayLength;if(d._iDisplayStart<0)d._iDisplayStart=0}if(typeof c=="undefined"||c){E(d);C(d)}return f};this.fnClearTable=function(a){var b=A(this[n.iApiIndex]);da(b);if(typeof a=="undefined"||a)C(b)};this.fnOpen=function(a,b,c){var d=A(this[n.iApiIndex]);this.fnClose(a);var f=
+p.createElement("tr"),e=p.createElement("td");f.appendChild(e);e.className=c;e.colSpan=S(d);e.innerHTML=b;b=j("tr",d.nTBody);j.inArray(a,b)!=-1&&j(f).insertAfter(a);d.aoOpenRows.push({nTr:f,nParent:a});return f};this.fnClose=function(a){for(var b=A(this[n.iApiIndex]),c=0;ctr",d.nTHead)[0];i=j(">tr",d.nTFoot)[0];q=[];h=[];for(f=0;f=S(d)){l.appendChild(q[a]);l=j(">tr",d.nTHead);f=1;for(e=l.length;ftr",d.nTFoot);f=1;for(e=l.length;ftr",d.nTHead);f=1;for(e=l.length;ftr",d.nTFoot);f=1;for(e=l.length;ftd:eq("+k+")",d.aoData[f].nTr)[0])}}d.aoColumns[a].bVisible=true}else{l.removeChild(q[a]);f=0;for(e=d.aoColumns[a].anThExtra.length;ftr>td."+a.oClasses.sRowEmpty,a.nTable).parent().remove();if(a.nTable!=a.nTHead.parentNode){j(">thead",a.nTable).remove();a.nTable.appendChild(a.nTHead)}if(a.nTFoot&&a.nTable!=a.nTFoot.parentNode){j(">tfoot",a.nTable).remove();a.nTable.appendChild(a.nTFoot)}a.nTable.parentNode.removeChild(a.nTable);j(a.nTableWrapper).remove();a.aaSorting=[];a.aaSortingFixed=[];T(a);j(R(a)).removeClass(a.asStripClasses.join(" "));if(a.bJUI){j("th",a.nTHead).removeClass([n.oStdClasses.sSortable,n.oJUIClasses.sSortableAsc,
+n.oJUIClasses.sSortableDesc,n.oJUIClasses.sSortableNone].join(" "));j("th span",a.nTHead).remove()}else j("th",a.nTHead).removeClass([n.oStdClasses.sSortable,n.oStdClasses.sSortableAsc,n.oStdClasses.sSortableDesc,n.oStdClasses.sSortableNone].join(" "));b.appendChild(a.nTable);d=0;for(f=a.aoData.length;dtr:even",c).addClass(a.asDestoryStrips[0]);j(">tr:odd",c).addClass(a.asDestoryStrips[1]);d=0;for(f=D.length;dt<"F"ip>'}if(e.oScroll.sX!==""||e.oScroll.sY!=="")e.oScroll.iBarWidth=Ma();if(typeof g.iDisplayStart!="undefined"&&typeof e.iInitDisplayStart=="undefined"){e.iInitDisplayStart=g.iDisplayStart;e._iDisplayStart=g.iDisplayStart}if(typeof g.bStateSave!="undefined"){e.oFeatures.bStateSave=g.bStateSave;La(e,g);e.aoDrawCallback.push({fn:na,sName:"state_save"})}if(typeof g.aaData!="undefined")h=
+true;if(typeof g!="undefined"&&typeof g.aoData!="undefined")g.aoColumns=g.aoData;if(typeof g.oLanguage!="undefined")if(typeof g.oLanguage.sUrl!="undefined"&&g.oLanguage.sUrl!==""){e.oLanguage.sUrl=g.oLanguage.sUrl;j.getJSON(e.oLanguage.sUrl,null,function(q){y(e,q,true)});i=true}else y(e,g.oLanguage,false)}else g={};if(typeof g.asStripClasses=="undefined"){e.asStripClasses.push(e.oClasses.sStripOdd);e.asStripClasses.push(e.oClasses.sStripEven)}c=false;d=j("tbody>tr",this);a=0;for(b=e.asStripClasses.length;a<
+b;a++)if(d.filter(":lt(2)").hasClass(e.asStripClasses[a])){c=true;break}if(c){e.asDestoryStrips=["",""];if(j(d[0]).hasClass(e.oClasses.sStripOdd))e.asDestoryStrips[0]+=e.oClasses.sStripOdd+" ";if(j(d[0]).hasClass(e.oClasses.sStripEven))e.asDestoryStrips[0]+=e.oClasses.sStripEven;if(j(d[1]).hasClass(e.oClasses.sStripOdd))e.asDestoryStrips[1]+=e.oClasses.sStripOdd+" ";if(j(d[1]).hasClass(e.oClasses.sStripEven))e.asDestoryStrips[1]+=e.oClasses.sStripEven;d.removeClass(e.asStripClasses.join(" "))}a=this.getElementsByTagName("thead");
+c=a.length===0?[]:fa(a[0]);var k;if(typeof g.aoColumns=="undefined"){k=[];a=0;for(b=c.length;a=0;a--){var l=g.aoColumnDefs[a].aTargets;j.isArray(l)||H(e,1,"aTargets must be an array of targets, not a "+typeof l);
+c=0;for(d=l.length;c=0){for(;e.aoColumns.length<=l[c];)F(e);x(e,l[c],g.aoColumnDefs[a])}else if(typeof l[c]=="number"&&l[c]<0)x(e,e.aoColumns.length+l[c],g.aoColumnDefs[a]);else if(typeof l[c]=="string"){b=0;for(f=e.aoColumns.length;b=e.aoColumns.length)e.aaSorting[a][0]=
+0;k=e.aoColumns[e.aaSorting[a][0]];if(typeof e.aaSorting[a][2]=="undefined")e.aaSorting[a][2]=0;if(typeof g.aaSorting=="undefined"&&typeof e.saved_aaSorting=="undefined")e.aaSorting[a][1]=k.asSorting[0];c=0;for(d=k.asSorting.length;c0)e.nTFoot=this.getElementsByTagName("tfoot")[0];if(h)for(a=0;ad)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
+"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
+e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
+"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
+s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
+j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
+toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
+-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
+if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
+b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
+!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
+l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;Ha";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
+k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
+scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
+false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
+1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
+"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
+c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
+else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
+if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
+attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
+b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
+c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
+arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
+d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
+c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
+8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
+"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
+B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
+0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
+break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
+q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
+l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
+m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
+true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
+g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]-
+0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
+if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
+g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
+n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
+function(){var g=k,i=t.createElement("div");i.innerHTML="";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
+p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
+t.createElement("div");g.innerHTML="";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
+function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
+h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
+c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
+2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
+b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
+e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1,
+""],legend:[1,""],thead:[1,""],tr:[2,""],td:[3,""],col:[2,""],area:[1,""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
+c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
+wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
+prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
+this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
+return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
+else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>$2>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
+prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
+b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length-
+1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
+d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
+jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
+zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
+h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
+if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
+d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
+e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/
+
+
+
+
+ DataTables unit testing
+ Running test:
+
+ Test information:
+
+
+