From 8317ee1ece935b5fa2a69458a9ad3505e401af4b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 23 Mar 2012 00:51:38 +0100 Subject: [PATCH 001/287] Prepare code for 6 professional id. --- htdocs/admin/company.php | 47 +++++++++++++++++++++++++------ htdocs/langs/en_US/companies.lang | 17 ++++++----- htdocs/langs/es_ES/companies.lang | 25 ++++++++-------- htdocs/langs/fr_FR/companies.lang | 17 ++++++----- htdocs/langs/pt_BR/companies.lang | 16 +++++++---- 5 files changed, 83 insertions(+), 39 deletions(-) diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index 67b6f9ac83b..011fad9cd7d 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -34,6 +34,8 @@ require_once(DOL_DOCUMENT_ROOT."/core/lib/functions2.lib.php"); require_once(DOL_DOCUMENT_ROOT."/core/class/html.formother.class.php"); require_once(DOL_DOCUMENT_ROOT."/core/class/html.formcompany.class.php"); +$action=GETPOST('action'); + $langs->load("admin"); $langs->load("companies"); @@ -44,8 +46,8 @@ if (!$user->admin) accessforbidden(); * Actions */ -if ( (isset($_POST["action"]) && $_POST["action"] == 'update' && empty($_POST["cancel"])) -|| (isset($_POST["action"]) && $_POST["action"] == 'updateedit') ) +if ( ($action == 'update' && empty($_POST["cancel"])) +|| ($action == 'updateedit') ) { require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php"); @@ -136,6 +138,7 @@ if ( (isset($_POST["action"]) && $_POST["action"] == 'update' && empty($_POST["c dolibarr_set_const($db, "MAIN_INFO_APE",$_POST["ape"],'chaine',0,'',$conf->entity); dolibarr_set_const($db, "MAIN_INFO_RCS",$_POST["rcs"],'chaine',0,'',$conf->entity); dolibarr_set_const($db, "MAIN_INFO_TRAINER",$_POST["trainer"],'chaine',0,'',$conf->entity); + dolibarr_set_const($db, "MAIN_INFO_PROFID6",$_POST["MAIN_INFO_PROFID6"],'chaine',0,'',$conf->entity); dolibarr_set_const($db, "MAIN_INFO_TVAINTRA",$_POST["tva"],'chaine',0,'',$conf->entity); @@ -147,14 +150,14 @@ if ( (isset($_POST["action"]) && $_POST["action"] == 'update' && empty($_POST["c dolibarr_set_const($db, "FACTURE_LOCAL_TAX1_OPTION",$_POST["optionlocaltax1"],'chaine',0,'',$conf->entity); dolibarr_set_const($db, "FACTURE_LOCAL_TAX2_OPTION",$_POST["optionlocaltax2"],'chaine',0,'',$conf->entity); - if ($_POST['action'] != 'updateedit' && ! $message) + if ($action != 'updateedit' && ! $message) { Header("Location: ".$_SERVER["PHP_SELF"]); exit; } } -if ($_GET["action"] == 'addthumb') +if ($action == 'addthumb') { if (file_exists($conf->societe->dir_output.'/logos/'.$_GET["file"])) { @@ -199,7 +202,7 @@ if ($_GET["action"] == 'addthumb') } } -if ($_GET["action"] == 'removelogo') +if ($action == 'removelogo') { require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php"); @@ -263,8 +266,7 @@ print_fiche_titre($langs->trans("CompanyFoundation"),'','setup'); print $langs->trans("CompanyFundationDesc")."
\n"; print "
\n"; -if ((isset($_GET["action"]) && $_GET["action"] == 'edit') -|| (isset($_POST["action"]) && $_POST["action"] == 'updateedit') ) +if ($action == 'edit' || $action == 'updateedit') { /** * Edition des parametres @@ -488,6 +490,22 @@ if ((isset($_GET["action"]) && $_GET["action"] == 'edit') print ''; } + // ProfId6 + if ($langs->transcountry("ProfId6",$country_code) != '-') + { + $var=!$var; + print ''.$langs->transcountry("ProfId6",$country_code).''; + if ($country_code) + { + print ''; + } + else + { + print $countrynotdefined; + } + print ''; + } + // TVA Intra $var=!$var; print ''.$langs->trans("VATIntra").''; @@ -805,6 +823,18 @@ else print ''; } + // ProfId6 + if ($langs->transcountry("ProfId6",$country_code) != '-') + { + $var=!$var; + print ''.$langs->transcountry("ProfId6",$country_code).''; + if ($langs->transcountry("ProfId6",$country_code) != '-') + { + print $conf->global->MAIN_INFO_PROFID6; + } + print ''; + } + // TVA $var=!$var; print ''.$langs->trans("VATIntra").''; @@ -969,6 +999,7 @@ else } -$db->close(); llxFooter(); + +$db->close(); ?> \ No newline at end of file diff --git a/htdocs/langs/en_US/companies.lang b/htdocs/langs/en_US/companies.lang index a9b3a81142b..b153ebd2422 100644 --- a/htdocs/langs/en_US/companies.lang +++ b/htdocs/langs/en_US/companies.lang @@ -93,11 +93,13 @@ ProfId2Short=Prof. id 2 ProfId3Short=Prof. id 3 ProfId4Short=Prof. id 4 ProfId5Short=Prof. id 5 +ProfId6Short=Prof. id 5 ProfId1=Professional ID 1 ProfId2=Professional ID 2 ProfId3=Professional ID 3 ProfId4=Professional ID 4 ProfId5=Professional ID 5 +ProfId6=Professional ID 6 ProfId1AR=Prof Id 1 (CUIT/CUIL) ProfId2AR=Prof Id 2 (Revenu brutes) ProfId3AR=- @@ -113,12 +115,12 @@ ProfId2BE=- ProfId3BE=- ProfId4BE=- ProfId5BE=- -#ProfId1BR=CNAE -#ProfId2BR=CNPJ -#ProfId3BR=CPF -#ProfId4BR=INSS -#ProfId5BR=IE -#ProfId6BR=IM +ProfId1BR=CNPJ +ProfId2BR=IE (Inscricao Estadual) +ProfId3BR=IM (Inscricao Municipal) +ProfId4BR=CPF +#ProfId5BR=CNAE +#ProfId6BR=INSS ProfId1CH=- ProfId2CH=- ProfId3CH=Prof Id 1 (Federal number) @@ -148,7 +150,8 @@ ProfId1FR=Prof Id 1 (SIREN) ProfId2FR=Prof Id 2 (SIRET) ProfId3FR=Prof Id 3 (NAF, old APE) ProfId4FR=Prof Id 4 (RCS/RM) -ProfId5FR=Prof Id 5 +ProfId5FR=- +ProfId6FR=- ProfId1GB=Registration Number ProfId2GB=- ProfId3GB=SIC diff --git a/htdocs/langs/es_ES/companies.lang b/htdocs/langs/es_ES/companies.lang index 8d45c2e63bf..7935411caf7 100644 --- a/htdocs/langs/es_ES/companies.lang +++ b/htdocs/langs/es_ES/companies.lang @@ -95,16 +95,18 @@ ProfId2Short=Prof. id 2 ProfId3Short=Prof. id 3 ProfId4Short=Prof. id 4 ProfId5Short=Prof. id 5 -ProfId1AR=CUIT/CUIL -ProfId2AR=Ingresos brutos -ProfId3AR=- -ProfId4AR=- -ProfId5AR=- +ProfId6Short=Prof. id 6 ProfId1=ID profesional 1 ProfId2=ID profesional 2 ProfId3=ID profesional 3 ProfId4=ID profesional 4 ProfId5=ID profesional 5 +ProfId6=ID profesional 6 +ProfId1AR=CUIT/CUIL +ProfId2AR=Ingresos brutos +ProfId3AR=- +ProfId4AR=- +ProfId5AR=- ProfId1AU=ABN ProfId2AU=- ProfId3AU=- @@ -115,12 +117,12 @@ ProfId2BE=- ProfId3BE=- ProfId4BE=- ProfId5BE=- -#ProfId1BR=CNAE -#ProfId2BR=CNPJ -#ProfId3BR=CPF -#ProfId4BR=INSS -#ProfId5BR=IE -#ProfId6BR=IM +ProfId1BR=CNPJ +ProfId2BR=IE (Inscricao Estadual) +ProfId3BR=IM (Inscricao Municipal) +ProfId4BR=CPF +#ProfId5BR=CNAE +#ProfId6BR=INSS ProfId1CH=- ProfId2CH=- ProfId3CH=Número federado @@ -151,6 +153,7 @@ ProfId2FR=SIRET ProfId3FR=NAF (Ex APE) ProfId4FR=RCS/RM ProfId5FR=- +ProfId6FR=- ProfId1GB=Número registro ProfId2GB=- ProfId3GB=SIC diff --git a/htdocs/langs/fr_FR/companies.lang b/htdocs/langs/fr_FR/companies.lang index 72f1e63930e..57069f1c592 100644 --- a/htdocs/langs/fr_FR/companies.lang +++ b/htdocs/langs/fr_FR/companies.lang @@ -95,11 +95,13 @@ ProfId2Short=Id prof. 2 ProfId3Short=Id prof. 3 ProfId4Short=Id prof. 4 ProfId5Short=Id prof. 5 +ProfId6Short=Id prof. 6 ProfId1=Id professionnel 1 ProfId2=Id professionnel 2 ProfId3=Id professionnel 3 ProfId4=Id professionnel 4 ProfId5=Id professionnel 5 +ProfId6=Id professionnel 6 ProfId1AR=Id prof. 1 (CUIT/CUIL) ProfId2AR=Id prof. 2 (Revenu brutes) ProfId3AR=- @@ -115,12 +117,12 @@ ProfId2BE=- ProfId3BE=- ProfId4BE=- ProfId5BE=- -#ProfId1BR=CNAE -#ProfId2BR=CNPJ -#ProfId3BR=CPF -#ProfId4BR=INSS -#ProfId5BR=IE -#ProfId6BR=IM +ProfId1BR=CNPJ +ProfId2BR=IE (Inscricao Estadual) +ProfId3BR=IM (Inscricao Municipal) +ProfId4BR=CPF +#ProfId5BR=CNAE +#ProfId6BR=INSS ProfId1CH=- ProfId2CH=- ProfId3CH=Numéro fédéral @@ -150,7 +152,8 @@ ProfId1FR=Id prof. 1 (SIREN) ProfId2FR=Id prof. 2 (SIRET) ProfId3FR=Id prof. 3 (NAF, ex APE) ProfId4FR=Id prof. 4 (RCS/RM) -ProfId5FR=Id prof. 5 +ProfId5FR=- +ProfId6FR=- ProfId1GB=Registration Number ProfId2GB=- ProfId3GB=SIC diff --git a/htdocs/langs/pt_BR/companies.lang b/htdocs/langs/pt_BR/companies.lang index b966398e699..d65a1b4b999 100644 --- a/htdocs/langs/pt_BR/companies.lang +++ b/htdocs/langs/pt_BR/companies.lang @@ -84,10 +84,14 @@ ProfId1Short=Prof. id 1 ProfId2Short=Prof. id 2 ProfId3Short=Prof. id 3 ProfId4Short=Prof. id 4 +ProfId5Short=Prof. id 5 +ProfId6Short=Prof. id 6 ProfId1=ID profesional 1 ProfId2=ID profesional 2 ProfId3=ID profesional 3 ProfId4=ID profesional 4 +ProfId5=ID profesional 5 +ProfId6=ID profesional 6 ProfId1AU=ABN ProfId2AU=- ProfId3AU=- @@ -96,6 +100,12 @@ ProfId1BE=Núm da Ordem ProfId2BE=- ProfId3BE=- ProfId4BE=- +ProfId1BR=CNPJ +ProfId2BR=IE (Inscricao Estadual) +ProfId3BR=IM (Inscricao Municipal) +ProfId4BR=CPF +#ProfId5BR=CNAE +#ProfId6BR=INSS ProfId1CH=- ProfId2CH=- ProfId3CH=Número federado @@ -112,12 +122,6 @@ ProfId1PT=NIPC ProfId2PT=Núm. Segurança Social ProfId3PT=Num. Reg. Comercial ProfId4PT=Conservatória -#ProfId1BR=CNAE -#ProfId2BR=CNPJ -#ProfId3BR=CPF -#ProfId4BR=INSS -#ProfId5BR=IE -#ProfId6BR=IM ProfId1TN=RC ProfId2TN=Matrícula Fiscal ProfId3TN=Código na Alfandega From 260aa99904e253672ba97126d0db2542e1f327a5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 23 Mar 2012 09:47:53 +0100 Subject: [PATCH 002/287] Echo message --- build/debian/dolibarr.postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/debian/dolibarr.postinst b/build/debian/dolibarr.postinst index 91e3d9346e8..2276c287c51 100644 --- a/build/debian/dolibarr.postinst +++ b/build/debian/dolibarr.postinst @@ -92,7 +92,7 @@ case "$1" in chown -R root:www-data $config else # File already exist. We add params not found. - // Add new params to overwrite path to use shared libraries/fonts + echo Add new params to overwrite path to use shared libraries/fonts grep -q -c "dolibarr_lib_ADODB_PATH" $config || echo "" >> $config grep -q -c "dolibarr_lib_FPDI_PATH" $config || echo "" >> $config grep -q -c "dolibarr_lib_GEOIP_PATH" $config || echo "" >> $config From 89be120764a4d68ee7d35e7da2441f930d096529 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Fri, 23 Mar 2012 22:44:59 +0800 Subject: [PATCH 003/287] Fix: missing actiontype of canvas --- htdocs/core/class/canvas.class.php | 4 ++-- .../canvas/actions_card_common.class.php | 24 +++++++------------ htdocs/societe/class/societe.class.php | 3 ++- 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/htdocs/core/class/canvas.class.php b/htdocs/core/class/canvas.class.php index 73713118b51..41bab9dee8a 100644 --- a/htdocs/core/class/canvas.class.php +++ b/htdocs/core/class/canvas.class.php @@ -132,7 +132,7 @@ class Canvas { if (empty($this->template_dir)) return 0; - if (file_exists($this->template_dir.($this->card?$this->card.'_':'').$this->action.'.tpl.php')) return 1; + if (file_exists($this->template_dir.($this->card?$this->card.'_':'').$this->actiontype.'.tpl.php')) return 1; else return 0; } @@ -148,7 +148,7 @@ class Canvas global $db, $conf, $langs, $user, $canvas; global $form, $formfile; - include($this->template_dir.($this->card?$this->card.'_':'').$this->action.'.tpl.php'); // Include native PHP template + include($this->template_dir.($this->card?$this->card.'_':'').$this->actiontype.'.tpl.php'); // Include native PHP template } diff --git a/htdocs/societe/canvas/actions_card_common.class.php b/htdocs/societe/canvas/actions_card_common.class.php index fc239fb69a3..15bb0519539 100644 --- a/htdocs/societe/canvas/actions_card_common.class.php +++ b/htdocs/societe/canvas/actions_card_common.class.php @@ -80,17 +80,9 @@ abstract class ActionsCardCommon { $ret = $this->getInstanceDao(); - if (is_object($this->object) && method_exists($this->object,'fetch')) - { - if (! empty($id) || ! empty($ref)) $this->object->fetch($id,$ref); - } - else - { - // TODO Keep only this part of code. Previous in this method is useless - $object = new Societe($this->db); - if (! empty($id) || ! empty($ref)) $object->fetch($id,$ref); - $this->object = $object; - } + $object = new Societe($this->db); + if (! empty($id) || ! empty($ref)) $object->fetch($id,$ref); + $this->object = $object; } /** @@ -398,14 +390,14 @@ abstract class ActionsCardCommon if ($conf->use_javascript_ajax) { $this->tpl['ajax_selecttype'] = "\n".''."\n"; print ''."\n"; } + // jQuery Multiselect + if (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)) + { + print ''."\n"; + } // CKEditor if (! empty($conf->fckeditor->enabled) && (empty($conf->global->FCKEDITOR_EDITORNAME) || $conf->global->FCKEDITOR_EDITORNAME == 'ckeditor')) { From 30fb26296d46d865f09db539ea70751d61102ee4 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Sat, 24 Mar 2012 21:19:22 +0800 Subject: [PATCH 011/287] Fix: add check array in GETPOST New: update multiselect with a fork --- htdocs/core/lib/functions.lib.php | 14 +- .../multiselect/css/ui.multiselect.css | 14 +- .../plugins/multiselect/js/ui.multiselect.js | 242 ++++++++++++++---- 3 files changed, 211 insertions(+), 59 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index a077743dc92..46bc67cee43 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -275,7 +275,7 @@ function dol_shutdown() * Return value of a param into GET or POST supervariable * * @param string $paramname Name of parameter to found - * @param string $check Type of check (''=no check, 'int'=check it's numeric, 'alpha'=check it's alpha only) + * @param string $check Type of check (''=no check, 'int'=check it's numeric, 'alpha'=check it's alpha only, 'array'=check it's array) * @param int $method Type of method (0 = get then post, 1 = only get, 2 = only post, 3 = post then get) * @return string Value found or '' if check fails */ @@ -289,17 +289,25 @@ function GETPOST($paramname,$check='',$method=0) if (! empty($check)) { - $out=trim($out); // Check if numeric - if ($check == 'int' && ! preg_match('/^[-\.,0-9]+$/i',$out)) $out=''; + if ($check == 'int' && ! preg_match('/^[-\.,0-9]+$/i',$out)) + { + $out=trim($out); + $out=''; + } // Check if alpha elseif ($check == 'alpha') { + $out=trim($out); // '"' is dangerous because param in url can close the href= or src= and add javascript functions. // '../' is dangerous because it allows dir transversals if (preg_match('/"/',$out)) $out=''; else if (preg_match('/\.\.\//',$out)) $out=''; } + elseif ($check == 'array') + { + if (! is_array($out) || empty($out)) $out=array(); + } } return $out; diff --git a/htdocs/includes/jquery/plugins/multiselect/css/ui.multiselect.css b/htdocs/includes/jquery/plugins/multiselect/css/ui.multiselect.css index f4599f8fc6b..7d3a44801d2 100644 --- a/htdocs/includes/jquery/plugins/multiselect/css/ui.multiselect.css +++ b/htdocs/includes/jquery/plugins/multiselect/css/ui.multiselect.css @@ -1,25 +1,25 @@ /* Multiselect ----------------------------------*/ -.multiselect { width: 460px; height: 150px; } .ui-multiselect { border: solid 1px; font-size: 0.8em; } .ui-multiselect ul { -moz-user-select: none; } -.ui-multiselect li { margin: 0; padding: 0; cursor: default; line-height: 20px; height: 20px; font-size: 11px; list-style: none; } +.ui-multiselect li { margin: 0; padding: 0; cursor: default; line-height: 20px; height: 20px; font-size: 11px; list-style: none; padding-right: 18px; overflow: hidden; } .ui-multiselect li a { color: #999; text-decoration: none; padding: 0; display: block; float: left; cursor: pointer;} .ui-multiselect li.ui-draggable-dragging { padding-left: 10px; } .ui-multiselect div.selected { position: relative; padding: 0; margin: 0; border: 0; float:left; } .ui-multiselect ul.selected { position: relative; padding: 0; overflow: auto; overflow-x: hidden; background: #fff; margin: 0; list-style: none; border: 0; position: relative; width: 100%; } -.ui-multiselect ul.selected li { } -.ui-multiselect div.available { position: relative; padding: 0; margin: 0; border: 0; float:left; border-left: 1px solid; } +.ui-multiselect div.available { position: relative; padding: 0; margin: 0; border: 0; float:left; } .ui-multiselect ul.available { position: relative; padding: 0; overflow: auto; overflow-x: hidden; background: #fff; margin: 0; list-style: none; border: 0; width: 100%; } .ui-multiselect ul.available li { padding-left: 10px; } - + +.ui-multiselect div.right-column { border-left: 1px solid; } + .ui-multiselect .ui-state-default { border: none; margin-bottom: 1px; position: relative; padding-left: 20px;} .ui-multiselect .ui-state-hover { border: none; } .ui-multiselect .ui-widget-header {border: none; font-size: 11px; margin-bottom: 1px;} - + .ui-multiselect .add-all { float: right; padding: 7px;} .ui-multiselect .remove-all { float: right; padding: 7px;} .ui-multiselect .search { float: left; padding: 4px;} @@ -27,5 +27,5 @@ .ui-multiselect li span.ui-icon-arrowthick-2-n-s { position: absolute; left: 2px; } .ui-multiselect li a.action { position: absolute; right: 2px; top: 2px; } - + .ui-multiselect input.search { height: 14px; padding: 1px; opacity: 0.5; margin: 4px; width: 100px; } \ No newline at end of file diff --git a/htdocs/includes/jquery/plugins/multiselect/js/ui.multiselect.js b/htdocs/includes/jquery/plugins/multiselect/js/ui.multiselect.js index 1234fa7a957..eb4578fc782 100644 --- a/htdocs/includes/jquery/plugins/multiselect/js/ui.multiselect.js +++ b/htdocs/includes/jquery/plugins/multiselect/js/ui.multiselect.js @@ -4,13 +4,13 @@ * Authors: * Michael Aufreiter (quasipartikel.at) * Yanick Rochon (yanick.rochon[at]gmail[dot]com) - * + * * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. - * + * * http://www.quasipartikel.at/multiselect/ * - * + * * Depends: * ui.core.js * ui.sortable.js @@ -18,7 +18,7 @@ * Optional: * localization (http://plugins.jquery.com/project/localisation) * scrollTo (http://plugins.jquery.com/project/ScrollTo) - * + * * Todo: * Make batch actions faster * Implement dynamic insertion through remote calls @@ -30,49 +30,82 @@ $.widget("ui.multiselect", { options: { sortable: true, + dragToAdd: true, searchable: true, doubleClickable: true, animated: 'fast', show: 'slideDown', hide: 'slideUp', dividerLocation: 0.6, + selectedContainerOnLeft: true, + width: null, + height: null, nodeComparator: function(node1,node2) { var text1 = node1.text(), text2 = node2.text(); return text1 == text2 ? 0 : (text1 < text2 ? -1 : 1); - } + }, + includeRemoveAll: true, + includeAddAll: true, + pressEnterKeyToAddAll: false }, _create: function() { this.element.hide(); this.id = this.element.attr("id"); this.container = $('
').insertAfter(this.element); this.count = 0; // number of currently selected options - this.selectedContainer = $('
').appendTo(this.container); - this.availableContainer = $('
').appendTo(this.container); - this.selectedActions = $('
0 '+$.ui.multiselect.locale.itemsCount+''+$.ui.multiselect.locale.removeAll+'
').appendTo(this.selectedContainer); - this.availableActions = $('').appendTo(this.availableContainer); + this.selectedContainer = $('
'); + if (this.options.selectedContainerOnLeft) { + this.selectedContainer.appendTo(this.container); + this.availableContainer = $('
').appendTo(this.container); + this.availableContainer.addClass('right-column'); + } + else + { + this.availableContainer = $('
').appendTo(this.container); + this.selectedContainer.appendTo(this.container); + this.selectedContainer.addClass('right-column'); + } + this.selectedActions = $('
0 '+$.ui.multiselect.locale.itemsCount+''+(this.options.includeRemoveAll?''+$.ui.multiselect.locale.removeAll+'':' ')+'
').appendTo(this.selectedContainer); + this.availableActions = $('
'+(this.options.includeAddAll?''+$.ui.multiselect.locale.addAll+'':' ')+'
').appendTo(this.availableContainer); this.selectedList = $('
').bind('selectstart', function(){return false;}).appendTo(this.selectedContainer); this.availableList = $('
').bind('selectstart', function(){return false;}).appendTo(this.availableContainer); - + var that = this; + var width = this.options.width; + if (!width) { + width = this.element.width(); + } + var height = this.options.height; + if (!height) { + height = this.element.height(); + } + // set dimensions - this.container.width(this.element.width()+1); - this.selectedContainer.width(Math.floor(this.element.width()*this.options.dividerLocation)); - this.availableContainer.width(Math.floor(this.element.width()*(1-this.options.dividerLocation))); + this.container.width(width-2); + if (this.options.selectedContainerOnLeft) { + this.selectedContainer.width(Math.floor(width*this.options.dividerLocation)-1); + this.availableContainer.width(Math.floor(width*(1-this.options.dividerLocation))-2); + } + else + { + this.selectedContainer.width(Math.floor(width*this.options.dividerLocation)-2); + this.availableContainer.width(Math.floor(width*(1-this.options.dividerLocation))-1); + } // fix list height to match '; + } + } + else + { + for ( i=0, iLen=aLengthMenu.length ; i'+aLengthMenu[i]+''; + } + } + sStdMenu += ''; + + var nLength = document.createElement( 'div' ); + if ( !oSettings.aanFeatures.l ) + { + nLength.id = oSettings.sTableId+'_length'; + } + nLength.className = oSettings.oClasses.sLength; + nLength.innerHTML = ''; + + /* + * 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).bind( 'change.DT', 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; + } + } + } + + + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Section - Feature: Filtering + * Note that most of the paging logic is done in + * DataTable.ext.oPagination */ - /* - * Function: _fnFeatureHtmlTable - * Purpose: Add any control elements for the table - specifically scrolling - * Returns: node: - Node to add to the DOM - * Inputs: object:oSettings - dataTables settings object + /** + * Generate the node required for default pagination + * @param {object} oSettings dataTables settings object + * @returns {node} Pagination feature node + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlPaginate ( oSettings ) + { + if ( oSettings.oScroll.bInfinite ) + { + return null; + } + + var nPaginate = document.createElement( 'div' ); + nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType; + + DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, + function( oSettings ) { + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } + ); + + /* Add a draw callback for the pagination on first instance, to update the paging display */ + if ( !oSettings.aanFeatures.p ) + { + oSettings.aoDrawCallback.push( { + "fn": function( oSettings ) { + DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) { + _fnCalculateEnd( oSettings ); + _fnDraw( oSettings ); + } ); + }, + "sName": "pagination" + } ); + } + return nPaginate; + } + + + /** + * Alter the display settings to change the page + * @param {object} oSettings dataTables settings object + * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" + * or page number to jump to (integer) + * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1 + * @memberof DataTable#oApi + */ + function _fnPageChange ( oSettings, mAction ) + { + var iOldStart = oSettings._iDisplayStart; + + if ( typeof mAction === "number" ) + { + oSettings._iDisplayStart = mAction * oSettings._iDisplayLength; + if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() ) + { + oSettings._iDisplayStart = 0; + } + } + else if ( mAction == "first" ) + { + oSettings._iDisplayStart = 0; + } + else if ( mAction == "previous" ) + { + oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ? + oSettings._iDisplayStart - oSettings._iDisplayLength : + 0; + + /* Correct for underrun */ + if ( oSettings._iDisplayStart < 0 ) + { + oSettings._iDisplayStart = 0; + } + } + else if ( mAction == "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 ( mAction == "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: "+mAction ); + } + $(oSettings.oInstance).trigger('page', oSettings); + + return iOldStart != oSettings._iDisplayStart; + } + + + + /** + * Generate the node required for the processing node + * @param {object} oSettings dataTables settings object + * @returns {node} Processing element + * @memberof DataTable#oApi + */ + function _fnFeatureHtmlProcessing ( oSettings ) + { + var nProcessing = document.createElement( 'div' ); + + if ( !oSettings.aanFeatures.r ) + { + nProcessing.id = oSettings.sTableId+'_processing'; + } + nProcessing.innerHTML = oSettings.oLanguage.sProcessing; + nProcessing.className = oSettings.oClasses.sProcessing; + oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable ); + + return nProcessing; + } + + + /** + * Display or hide the processing indicator + * @param {object} oSettings dataTables settings object + * @param {bool} bShow Show the processing indicator (true) or not (false) + * @memberof DataTable#oApi + */ + function _fnProcessingDisplay ( oSettings, bShow ) + { + if ( oSettings.oFeatures.bProcessing ) + { + var an = oSettings.aanFeatures.r; + for ( var i=0, iLen=an.length ; icaption', oSettings.nTable); - for ( var i=0, iLen=nCaptions.length ; i 0 ) { - nScrollHeadTable.appendChild( nCaptions[i] ); + nCaption = nCaption[0]; + if ( nCaption._captionSide === "top" ) + { + nScrollHeadTable.appendChild( nCaption ); + } + else if ( nCaption._captionSide === "bottom" && nTfoot ) + { + nScrollFootTable.appendChild( nCaption ); + } } /* @@ -3883,7 +3050,7 @@ { $(nScrollBody).scroll( function() { /* Use a blocker to stop scrolling from loading more data while other data is still loading */ - if ( !oSettings.bDrawing ) + if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 ) { /* Check if we should load the next data set */ if ( $(this).scrollTop() + $(this).height() > @@ -3907,16 +3074,17 @@ 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: + + /** + * Update the various tables for resizing. 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 + * @param {object} o dataTables settings object + * @returns {node} Node to add to the DOM + * @memberof DataTable#oApi */ function _fnScrollDraw ( o ) { @@ -3925,36 +3093,26 @@ nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], nScrollBody = o.nTable.parentNode, i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, - iWidth, aApplied=[], iSanityWidth; + nTheadSize, nTfootSize, + iWidth, aApplied=[], iSanityWidth, + nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, + nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, + ie67 = $.browser.msie && $.browser.version <= 7; /* * 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] ); - } - } - + $(o.nTable).children('thead, tfoot').remove(); + /* Clone the current header and footer elements and then place it into the inner table */ - nTheadSize = o.nTHead.cloneNode(true); + nTheadSize = $(o.nTHead).clone()[0]; o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] ); if ( o.nTFoot !== null ) { - nTfootSize = o.nTFoot.cloneNode(true); + nTfootSize = $(o.nTFoot).clone()[0]; o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] ); } @@ -3985,6 +3143,14 @@ n.style.width = ""; }, nTfootSize.getElementsByTagName('tr') ); } + + // If scroll collapse is enabled, when we put the headers back into the body for sizing, we + // will end up forcing the scrollbar to appear, making our measurements wrong for when we + // then hide it (end of this function), so add the header height to the body scroller. + if ( o.oScroll.bCollapse && o.oScroll.sY !== "" ) + { + nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px"; + } /* Size the table as a whole */ iSanityWidth = $(o.nTable).outerWidth(); @@ -3994,11 +3160,13 @@ o.nTable.style.width = "100%"; /* I know this is rubbish - but IE7 will make the width of the table when 100% include - * the scrollbar - which is shouldn't. This needs feature detection in future - to do + * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this + * into account. */ - if ( $.browser.msie && $.browser.version <= 7 ) + if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || + $(nScrollBody).css('overflow-y') == "scroll") ) { - o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth ); + o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth); } } else @@ -4032,13 +3200,6 @@ */ iSanityWidth = $(o.nTable).outerWidth(); - /* If x-scrolling is disabled, then the viewport cannot be less than the sanity width */ - if ( o.oScroll.sX === "" ) - { - nScrollBody.style.width = _fnStringToCss( iSanityWidth+o.oScroll.iBarWidth ); - nScrollHeadInner.parentNode.style.width = _fnStringToCss( iSanityWidth+o.oScroll.iBarWidth ); - } - /* We want the hidden header to have zero height, so remove padding and borders. Then * set the width based on the real headers */ @@ -4101,22 +3262,52 @@ } /* Sanity check that the table is of a sensible width. If not then we are going to get - * misalignment + * misalignment - try to prevent this by not allowing the table to shrink below its min width */ if ( $(o.nTable).outerWidth() < iSanityWidth ) { + /* The min width depends upon if we have a vertical scrollbar visible or not */ + var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || + $(nScrollBody).css('overflow-y') == "scroll")) ? + iSanityWidth+o.oScroll.iBarWidth : iSanityWidth; + + /* IE6/7 are a law unto themselves... */ + if ( ie67 && (nScrollBody.scrollHeight > + nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") ) + { + o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth ); + } + + /* Apply the calculated minimum width to the table wrappers */ + nScrollBody.style.width = _fnStringToCss( iCorrection ); + nScrollHeadInner.parentNode.style.width = _fnStringToCss( iCorrection ); + + if ( o.nTFoot !== null ) + { + nScrollFootInner.parentNode.style.width = _fnStringToCss( iCorrection ); + } + + /* And give the user a warning that we've stopped the table getting too small */ 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" ); + " misalignment. The table has been drawn at its minimum possible width." ); } 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" ); + " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+ + " calculation" ); + } + } + else + { + nScrollBody.style.width = _fnStringToCss( '100%' ); + nScrollHeadInner.parentNode.style.width = _fnStringToCss( '100%' ); + + if ( o.nTFoot !== null ) + { + nScrollFootInner.parentNode.style.width = _fnStringToCss( '100%' ); } } @@ -4124,14 +3315,13 @@ /* * 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 ) + if ( ie67 ) { nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth ); } @@ -4145,1320 +3335,75 @@ o.oScroll.iBarWidth : 0; if ( o.nTable.offsetHeight < nScrollBody.offsetHeight ) { - nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra ); + nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+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.style.width = _fnStringToCss( iOuterWidth ); + + // Figure out if there are scrollbar present - if so then we need a the header and footer to + // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) + var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; + nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; 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 ); + nScrollFootTable.style.width = _fnStringToCss( iOuterWidth ); + nScrollFootInner.style.width = _fnStringToCss( iOuterWidth ); + nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; } + + /* Adjust the position of the header incase we loose the y-scrollbar */ + $(nScrollBody).scroll(); - /* If sorting or filtering has occured, jump the scrolling back to the top */ + /* If sorting or filtering has occurred, 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! + + /** + * Apply a given function to the display child nodes of an element array (typically + * TD children of TR rows + * @param {function} fn Method to apply to the objects + * @param array {nodes} an1 List of elements to look through for display children + * @param array {nodes} an2 Another list (identical structure to the first) - optional + * @memberof DataTable#oApi */ - function _fnAjustColumnSizing ( oSettings ) + function _fnApplyToChildren( fn, an1, an2 ) { - /* Not interested in doing column width calculation if autowidth is disabled */ - if ( oSettings.oFeatures.bAutoWidth === false ) + for ( var i=0, iLen=an1.length ; i') : - sSearchStr==="" ? '' : sSearchStr+' '; - - var nFilter = document.createElement( 'div' ); - nFilter.className = oSettings.oClasses.sFilter; - nFilter.innerHTML = ''; - if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.f == "undefined" ) - { - nFilter.setAttribute( 'id', oSettings.sTableId+'_filter' ); - } - - var jqFilter = $("input", nFilter); - jqFilter.val( oSettings.oPreviousSearch.sSearch.replace('"','"') ); - jqFilter.bind( 'keyup.DT', 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( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ), - 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," "); - } - else if ( sData === null ) - { - return ''; - } - 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 = ''; - - /* - * 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).bind( 'change.DT', 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 for filtering data. + *
    + *
  • + * Function input parameters: + *
      + *
    • {*} Data from the column cell to be prepared for filtering
    • + *
    + *
  • + *
  • + * Function return: + *
      + *
    • {string|null} Formatted string that will be used for the filtering.
    • + *
    + * + *
+ * + * Note that as of v1.9, it is typically preferable to use mDataProp to prepare data for + * the different uses that DataTables can put the data to. Specifically mDataProp when + * used as a function will give you a 'type' (sorting, filtering etc) that you can use to + * prepare the data as required for the different types. As such, this method is deprecated. + * @type object + * @default {} + * @deprecated + * + * @example + * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) { + * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" ); + * } + */ + "ofnSearch": {}, + + + /** + * Container for all private functions in DataTables so they can be exposed externally + * @type object + * @default {} + */ + "oApi": {}, + + + /** + * Storage for the various classes that DataTables uses + * @type object + * @default {} + */ + "oStdClasses": {}, + + + /** + * Storage for the various classes that DataTables uses - jQuery UI suitable + * @type object + * @default {} + */ + "oJUIClasses": {}, + + + /** + * Pagination plug-in methods - The style and controls of the pagination can significantly + * impact on how the end user interacts with the data in your table, and DataTables allows + * the addition of pagination controls by extending this object, which can then be enabled + * through the sPaginationType initialisation parameter. Each pagination type that + * is added is an object (the property name of which is what sPaginationType refers + * to) that has two properties, both methods that are used by DataTables to update the + * control's state. + *
    + *
  • + * fnInit - Initialisation of the paging controls. Called only during initialisation + * of the table. It is expected that this function will add the required DOM elements + * to the page for the paging controls to work. The element pointer + * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging + * controls (note that this is a 2D array to allow for multiple instances of each + * DataTables DOM element). It is suggested that you add the controls to this element + * as children + *
      + *
    • + * Function input parameters: + *
        + *
      • {object} DataTables settings object: see {@link DataTable.models.oSettings}.
      • + *
      • {node} Container into which the pagination controls must be inserted
      • + *
      • {function} Draw callback function - whenever the controls cause a page + * change, this method must be called to redraw the table.
      • + *
      + *
    • + *
    • + * Function return: + *
        + *
      • No return required
      • + *
      + * + *
    + * + *
  • + * fnInit - This function is called whenever the paging status of the table changes and is + * typically used to update classes and/or text of the paging controls to reflex the new + * status. + *
      + *
    • + * Function input parameters: + *
        + *
      • {object} DataTables settings object: see {@link DataTable.models.oSettings}.
      • + *
      • {function} Draw callback function - in case you need to redraw the table again + * or attach new event listeners
      • + *
      + *
    • + *
    • + * Function return: + *
        + *
      • No return required
      • + *
      + * + *
    + * + *
+ * @type object + * @default {} + * + * @example + * $.fn.dataTableExt.oPagination.four_button = { + * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) { + * nFirst = document.createElement( 'span' ); + * nPrevious = document.createElement( 'span' ); + * nNext = document.createElement( 'span' ); + * nLast = document.createElement( 'span' ); + * + * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) ); + * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) ); + * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) ); + * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) ); + * + * nFirst.className = "paginate_button first"; + * nPrevious.className = "paginate_button previous"; + * nNext.className="paginate_button next"; + * nLast.className = "paginate_button last"; + * + * nPaging.appendChild( nFirst ); + * nPaging.appendChild( nPrevious ); + * nPaging.appendChild( nNext ); + * nPaging.appendChild( nLast ); + * + * $(nFirst).click( function () { + * oSettings.oApi._fnPageChange( oSettings, "first" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nPrevious).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "previous" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nNext).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "next" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nLast).click( function() { + * oSettings.oApi._fnPageChange( oSettings, "last" ); + * fnCallbackDraw( oSettings ); + * } ); + * + * $(nFirst).bind( 'selectstart', function () { return false; } ); + * $(nPrevious).bind( 'selectstart', function () { return false; } ); + * $(nNext).bind( 'selectstart', function () { return false; } ); + * $(nLast).bind( 'selectstart', function () { return false; } ); + * }, + * + * "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 + *
  • + * Function input parameters: + *
      + *
    • {*} Data to compare to the second parameter
    • + *
    • {*} Data to compare to the first parameter
    • + *
    + *
  • + *
  • + * Function return: + *
      + *
    • {int} Sorting match: <0 if first parameter should be sorted lower than + * the second parameter, ===0 if the two parameters are equal and >0 if + * the first parameter should be sorted height than the second parameter.
    • + *
    + * + * + * @type object + * @default {} + * + * @example + * // Case-sensitive string sorting, with no pre-formatting method + * $.extend( $.fn.dataTableExt.oSort, { + * "string-case-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-case-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + * + * @example + * // Case-insensitive string sorting, with pre-formatting + * $.extend( $.fn.dataTableExt.oSort, { + * "string-pre": function(x) { + * return x.toLowerCase(); + * }, + * "string-asc": function(x,y) { + * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + * }, + * "string-desc": function(x,y) { + * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + * } + * } ); + */ + "oSort": {}, + + + /** + * Version string for plug-ins to check compatibility. 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 + * @type string + * @default Version number + */ + "sVersion": DataTable.version, + + + /** + * How should DataTables report an error. Can take the value 'alert' or 'throw' + * @type string + * @default alert + */ + "sErrMode": "alert", + + + /** + * Store information for DataTables to access globally about other instances + * @namespace + * @private + */ + "_oExternConfig": { + /* int:iNextUnique - next unique number for an instance */ + "iNextUnique": 0 + } + }; + + + + + /** + * Template object for the way in which DataTables holds information about + * search information for the global filter and individual column filters. + * @namespace + */ + DataTable.models.oSearch = { + /** + * Flag to indicate if the filtering should be case insensitive or not + * @type boolean + * @default true + */ + "bCaseInsensitive": true, + + /** + * Applied search term + * @type string + * @default Empty string + */ + "sSearch": "", + + /** + * Flag to indicate if the search term should be interpreted as a + * regular expression (true) or not (false) and therefore and special + * regex characters escaped. + * @type boolean + * @default false + */ + "bRegex": false, + + /** + * Flag to indicate if DataTables is to use its smart filtering or not. + * @type boolean + * @default true + */ + "bSmart": true + }; + + + + + /** + * Template object for the way in which DataTables holds information about + * each individual row. This is the object format used for the settings + * aoData array. + * @namespace + */ + DataTable.models.oRow = { + /** + * TR element for the row + * @type node + * @default null + */ + "nTr": null, + + /** + * Data object from the original data source for the row. This is either + * an array if using the traditional form of DataTables, or an object if + * using mDataProp options. The exact type will depend on the passed in + * data from the data source, or will be an array if using DOM a data + * source. + * @type array|object + * @default [] + */ + "_aData": [], + + /** + * Sorting data cache - this array is ostensibly the same length as the + * number of columns (although each index is generated only as it is + * needed), and holds the data that is used for sorting each column in the + * row. We do this cache generation at the start of the sort in order that + * the formatting of the sort data need be done only once for each cell + * per sort. This array should not be read from or written to by anything + * other than the master sorting methods. + * @type array + * @default [] + * @private + */ + "_aSortData": [], + + /** + * Array of TD elements that are cached for hidden rows, so they can be + * reinserted into the table if a column is made visible again (or to act + * as a store if a column is made hidden). Only hidden columns have a + * reference in the array. For non-hidden columns the value is either + * undefined or null. + * @type array nodes + * @default [] + * @private + */ + "_anHidden": [], + + /** + * Cache of the class name that DataTables has applied to the row, so we + * can quickly look at this variable rather than needing to do a DOM check + * on className for the nTr property. + * @type string + * @default Empty string + * @private + */ + "_sRowStripe": "" + }; + + + + /** + * Template object for the column information object in DataTables. This object + * is held in the settings aoColumns array and contains all the information that + * DataTables needs about each individual column. + * + * Note that this object is related to {@link DataTable.defaults.columns} + * but this one is the internal data store for DataTables's cache of columns. + * It should NOT be manipulated outside of DataTables. Any configuration should + * be done through the initialisation options. + * @namespace + */ + DataTable.models.oColumn = { + /** + * A list of the columns that sorting should occur on when this column + * is sorted. That this property is an array allows multi-column sorting + * to be defined for a column (for example first name / last name columns + * would benefit from this). The values are integers pointing to the + * columns to be sorted on (typically it will be a single integer pointing + * at itself, but that doesn't need to be the case). + * @type array + */ + "aDataSort": null, + + /** + * Define the sorting directions that are applied to the column, in sequence + * as the column is repeatedly sorted upon - i.e. the first value is used + * as the sorting direction when the column if first sorted (clicked on). + * Sort it again (click again) and it will move on to the next index. + * Repeat until loop. + * @type array + */ + "asSorting": null, + + /** + * Flag to indicate if the column is searchable, and thus should be included + * in the filtering or not. + * @type boolean + */ + "bSearchable": null, + + /** + * Flag to indicate if the column is sortable or not. + * @type boolean + */ + "bSortable": null, + + /** + * When using fnRender, you have two options for what to do with the data, + * and this property serves as the switch. Firstly, you can have the sorting + * and filtering use the rendered value (true - default), or you can have + * the sorting and filtering us the original value (false). + * + * *NOTE* It is it is advisable now to use mDataProp as a function and make + * use of the 'type' that it gives, allowing (potentially) different data to + * be used for sorting, filtering, display and type detection. + * @type boolean + * @deprecated + */ + "bUseRendered": null, + + /** + * Flag to indicate if the column is currently visible in the table or not + * @type boolean + */ + "bVisible": null, + + /** + * Flag to indicate to the type detection method if the automatic type + * detection should be used, or if a column type (sType) has been specified + * @type boolean + * @default true + * @private + */ + "_bAutoType": true, + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to fnRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available (since it is not when fnRender is called). + * @type function + * @param {element} nTd The TD node that has been created + * @param {*} sData The Data for the cell + * @param {array|object} oData The data for the whole row + * @param {int} iRow The row index for the aoData data store + * @default null + */ + "fnCreatedCell": null, + + /** + * Function to get data from a cell in a column. You should never + * access data directly through _aData internally in DataTables - always use + * the method attached to this property. It allows mDataProp to function as + * required. This function is automatically assigned by the column + * initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {string} sSpecific The specific data type you want to get - + * 'display', 'type' 'filter' 'sort' + * @returns {*} The data for the cell from the given row's data + * @default null + */ + "fnGetData": null, + + /** + * Custom display function that will be called for the display of each cell + * in this column. + * @type function + * @param {object} o Object with the following parameters: + * @param {int} o.iDataRow The row in aoData + * @param {int} o.iDataColumn The column in question + * @param {array o.aData The data for the row in question + * @param {object} o.oSettings The settings object for this DataTables instance + * @returns {string} The string you which to use in the display + * @default null + */ + "fnRender": null, + + /** + * Function to set data for a cell in the column. You should never + * set the data directly to _aData internally in DataTables - always use + * this method. It allows mDataProp to function as required. This function + * is automatically assigned by the column initialisation method + * @type function + * @param {array|object} oData The data array/object for the array + * (i.e. aoData[]._aData) + * @param {*} sValue Value to set + * @default null + */ + "fnSetData": null, + + /** + * Property to read the value for the cells in the column from the data + * source array / object. If null, then the default content is used, if a + * function is given then the return from the function is used. + * @type function|int|string|null + * @default null + */ + "mDataProp": null, + + /** + * Unique header TH/TD element for this column - this is what the sorting + * listener is attached to (if sorting is enabled.) + * @type node + * @default null + */ + "nTh": null, + + /** + * Unique footer TH/TD element for this column (if there is one). Not used + * in DataTables as such, but can be used for plug-ins to reference the + * footer for each column. + * @type node + * @default null + */ + "nTf": null, + + /** + * The class to apply to all TD elements in the table's TBODY for the column + * @type string + * @default null + */ + "sClass": null, + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * @type string + */ + "sContentPadding": null, + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because mDataProp + * is set to null, or because the data source itself is null). + * @type string + * @default null + */ + "sDefaultContent": null, + + /** + * Name for the column, allowing reference to the column by name as well as + * by index (needs a lookup to work by name). + * @type string + */ + "sName": null, + + /** + * Custom sorting data type - defines which of the available plug-ins in + * afnSortData the custom sorting will use - if any is defined. + * @type string + * @default std + */ + "sSortDataType": 'std', + + /** + * Class to be applied to the header element when sorting on this column + * @type string + * @default null + */ + "sSortingClass": null, + + /** + * Class to be applied to the header element when sorting on this column - + * when jQuery UI theming is used. + * @type string + * @default null + */ + "sSortingClassJUI": null, + + /** + * Title of the column - what is seen in the TH element (nTh). + * @type string + */ + "sTitle": null, + + /** + * Column sorting and filtering type + * @type string + * @default null + */ + "sType": null, + + /** + * Width of the column + * @type string + * @default null + */ + "sWidth": null, + + /** + * Width of the column when it was first "encountered" + * @type string + * @default null + */ + "sWidthOrig": null + }; + + + + /** + * Initialisation options that can be given to DataTables at initialisation + * time. + * @namespace + */ + DataTable.defaults = { + /** + * An array of data to use for the table, passed in at initialisation which + * will be used in preference to any data which is already in the DOM. This is + * particularly useful for constructing tables purely in Javascript, for + * example with a custom Ajax call. + * @type array + * @default null + * @dtopt Option + * + * @example + * // Using a 2D array data source + * $(document).ready( function () { + * $('#example').dataTable( { + * "aaData": [ + * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], + * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], + * ], + * "aoColumns": [ + * { "sTitle": "Engine" }, + * { "sTitle": "Browser" }, + * { "sTitle": "Platform" }, + * { "sTitle": "Version" }, + * { "sTitle": "Grade" } + * ] + * } ); + * } ); + * + * @example + * // Using an array of objects as a data source (mDataProp) + * $(document).ready( function () { + * $('#example').dataTable( { + * "aaData": [ + * { + * "engine": "Trident", + * "browser": "Internet Explorer 4.0", + * "platform": "Win 95+", + * "version": 4, + * "grade": "X" + * }, + * { + * "engine": "Trident", + * "browser": "Internet Explorer 5.0", + * "platform": "Win 95+", + * "version": 5, + * "grade": "C" + * } + * ], + * "aoColumns": [ + * { "sTitle": "Engine", "mDataProp": "engine" }, + * { "sTitle": "Browser", "mDataProp": "browser" }, + * { "sTitle": "Platform", "mDataProp": "platform" }, + * { "sTitle": "Version", "mDataProp": "version" }, + * { "sTitle": "Grade", "mDataProp": "grade" } + * ] + * } ); + * } ); + */ + "aaData": null, + + + /** + * If sorting is enabled, then DataTables will perform a first pass sort on + * initialisation. You can define which column(s) the sort is performed upon, + * and the sorting direction, with this variable. The aaSorting array should + * contain an array for each column to be sorted initially containing the + * column's index and a direction string ('asc' or 'desc'). + * @type array + * @default [[0,'asc']] + * @dtopt Option + * + * @example + * // Sort by 3rd column first, and then 4th column + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSorting": [[2,'asc'], [3,'desc']] + * } ); + * } ); + * + * // No initial sorting + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSorting": [] + * } ); + * } ); + */ + "aaSorting": [[0,'asc']], + + + /** + * This parameter is basically identical to the aaSorting parameter, but + * cannot be overridden by user interaction with the table. What this means + * is that you could have a column (visible or hidden) which the sorting will + * always be forced on first - any sorting after that (from the user) will + * then be performed as required. This can be useful for grouping rows + * together. + * @type array + * @default null + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aaSortingFixed": [[0,'asc']] + * } ); + * } ) + */ + "aaSortingFixed": null, + + + /** + * This parameter allows you to readily specify the entries in the length drop + * down menu that DataTables shows when pagination is enabled. It can be + * either a 1D array of options which will be used for both the displayed + * option and the value, or a 2D array which will use the array in the first + * position as the value, and the array in the second position as the + * displayed options (useful for language strings such as 'All'). + * @type array + * @default [ 10, 25, 50, 100 ] + * @dtopt Option + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] + * } ); + * } ); + * + * @example + * // Setting the default display length as well as length menu + * // This is likely to be wanted if you remove the '10' option which + * // is the iDisplayLength default. + * $(document).ready(function() { + * $('#example').dataTable( { + * "iDisplayLength": 25, + * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]] + * } ); + * } ); + */ + "aLengthMenu": [ 10, 25, 50, 100 ], + + + /** + * The aoColumns option in the initialisation parameter allows you to define + * details about the way individual columns behave. For a full list of + * column options that can be set, please see + * {@link DataTable.defaults.columns}. Note that if you use aoColumns to + * define your columns, you must have an entry in the array for every single + * column that you have in your table (these can be null if you don't which + * to specify any options). + * @member + */ + "aoColumns": null, + + /** + * Very similar to aoColumns, aoColumnDefs allows you to target a specific + * column, multiple columns, or all columns, using the aTargets property of + * each object in the array. This allows great flexibility when creating + * tables, as the aoColumnDefs arrays can be of any length, targeting the + * columns you specifically want. aoColumnDefs may use any of the column + * options available: {@link DataTable.defaults.columns}, but it _must_ + * have aTargets defined in each object in the array. Values in the aTargets + * array may be: + *
      + *
    • a string - class name will be matched on the TH for the column
    • + *
    • 0 or a positive integer - column index counting from the left
    • + *
    • a negative integer - column index counting from the right
    • + *
    • the string "_all" - all columns (i.e. assign a default)
    • + *
    + * @member + */ + "aoColumnDefs": null, + + + /** + * Basically the same as oSearch, this parameter defines the individual column + * filtering state at initialisation time. The array must be of the same size + * as the number of columns, and each element be an object with the parameters + * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also + * accepted and the default will be used. + * @type array + * @default [] + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "aoSearchCols": [ + * null, + * { "sSearch": "My filter" }, + * null, + * { "sSearch": "^[0-9]", "bEscapeRegex": false } + * ] + * } ); + * } ) + */ + "aoSearchCols": [], + + + /** + * An array of CSS classes that should be applied to displayed rows. This + * array may be of any length, and DataTables will apply each class + * sequentially, looping when required. + * @type array + * @default null Will take the values determinted by the oClasses.sStripe* + * options + * @dtopt Option + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ] + * } ); + * } ) + */ + "asStripeClasses": null, + + + /** + * Enable or disable automatic column width calculation. This can be disabled + * as an optimisation (it takes some time to calculate the widths) if the + * tables widths are passed in using aoColumns. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bAutoWidth": false + * } ); + * } ); + */ + "bAutoWidth": true, + + + /** + * Deferred rendering can provide DataTables with a huge speed boost when you + * are using an Ajax or JS data source for the table. This option, when set to + * true, will cause DataTables to defer the creation of the table elements for + * each row until they are needed for a draw - saving a significant amount of + * time. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/arrays.txt", + * "bDeferRender": true + * } ); + * } ); + */ + "bDeferRender": false, + + + /** + * Replace a DataTable which matches the given selector and replace it with + * one which has the properties of the new initialisation object passed. If no + * table matches the selector, then the new DataTable will be constructed as + * per normal. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * + * // Some time later.... + * $('#example').dataTable( { + * "bFilter": false, + * "bDestroy": true + * } ); + * } ); + */ + "bDestroy": false, + + + /** + * Enable or disable filtering of data. Filtering in DataTables is "smart" in + * that it allows the end user to input multiple words (space separated) and + * will match a row containing those words, even if not in the order that was + * specified (this allow matching across multiple columns). Note that if you + * wish to use filtering in DataTables this must remain 'true' - to remove the + * default filtering input box and retain filtering abilities, please use + * {@link DataTable.defaults.sDom}. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bFilter": false + * } ); + * } ); + */ + "bFilter": true, + + + /** + * Enable or disable the table information display. This shows information + * about the data that is currently visible on the page, including information + * about filtered data if that action is being performed. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bInfo": false + * } ); + * } ); + */ + "bInfo": true, + + + /** + * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some + * slightly different and additional mark-up from what DataTables has + * traditionally used). + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "bJQueryUI": true + * } ); + * } ); + */ + "bJQueryUI": false, + + + /** + * Allows the end user to select the size of a formatted page from a select + * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate). + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bLengthChange": false + * } ); + * } ); + */ + "bLengthChange": true, + + + /** + * Enable or disable pagination. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bPaginate": false + * } ); + * } ); + */ + "bPaginate": true, + + + /** + * Enable or disable the display of a 'processing' indicator when the table is + * being processed (e.g. a sort). This is particularly useful for tables with + * large amounts of data where it can take a noticeable amount of time to sort + * the entries. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bProcessing": true + * } ); + * } ); + */ + "bProcessing": false, + + + /** + * Retrieve the DataTables object for the given selector. Note that if the + * table has already been initialised, this parameter will cause DataTables + * to simply return the object that has already been set up - it will not take + * account of any changes you might have made to the initialisation object + * passed to DataTables (setting this parameter to true is an acknowledgement + * that you understand this). bDestroy can be used to reinitialise a table if + * you need. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready(function() { + * initTable(); + * tableActions(); + * } ); + * + * function initTable () + * { + * return $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false, + * "bRetrieve": true + * } ); + * } + * + * function tableActions () + * { + * var oTable = initTable(); + * // perform API operations with oTable + * } + */ + "bRetrieve": false, + + + /** + * Indicate if DataTables should be allowed to set the padding / margin + * etc for the scrolling header elements or not. Typically you will want + * this. + * @type boolean + * @default true + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bScrollAutoCss": false, + * "sScrollY": "200px" + * } ); + * } ); + */ + "bScrollAutoCss": true, + + + /** + * When vertical (y) scrolling is enabled, DataTables will force the height of + * the table's viewport to the given height at all times (useful for layout). + * However, this can look odd when filtering data down to a small data set, + * and the footer is left "floating" further down. This parameter (when + * enabled) will cause DataTables to collapse the table's viewport down when + * the result set will fit within the given Y height. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sScrollY": "200", + * "bScrollCollapse": true + * } ); + * } ); + */ + "bScrollCollapse": false, + + + /** + * Enable infinite scrolling for DataTables (to be used in combination with + * sScrollY). Infinite scrolling means that DataTables will continually load + * data as a user scrolls through a table, which is very useful for large + * dataset. This cannot be used with pagination, which is automatically + * disabled. Note - the Scroller extra for DataTables is recommended in + * in preference to this option. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bScrollInfinite": true, + * "bScrollCollapse": true, + * "sScrollY": "200px" + * } ); + * } ); + */ + "bScrollInfinite": false, + + + /** + * Configure DataTables to use server-side processing. Note that the + * sAjaxSource parameter must also be given in order to give DataTables a + * source to obtain the required data for each draw. + * @type boolean + * @default false + * @dtopt Features + * @dtopt Server-side + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "xhr.php" + * } ); + * } ); + */ + "bServerSide": false, + + + /** + * Enable or disable sorting of columns. Sorting of individual columns can be + * disabled by the "bSortable" option for each column. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bSort": false + * } ); + * } ); + */ + "bSort": true, + + + /** + * Allows control over whether DataTables should use the top (true) unique + * cell that is found for a single column, or the bottom (false - default). + * This is useful when using complex headers. + * @type boolean + * @default false + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bSortCellsTop": true + * } ); + * } ); + */ + "bSortCellsTop": false, + + + /** + * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and + * 'sorting_3' to the columns which are currently being sorted on. This is + * presented as a feature switch as it can increase processing time (while + * classes are removed and added) so for large data sets you might want to + * turn this off. + * @type boolean + * @default true + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bSortClasses": false + * } ); + * } ); + */ + "bSortClasses": true, + + + /** + * Enable or disable state saving. When enabled a cookie will be used to save + * table display information such as pagination information, display length, + * filtering and sorting. As such when the end user reloads the page the + * display display will match what thy had previously set up. + * @type boolean + * @default false + * @dtopt Features + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "bStateSave": true + * } ); + * } ); + */ + "bStateSave": false, + + + /** + * Customise the cookie and / or the parameters being stored when using + * DataTables with state saving enabled. This function is called whenever + * the cookie is modified, and it expects a fully formed cookie string to be + * returned. Note that the data object passed in is a Javascript object which + * must be converted to a string (JSON.stringify for example). + * @type function + * @param {string} sName Name of the cookie defined by DataTables + * @param {object} oData Data to be stored in the cookie + * @param {string} sExpires Cookie expires string + * @param {string} sPath Path of the cookie to set + * @returns {string} Cookie formatted string (which should be encoded by + * using encodeURIComponent()) + * @dtopt Callbacks + * + * @example + * $(document).ready( function () { + * $('#example').dataTable( { + * "fnCookieCallback": function (sName, oData, sExpires, sPath) { + * // Customise oData or sName or whatever else here + * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath; + * } + * } ); + * } ); + */ + "fnCookieCallback": null, + + + /** + * This function is called when a TR element is created (and all TD child + * elements have been inserted), or registered if using a DOM source, allowing + * manipulation of the TR element (adding classes etc). + * @type function + * @param {node} nRow "TR" element for the current row + * @param {array} aData Raw data array for this row + * @param {int} iDataIndex The index of this row in aoData + * @dtopt Callbacks + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "fnCreatedRow": function( nRow, aData, iDataIndex ) { + * // Bold the grade for all 'A' grade browsers + * if ( aData[4] == "A" ) + * { + * $('td:eq(4)', nRow).html( 'A' ); + * } + * } + * } ); + * } ); + */ + "fnCreatedRow": null, + + + /** + * This function is called on every 'draw' event, and allows you to + * dynamically modify any aspect you want about the created DOM. + * @type function + * @param {object} oSettings DataTables settings object + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnDrawCallback": function( oSettings ) { + * alert( 'DataTables has redrawn the table' ); + * } + * } ); + * } ); + */ + "fnDrawCallback": null, + + + /** + * Identical to fnHeaderCallback() but for the table footer this function + * allows you to modify the table footer on every 'draw' even. + * @type function + * @param {node} nFoot "TR" element for the footer + * @param {array} aData Full table data (as derived from the original HTML) + * @param {int} iStart Index for the current display starting point in the + * display array + * @param {int} iEnd Index for the current display ending point in the + * display array + * @param {array int} aiDisplay Index array to translate the visual position + * to the full data array + * @dtopt Callbacks + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) { + * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart; + * } + * } ); + * } ) + */ + "fnFooterCallback": null, + + + /** + * When rendering large numbers in the information element for the table + * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers + * to have a comma separator for the 'thousands' units (e.g. 1 million is + * rendered as "1,000,000") to help readability for the end user. This + * function will override the default method DataTables uses. + * @type function + * @member + * @param {int} iIn number to be formatted + * @returns {string} formatted string for DataTables to show the number + * @dtopt Callbacks + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "fnFormatNumber": function ( iIn ) { + * if ( iIn < 1000 ) { + * return iIn; + * } else { + * var + * s=(iIn+""), + * a=s.split(""), out="", + * iLen=s.length; + * + * for ( var i=0 ; i<iLen ; i++ ) { + * if ( i%3 === 0 && i !== 0 ) { + * out = "'"+out; + * } + * out = a[iLen-i-1]+out; + * } + * } + * return out; + * }; + * } ); + * } ); + */ + "fnFormatNumber": function ( iIn ) { + if ( iIn < 1000 ) + { + // A small optimisation for what is likely to be the majority of use cases + return iIn; + } + + var s=(iIn+""), a=s.split(""), out="", iLen=s.length; + + for ( var i=0 ; iA
    ' ); + * } + * } + * } ); + * } ); + */ + "fnRowCallback": null, + + + /** + * This parameter allows you to override the default function which obtains + * the data from the server ($.getJSON) so something more suitable for your + * application. For example you could use POST data, or pull information from + * a Gears or AIR database. + * @type function + * @member + * @param {string} sSource HTTP source to obtain the data from (sAjaxSource) + * @param {array} aoData A key/value pair object containing the data to send + * to the server + * @param {function} fnCallback to be called on completion of the data get + * process that will draw the data on the page. + * @param {object} oSettings DataTables settings object + * @dtopt Callbacks + * @dtopt Server-side + * + * @example + * // POST data to server + * $(document).ready(function() { + * $('#example').dataTable( { + * "bProcessing": true, + * "bServerSide": true, + * "sAjaxSource": "xhr.php", + * "fnServerData": function ( sSource, aoData, fnCallback ) { + * $.ajax( { + * "dataType": 'json', + * "type": "POST", + * "url": sSource, + * "data": aoData, + * "success": fnCallback + * } ); + * } + * } ); + * } ); + */ + "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) { + oSettings.jqXHR = $.ajax( { + "url": sUrl, + "data": aoData, + "success": function (json) { + $(oSettings.oInstance).trigger('xhr', oSettings); + fnCallback( json ); + }, + "dataType": "json", + "cache": false, + "type": oSettings.sServerMethod, + "error": function (xhr, error, thrown) { + if ( error == "parsererror" ) { + oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+ + "server could not be parsed. This is caused by a JSON formatting error." ); + } + } + } ); + }, + + + /** + * It is often useful to send extra data to the server when making an Ajax + * request - for example custom filtering information, and this callback + * function makes it trivial to send extra information to the server. The + * passed in parameter is the data set that has been constructed by + * DataTables, and you can add to this or modify it as you require. + * @type function + * @param {array} aoData Data array (array of objects which are name/value + * pairs) that has been constructed by DataTables and will be sent to the + * server. In the case of Ajax sourced data with server-side processing + * this will be an empty array, for server-side processing there will be a + * significant number of parameters! + * @returns {undefined} Ensure that you modify the aoData array passed in, + * as this is passed by reference. + * @dtopt Callbacks + * @dtopt Server-side + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bProcessing": true, + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "fnServerParams": function ( aoData ) { + * aoData.push( { "name": "more_data", "value": "my_value" } ); + * } + * } ); + * } ); + */ + "fnServerParams": null, + + + /** + * Load the table state. With this function you can define from where, and how, the + * state of a table is loaded. By default DataTables will load from its state saving + * cookie, but you might wish to use local storage (HTML5) or a server-side database. + * @type function + * @member + * @param {object} oSettings DataTables settings object + * @return {object} The DataTables state object to be loaded + * @dtopt Callbacks + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoad": function (oSettings, oData) { + * var o; + * + * // Send an Ajax request to the server to get the data. Note that + * // this is a synchronous request. + * $.ajax( { + * "url": "/state_load", + * "async": false, + * "dataType": "json", + * "success": function (json) { + * o = json; + * } + * } ); + * + * return o; + * } + * } ); + * } ); + */ + "fnStateLoad": function ( oSettings ) { + var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance ); + var oData; + + try { + oData = (typeof $.parseJSON === 'function') ? + $.parseJSON(sData) : eval( '('+sData+')' ); + } catch (e) { + oData = null; + } + + return oData; + }, + + + /** + * Callback which allows modification of the saved state prior to loading that state. + * This callback is called when the table is loading state from the stored data, but + * prior to the settings object being modified by the saved state. Note that for + * plug-in authors, you should use the 'stateLoadParams' event to load parameters for + * a plug-in. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object that is to be loaded + * @dtopt Callbacks + * + * @example + * // Remove a saved filter, so filtering is never loaded + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoadParams": function (oSettings, oData) { + * oData.oSearch.sSearch = ""; + * } ); + * } ); + * + * @example + * // Disallow state loading by returning false + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoadParams": function (oSettings, oData) { + * return false; + * } ); + * } ); + */ + "fnStateLoadParams": null, + + + /** + * Callback that is called when the state has been loaded from the state saving method + * and the DataTables settings object has been modified as a result of the loaded state. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object that was loaded + * @dtopt Callbacks + * + * @example + * // Show an alert with the filtering value that was saved + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateLoaded": function (oSettings, oData) { + * alert( 'Saved filter was: '+oData.oSearch.sSearch ); + * } ); + * } ); + */ + "fnStateLoaded": null, + + + /** + * Save the table state. This function allows you to define where and how the state + * information for the table is stored - by default it will use a cookie, but you + * might want to use local storage (HTML5) or a server-side database. + * @type function + * @member + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object to be saved + * @dtopt Callbacks + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateSave": function (oSettings, oData) { + * // Send an Ajax request to the server with the state object + * $.ajax( { + * "url": "/state_save", + * "data": oData, + * "dataType": "json", + * "method": "POST" + * "success": function () {} + * } ); + * } + * } ); + * } ); + */ + "fnStateSave": function ( oSettings, oData ) { + this.oApi._fnCreateCookie( + oSettings.sCookiePrefix+oSettings.sInstance, + this.oApi._fnJsonString(oData), + oSettings.iCookieDuration, + oSettings.sCookiePrefix, + oSettings.fnCookieCallback + ); + }, + + + /** + * Callback which allows modification of the state to be saved. Called when the table + * has changed state a new state save is required. This method allows modification of + * the state saving object prior to actually doing the save, including addition or + * other state properties or modification. Note that for plug-in authors, you should + * use the 'stateSaveParams' event to save parameters for a plug-in. + * @type function + * @param {object} oSettings DataTables settings object + * @param {object} oData The state object to be saved + * @dtopt Callbacks + * + * @example + * // Remove a saved filter, so filtering is never saved + * $(document).ready(function() { + * $('#example').dataTable( { + * "bStateSave": true, + * "fnStateSaveParams": function (oSettings, oData) { + * oData.oSearch.sSearch = ""; + * } ); + * } ); + */ + "fnStateSaveParams": null, + + + /** + * Duration of the cookie which is used for storing session information. This + * value is given in seconds. + * @type int + * @default 7200 (2 hours) + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iCookieDuration": 60*60*24 // 1 day + * } ); + * } ) + */ + "iCookieDuration": 7200, + + + /** + * When enabled DataTables will not make a request to the server for the first + * page draw - rather it will use the data already on the page (no sorting etc + * will be applied to it), thus saving on an XHR at load time. iDeferLoading + * is used to indicate that deferred loading is required, but it is also used + * to tell DataTables how many records there are in the full table (allowing + * the information element and pagination to be displayed correctly). In the case + * where a filtering is applied to the table on initial load, this can be + * indicated by giving the parameter as an array, where the first element is + * the number of records available after filtering and the second element is the + * number of records without filtering (allowing the table information element + * to be shown correctly). + * @type int | array + * @default null + * @dtopt Options + * + * @example + * // 57 records available in the table, no filtering applied + * $(document).ready(function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "iDeferLoading": 57 + * } ); + * } ); + * + * @example + * // 57 records after filtering, 100 without filtering (an initial filter applied) + * $(document).ready(function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/server_processing.php", + * "iDeferLoading": [ 57, 100 ], + * "oSearch": { + * "sSearch": "my_filter" + * } + * } ); + * } ); + */ + "iDeferLoading": null, + + + /** + * Number of rows to display on a single page when using pagination. If + * feature enabled (bLengthChange) then the end user will be able to override + * this to a custom setting using a pop-up menu. + * @type int + * @default 10 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iDisplayLength": 50 + * } ); + * } ) + */ + "iDisplayLength": 10, + + + /** + * Define the starting point for data display when using DataTables with + * pagination. Note that this parameter is the number of records, rather than + * the page number, so if you have 10 records per page and want to start on + * the third page, it should be "20". + * @type int + * @default 0 + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "iDisplayStart": 20 + * } ); + * } ) + */ + "iDisplayStart": 0, + + + /** + * The scroll gap is the amount of scrolling that is left to go before + * DataTables will load the next 'page' of data automatically. You typically + * want a gap which is big enough that the scrolling will be smooth for the + * user, while not so large that it will load more data than need. + * @type int + * @default 100 + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bScrollInfinite": true, + * "bScrollCollapse": true, + * "sScrollY": "200px", + * "iScrollLoadGap": 50 + * } ); + * } ); + */ + "iScrollLoadGap": 100, + + + /** + * By default DataTables allows keyboard navigation of the table (sorting, paging, + * and filtering) by adding a tabindex attribute to the required elements. This + * allows you to tab through the controls and press the enter key to activate them. + * The tabindex is default 0, meaning that the tab follows the flow of the document. + * You can overrule this using this parameter if you wish. Use a value of -1 to + * disable built-in keyboard navigation. + * @type int + * @default 0 + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "iTabIndex": 1 + * } ); + * } ); + */ + "iTabIndex": 0, + + + /** + * All strings that DataTables uses in the user interface that it creates + * are defined in this object, allowing you to modified them individually or + * completely replace them all as required. + * @namespace + */ + "oLanguage": { + /** + * Strings that are used for WAI-ARIA labels and controls only (these are not + * actually visible on the page, but will be read by screenreaders, and thus + * must be internationalised as well). + * @namespace + */ + "oAria": { + /** + * ARIA label that is added to the table headers when the column may be + * sorted ascending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oAria": { + * "sSortAscending": " - click/return to sort ascending" + * } + * } + * } ); + * } ); + */ + "sSortAscending": ": activate to sort column ascending", + + /** + * ARIA label that is added to the table headers when the column may be + * sorted descending by activing the column (click or return when focused). + * Note that the column header is prefixed to this string. + * @type string + * @default : activate to sort column ascending + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oAria": { + * "sSortDescending": " - click/return to sort descending" + * } + * } + * } ); + * } ); + */ + "sSortDescending": ": activate to sort column descending" + }, + + /** + * Pagination string used by DataTables for the two built-in pagination + * control types ("two_button" and "full_numbers") + * @namespace + */ + "oPaginate": { + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the first page. + * @type string + * @default First + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sFirst": "First page" + * } + * } + * } ); + * } ); + */ + "sFirst": "First", + + + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the last page. + * @type string + * @default Last + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sLast": "Last page" + * } + * } + * } ); + * } ); + */ + "sLast": "Last", + + + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the next page. + * @type string + * @default Next + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sNext": "Next page" + * } + * } + * } ); + * } ); + */ + "sNext": "Next", + + + /** + * Text to use when using the 'full_numbers' type of pagination for the + * button to take the user to the previous page. + * @type string + * @default Previous + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "oPaginate": { + * "sPrevious": "Previous page" + * } + * } + * } ); + * } ); + */ + "sPrevious": "Previous" + }, + + /** + * This string is shown in preference to sZeroRecords when the table is + * empty of data (regardless of filtering). Note that this is an optional + * parameter - if it is not given, the value of sZeroRecords will be used + * instead (either the default or given value). + * @type string + * @default No data available in table + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sEmptyTable": "No data available in table" + * } + * } ); + * } ); + */ + "sEmptyTable": "No data available in table", + + + /** + * This string gives information to the end user about the information that + * is current on display on the page. The _START_, _END_ and _TOTAL_ + * variables are all dynamically replaced as the table display updates, and + * can be freely moved or removed as the language requirements change. + * @type string + * @default Showing _START_ to _END_ of _TOTAL_ entries + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)" + * } + * } ); + * } ); + */ + "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", + + + /** + * Display information string for when the table is empty. Typically the + * format of this string should match sInfo. + * @type string + * @default Showing 0 to 0 of 0 entries + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoEmpty": "No entries to show" + * } + * } ); + * } ); + */ + "sInfoEmpty": "Showing 0 to 0 of 0 entries", + + + /** + * When a user filters the information in a table, this string is appended + * to the information (sInfo) to give an idea of how strong the filtering + * is. The variable _MAX_ is dynamically updated. + * @type string + * @default (filtered from _MAX_ total entries) + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoFiltered": " - filtering from _MAX_ records" + * } + * } ); + * } ); + */ + "sInfoFiltered": "(filtered from _MAX_ total entries)", + + + /** + * If can be useful to append extra information to the info string at times, + * and this variable does exactly that. This information will be appended to + * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are + * being used) at all times. + * @type string + * @default Empty string + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoPostFix": "All records shown are derived from real information." + * } + * } ); + * } ); + */ + "sInfoPostFix": "", + + + /** + * DataTables has a build in number formatter (fnFormatNumber) which is used + * to format large numbers that are used in the table information. By + * default a comma is used, but this can be trivially changed to any + * character you wish with this parameter. + * @type string + * @default , + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sInfoThousands": "'" + * } + * } ); + * } ); + */ + "sInfoThousands": ",", + + + /** + * Detail the action that will be taken when the drop down menu for the + * pagination length option is changed. The '_MENU_' variable is replaced + * with a default select list of 10, 25, 50 and 100, and can be replaced + * with a custom select box if required. + * @type string + * @default Show _MENU_ entries + * @dtopt Language + * + * @example + * // Language change only + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLengthMenu": "Display _MENU_ records" + * } + * } ); + * } ); + * + * @example + * // Language and options change + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLengthMenu": 'Display records' + * } + * } ); + * } ); + */ + "sLengthMenu": "Show _MENU_ entries", + + + /** + * When using Ajax sourced data and during the first draw when DataTables is + * gathering the data, this message is shown in an empty row in the table to + * indicate to the end user the the data is being loaded. Note that this + * parameter is not used when loading data by server-side processing, just + * Ajax sourced data with client-side processing. + * @type string + * @default Loading... + * @dtopt Language + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sLoadingRecords": "Please wait - loading..." + * } + * } ); + * } ); + */ + "sLoadingRecords": "Loading...", + + + /** + * Text which is displayed when the table is processing a user action + * (usually a sort command or similar). + * @type string + * @default Processing... + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sProcessing": "DataTables is currently busy" + * } + * } ); + * } ); + */ + "sProcessing": "Processing...", + + + /** + * Details the actions that will be taken when the user types into the + * filtering input text box. The variable "_INPUT_", if used in the string, + * is replaced with the HTML text box for the filtering input allowing + * control over where it appears in the string. If "_INPUT_" is not given + * then the input box is appended to the string automatically. + * @type string + * @default Search: + * @dtopt Language + * + * @example + * // Input text box will be appended at the end automatically + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sSearch": "Filter records:" + * } + * } ); + * } ); + * + * @example + * // Specify where the filter should appear + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sSearch": "Apply filter _INPUT_ to table" + * } + * } ); + * } ); + */ + "sSearch": "Search:", + + + /** + * All of the language information can be stored in a file on the + * server-side, which DataTables will look up if this parameter is passed. + * It must store the URL of the language file, which is in a JSON format, + * and the object has the same properties as the oLanguage object in the + * initialiser object (i.e. the above parameters). Please refer to one of + * the example language files to see how this works in action. + * @type string + * @default Empty string - i.e. disabled + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt" + * } + * } ); + * } ); + */ + "sUrl": "", + + + /** + * Text shown inside the table records when the is no information to be + * displayed after filtering. sEmptyTable is shown when there is simply no + * information in the table at all (regardless of filtering). + * @type string + * @default No matching records found + * @dtopt Language + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "oLanguage": { + * "sZeroRecords": "No records to display" + * } + * } ); + * } ); + */ + "sZeroRecords": "No matching records found" + }, + + + /** + * This parameter allows you to have define the global filtering state at + * initialisation time. As an object the "sSearch" parameter must be + * defined, but all other parameters are optional. When "bRegex" is true, + * the search string will be treated as a regular expression, when false + * (default) it will be treated as a straight string. When "bSmart" + * DataTables will use it's smart filtering methods (to word match at + * any point in the data), when false this will not be done. + * @namespace + * @extends DataTable.models.oSearch + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "oSearch": {"sSearch": "Initial search"} + * } ); + * } ) + */ + "oSearch": $.extend( {}, DataTable.models.oSearch ), + + + /** + * By default DataTables will look for the property 'aaData' when obtaining + * data from an Ajax source or for server-side processing - this parameter + * allows that property to be changed. You can use Javascript dotted object + * notation to get a data source for multiple levels of nesting. + * @type string + * @default aaData + * @dtopt Options + * @dtopt Server-side + * + * @example + * // Get data from { "data": [...] } + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/data.txt", + * "sAjaxDataProp": "data" + * } ); + * } ); + * + * @example + * // Get data from { "data": { "inner": [...] } } + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/data.txt", + * "sAjaxDataProp": "data.inner" + * } ); + * } ); + */ + "sAjaxDataProp": "aaData", + + + /** + * You can instruct DataTables to load data from an external source using this + * parameter (use aData if you want to pass data in you already have). Simply + * provide a url a JSON object can be obtained from. This object must include + * the parameter 'aaData' which is the data source for the table. + * @type string + * @default null + * @dtopt Options + * @dtopt Server-side + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php" + * } ); + * } ) + */ + "sAjaxSource": null, + + + /** + * This parameter can be used to override the default prefix that DataTables + * assigns to a cookie when state saving is enabled. + * @type string + * @default SpryMedia_DataTables_ + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sCookiePrefix": "my_datatable_", + * } ); + * } ); + */ + "sCookiePrefix": "SpryMedia_DataTables_", + + + /** + * This initialisation variable allows you to specify exactly where in the + * DOM you want DataTables to inject the various controls it adds to the page + * (for example you might want the pagination controls at the top of the + * table). DIV elements (with or without a custom class) can also be added to + * aid styling. The follow syntax is used: + *
      + *
    • 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 ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')
      • + *
      • 'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')
      • + *
      + *
    • + *
    • The following syntax is expected: + *
        + *
      • '<' and '>' - div elements
      • + *
      • '<"class" and '>' - div with a class
      • + *
      • '<"#id" and '>' - div with an ID
      • + *
      + *
    • + *
    • Examples: + *
        + *
      • '<"wrapper"flipt>'
      • + *
      • '<lf<t>ip>'
      • + *
      + *
    • + *
    + * @type string + * @default lfrtip (when bJQueryUI is false) or + * <"H"lfr>t<"F"ip> (when bJQueryUI is true) + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sDom": '<"top"i>rt<"bottom"flp><"clear"&lgt;' + * } ); + * } ); + */ + "sDom": "lfrtip", + + + /** + * DataTables features two different built-in pagination interaction methods + * ('two_button' or 'full_numbers') which present different page controls to + * the end user. Further methods can be added using the API (see below). + * @type string + * @default two_button + * @dtopt Options + * + * @example + * $(document).ready( function() { + * $('#example').dataTable( { + * "sPaginationType": "full_numbers" + * } ); + * } ) + */ + "sPaginationType": "two_button", + + + /** + * Enable horizontal scrolling. When a table is too wide to fit into a certain + * layout, or you have a large number of columns in the table, you can enable + * x-scrolling to show the table in a viewport, which can be scrolled. This + * property can be any CSS unit, or a number (in which case it will be treated + * as a pixel measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Features + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sScrollX": "100%", + * "bScrollCollapse": true + * } ); + * } ); + */ + "sScrollX": "", + + + /** + * This property can be used to force a DataTable to use more width than it + * might otherwise do when x-scrolling is enabled. For example if you have a + * table which requires to be well spaced, this parameter is useful for + * "over-sizing" the table, and thus forcing scrolling. This property can by + * any CSS unit, or a number (in which case it will be treated as a pixel + * measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Options + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sScrollX": "100%", + * "sScrollXInner": "110%" + * } ); + * } ); + */ + "sScrollXInner": "", + + + /** + * Enable vertical scrolling. Vertical scrolling will constrain the DataTable + * to the given height, and enable scrolling for any data which overflows the + * current viewport. This can be used as an alternative to paging to display + * a lot of data in a small area (although paging and scrolling can both be + * enabled at the same time). This property can be any CSS unit, or a number + * (in which case it will be treated as a pixel measurement). + * @type string + * @default blank string - i.e. disabled + * @dtopt Features + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "sScrollY": "200px", + * "bPaginate": false + * } ); + * } ); + */ + "sScrollY": "", + + + /** + * Set the HTTP method that is used to make the Ajax call for server-side + * processing or Ajax sourced data. + * @type string + * @default GET + * @dtopt Options + * @dtopt Server-side + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "bServerSide": true, + * "sAjaxSource": "scripts/post.php", + * "sServerMethod": "POST" + * } ); + * } ); + */ + "sServerMethod": "GET" + }; + + + + /** + * Column options that can be given to DataTables at initialisation time. + * @namespace + */ + DataTable.defaults.columns = { + /** + * Allows a column's sorting to take multiple columns into account when + * doing a sort. For example first name / last name columns make sense to + * do a multi-column sort over the two columns. + * @type array + * @default null Takes the value of the column index automatically + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] }, + * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] }, + * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "aDataSort": [ 0, 1 ] }, + * { "aDataSort": [ 1, 0 ] }, + * { "aDataSort": [ 2, 3, 4 ] }, + * null, + * null + * ] + * } ); + * } ); + */ + "aDataSort": null, + + + /** + * You can control the default sorting direction, and even alter the behaviour + * of the sort handler (i.e. only allow ascending sorting etc) using this + * parameter. + * @type array + * @default [ 'asc', 'desc' ] + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "asSorting": [ "asc" ], "aTargets": [ 1 ] }, + * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] }, + * { "asSorting": [ "desc" ], "aTargets": [ 3 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * { "asSorting": [ "asc" ] }, + * { "asSorting": [ "desc", "asc", "asc" ] }, + * { "asSorting": [ "desc" ] }, + * null + * ] + * } ); + * } ); + */ + "asSorting": [ 'asc', 'desc' ], + + + /** + * Enable or disable filtering on the data in this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bSearchable": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bSearchable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSearchable": true, + + + /** + * Enable or disable sorting on this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bSortable": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bSortable": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bSortable": true, + + + /** + * When using fnRender() for a column, you may wish to use the original data + * (before rendering) for sorting and filtering (the default is to used the + * rendered data that the user can see). This may be useful for dates etc. + * + * *NOTE* It is it is advisable now to use mDataProp as a function and make + * use of the 'type' that it gives, allowing (potentially) different data to + * be used for sorting, filtering, display and type detection. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "fnRender": function ( oObj ) { + * return oObj.aData[0] +' '+ oObj.aData[3]; + * }, + * "bUseRendered": false, + * "aTargets": [ 0 ] + * } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { + * "fnRender": function ( oObj ) { + * return oObj.aData[0] +' '+ oObj.aData[3]; + * }, + * "bUseRendered": false + * }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "bUseRendered": true, + + + /** + * Enable or disable the display of this column. + * @type boolean + * @default true + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "bVisible": false, "aTargets": [ 0 ] } + * ] } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "bVisible": false }, + * null, + * null, + * null, + * null + * ] } ); + * } ); + */ + "bVisible": true, + + + /** + * Developer definable function that is called whenever a cell is created (Ajax source, + * etc) or processed for input (DOM source). This can be used as a compliment to fnRender + * allowing you to modify the DOM element (add background colour for example) when the + * element is available (since it is not when fnRender is called). + * @type function + * @param {element} nTd The TD node that has been created + * @param {*} sData The Data for the cell + * @param {array|object} oData The data for the whole row + * @param {int} iRow The row index for the aoData data store + * @param {int} iCol The column index for aoColumns + * @dtopt Columns + * + * @example + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ { + * "aTargets": [3], + * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) { + * if ( sData == "1.7" ) { + * $(nTd).css('color', 'blue') + * } + * } + * } ] + * }); + * } ); + */ + "fnCreatedCell": null, + + + /** + * Custom display function that will be called for the display of each cell in + * this column. + * @type function + * @param {object} o Object with the following parameters: + * @param {int} o.iDataRow The row in aoData + * @param {int} o.iDataColumn The column in question + * @param {array} o.aData The data for the row in question + * @param {object} o.oSettings The settings object for this DataTables instance + * @param {object} o.mDataProp The data property used for this column + * @param {*} val The current cell value + * @returns {string} The string you which to use in the display + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "fnRender": function ( o, val ) { + * return o.aData[0] +' '+ o.aData[3]; + * }, + * "aTargets": [ 0 ] + * } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "fnRender": function ( o, val ) { + * return o.aData[0] +' '+ o.aData[3]; + * } }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "fnRender": null, + + + /** + * The column index (starting from 0!) that you wish a sort to be performed + * upon when this column is selected for sorting. This can be used for sorting + * on hidden columns for example. + * @type int + * @default -1 Use automatically calculated column index + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "iDataSort": 1, "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "iDataSort": 1 }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "iDataSort": -1, + + + /** + * This property can be used to read data from any JSON data source property, + * including deeply nested objects / properties. mDataProp can be given in a + * number of different ways which effect its behaviour: + *
      + *
    • integer - treated as an array index for the data source. This is the + * default that DataTables uses (incrementally increased for each column).
    • + *
    • string - read an object property from the data source. Note that you can + * use Javascript dotted notation to read deep properties/arrays from the + * data source.
    • + *
    • null - the sDefaultContent option will be used for the cell (null + * by default, so you will need to specify the default content you want - + * typically an empty string). This can be useful on generated columns such + * as edit / delete action columns.
    • + *
    • function - the function given will be executed whenever DataTables + * needs to set or get the data for a cell in the column. The function + * takes three parameters: + *
        + *
      • {array|object} The data source for the row
      • + *
      • {string} The type call data requested - this will be 'set' when + * setting data or 'filter', 'display', 'type', 'sort' or undefined when + * gathering data. Note that when undefined is given for the type + * DataTables expects to get the raw data for the object back
      • + *
      • {*} Data to set when the second parameter is 'set'.
      • + *
      + * The return value from the function is not required when 'set' is the type + * of call, but otherwise the return is what will be used for the data + * requested.
    • + *
    + * @type string|int|function|null + * @default null Use automatically calculated column index + * @dtopt Columns + * + * @example + * // Read table data from objects + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "sAjaxSource": "sources/deep.txt", + * "aoColumns": [ + * { "mDataProp": "engine" }, + * { "mDataProp": "browser" }, + * { "mDataProp": "platform.inner" }, + * { "mDataProp": "platform.details.0" }, + * { "mDataProp": "platform.details.1" } + * ] + * } ); + * } ); + * + * @example + * // Using mDataProp as a function to provide different information for + * // sorting, filtering and display. In this case, currency (price) + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "aTargets": [ 0 ], + * "mDataProp": function ( source, type, val ) { + * if (type === 'set') { + * source.price = val; + * // Store the computed dislay and filter values for efficiency + * source.price_display = val=="" ? "" : "$"+numberFormat(val); + * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; + * return; + * } + * else if (type === 'display') { + * return source.price_display; + * } + * else if (type === 'filter') { + * return source.price_filter; + * } + * // 'sort', 'type' and undefined all just use the integer + * return source.price; + * } + * ] + * } ); + * } ); + */ + "mDataProp": null, + + + /** + * Change the cell type created for the column - either TD cells or TH cells. This + * can be useful as TH cells have semantic meaning in the table body, allowing them + * to act as a header for a row (you may wish to add scope='row' to the TH elements). + * @type string + * @default td + * @dtopt Columns + * + * @example + * // Make the first column use TH cells + * $(document).ready(function() { + * var oTable = $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "aTargets": [ 0 ], + * "sCellType": "th" + * ] + * } ); + * } ); + */ + "sCellType": "td", + + + /** + * Class to give to each cell in this column. + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sClass": "my_class", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sClass": "my_class" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sClass": "", + + /** + * When DataTables calculates the column widths to assign to each column, + * it finds the longest string in each column and then constructs a + * temporary table and reads the widths from that. The problem with this + * is that "mmm" is much wider then "iiii", but the latter is a longer + * string - thus the calculation can go wrong (doing it properly and putting + * it into an DOM object and measuring that is horribly(!) slow). Thus as + * a "work around" we provide this option. It will append its value to the + * text that is found to be the longest string for the column - i.e. padding. + * Generally you shouldn't need this, and it is not documented on the + * general DataTables.net documentation + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * null, + * { + * "sContentPadding": "mmm" + * } + * ] + * } ); + * } ); + */ + "sContentPadding": "", + + + /** + * Allows a default value to be given for a column's data, and will be used + * whenever a null data source is encountered (this can be because mDataProp + * is set to null, or because the data source itself is null). + * @type string + * @default null + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { + * "mDataProp": null, + * "sDefaultContent": "Edit", + * "aTargets": [ -1 ] + * } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * null, + * { + * "mDataProp": null, + * "sDefaultContent": "Edit" + * } + * ] + * } ); + * } ); + */ + "sDefaultContent": null, + + + /** + * This parameter is only used in DataTables' server-side processing. It can + * be exceptionally useful to know what columns are being displayed on the + * client side, and to map these to database fields. When defined, the names + * also allow DataTables to reorder information from the server if it comes + * back in an unexpected order (i.e. if you switch your columns around on the + * client-side, your server-side code does not also need updating). + * @type string + * @default Empty string + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sName": "engine", "aTargets": [ 0 ] }, + * { "sName": "browser", "aTargets": [ 1 ] }, + * { "sName": "platform", "aTargets": [ 2 ] }, + * { "sName": "version", "aTargets": [ 3 ] }, + * { "sName": "grade", "aTargets": [ 4 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sName": "engine" }, + * { "sName": "browser" }, + * { "sName": "platform" }, + * { "sName": "version" }, + * { "sName": "grade" } + * ] + * } ); + * } ); + */ + "sName": "", + + + /** + * Defines a data source type for the sorting which can be used to read + * realtime information from the table (updating the internally cached + * version) prior to sorting. This allows sorting to occur on user editable + * elements such as form inputs. + * @type string + * @default std + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] }, + * { "sType": "numeric", "aTargets": [ 3 ] }, + * { "sSortDataType": "dom-select", "aTargets": [ 4 ] }, + * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * null, + * null, + * { "sSortDataType": "dom-text" }, + * { "sSortDataType": "dom-text", "sType": "numeric" }, + * { "sSortDataType": "dom-select" }, + * { "sSortDataType": "dom-checkbox" } + * ] + * } ); + * } ); + */ + "sSortDataType": "std", + + + /** + * The title of this column. + * @type string + * @default null Derived from the 'TH' value for this column in the + * original HTML table. + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sTitle": "My column title", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sTitle": "My column title" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sTitle": null, + + + /** + * The type allows you to specify how the data for this column will be sorted. + * Four types (string, numeric, date and html (which will strip HTML tags + * before sorting)) are currently available. Note that only date formats + * understood by Javascript's Date() object will be accepted as type date. For + * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric', + * 'date' or 'html' (by default). Further types can be adding through + * plug-ins. + * @type string + * @default null Auto-detected from raw data + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sType": "html", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sType": "html" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sType": null, + + + /** + * Defining the width of the column, this parameter may take any CSS value + * (3em, 20px etc). DataTables applys 'smart' widths to columns which have not + * been given a specific width through this interface ensuring that the table + * remains readable. + * @type string + * @default null Automatic + * @dtopt Columns + * + * @example + * // Using aoColumnDefs + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumnDefs": [ + * { "sWidth": "20%", "aTargets": [ 0 ] } + * ] + * } ); + * } ); + * + * @example + * // Using aoColumns + * $(document).ready(function() { + * $('#example').dataTable( { + * "aoColumns": [ + * { "sWidth": "20%" }, + * null, + * null, + * null, + * null + * ] + * } ); + * } ); + */ + "sWidth": null + }; + + + + /** + * DataTables settings object - this holds all the information needed for a + * given table, including configuration, data and current application of the + * table options. DataTables does not have a single instance for each DataTable + * with the settings attached to that instance, but rather instances of the + * DataTable "class" are created on-the-fly as needed (typically by a + * $().dataTable() call) and the settings object is then applied to that + * instance. + * + * Note that this object is related to {@link DataTable.defaults} but this + * one is the internal data store for DataTables's cache of columns. It should + * NOT be manipulated outside of DataTables. Any configuration should be done + * through the initialisation options. + * @namespace + * @todo Really should attach the settings object to individual instances so we + * don't need to create new instances on each $().dataTable() call (if the + * table already exists). It would also save passing oSettings around and + * into every single function. However, this is a very significant + * architecture change for DataTables and will almost certainly break + * backwards compatibility with older installations. This is something that + * will be done in 2.0. + */ + DataTable.models.oSettings = { + /** + * Primary features of DataTables and their enablement state. + * @namespace + */ + "oFeatures": { + + /** + * Flag to say if DataTables should automatically try to calculate the + * optimum table and columns widths (true) or not (false). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bAutoWidth": null, + + /** + * Delay the creation of TR and TD elements until they are actually + * needed by a driven page draw. This can give a significant speed + * increase for Ajax source and Javascript source data, but makes no + * difference at all fro DOM and server-side processing tables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bDeferRender": null, + + /** + * Enable filtering on the table or not. Note that if this is disabled + * then there is no filtering at all on the table, including fnFilter. + * To just remove the filtering input use sDom and remove the 'f' option. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bFilter": null, + + /** + * Table information element (the 'Showing x of y records' div) enable + * flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bInfo": null, + + /** + * Present a user control allowing the end user to change the page size + * when pagination is enabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bLengthChange": null, + + /** + * Pagination enabled or not. Note that if this is disabled then length + * changing must also be disabled. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bPaginate": null, + + /** + * Processing indicator enable flag whenever DataTables is enacting a + * user request - typically an Ajax request for server-side processing. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bProcessing": null, + + /** + * Server-side processing enabled flag - when enabled DataTables will + * get all data from the server for every draw - there is no filtering, + * sorting or paging done on the client-side. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bServerSide": null, + + /** + * Sorting enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSort": null, + + /** + * Apply a class to the columns which are being sorted to provide a + * visual highlight or not. This can slow things down when enabled since + * there is a lot of DOM interaction. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortClasses": null, + + /** + * State saving enablement flag. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bStateSave": null + }, + + + /** + * Scrolling settings for a table. + * @namespace + */ + "oScroll": { + /** + * Indicate if DataTables should be allowed to set the padding / margin + * etc for the scrolling header elements or not. Typically you will want + * this. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bAutoCss": null, + + /** + * When the table is shorter in height than sScrollY, collapse the + * table container down to the height of the table (when true). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bCollapse": null, + + /** + * Infinite scrolling enablement flag. Now deprecated in favour of + * using the Scroller plug-in. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bInfinite": null, + + /** + * Width of the scrollbar for the web-browser's platform. Calculated + * during table initialisation. + * @type int + * @default 0 + */ + "iBarWidth": 0, + + /** + * Space (in pixels) between the bottom of the scrolling container and + * the bottom of the scrolling viewport before the next page is loaded + * when using infinite scrolling. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type int + */ + "iLoadGap": null, + + /** + * Viewport width for horizontal scrolling. Horizontal scrolling is + * disabled if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sX": null, + + /** + * Width to expand the table to when using x-scrolling. Typically you + * should not need to use this. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @deprecated + */ + "sXInner": null, + + /** + * Viewport height for vertical scrolling. Vertical scrolling is disabled + * if an empty string. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sY": null + }, + + /** + * Language information for the table. + * @namespace + * @extends DataTable.defaults.oLanguage + */ + "oLanguage": { + /** + * Information callback function. See + * {@link DataTable.defaults.fnInfoCallback} + * @type function + * @default + */ + "fnInfoCallback": null + }, + + /** + * Array referencing the nodes which are used for the features. 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
    • + *
    + * @type array + * @default [] + */ + "aanFeatures": [], + + /** + * Store data information - see {@link DataTable.models.oRow} for detailed + * information. + * @type array + * @default [] + */ + "aoData": [], + + /** + * Array of indexes which are in the current display (after filtering etc) + * @type array + * @default [] + */ + "aiDisplay": [], + + /** + * Array of indexes for display - no filtering + * @type array + * @default [] + */ + "aiDisplayMaster": [], + + /** + * Store information about each column that is in use + * @type array + * @default [] + */ + "aoColumns": [], + + /** + * Store information about the table's header + * @type array + * @default [] + */ + "aoHeader": [], + + /** + * Store information about the table's footer + * @type array + * @default [] + */ + "aoFooter": [], + + /** + * Search data array for regular expression searching + * @type array + * @default [] + */ + "asDataSearch": [], + + /** + * Store the applied global search information in case we want to force a + * research or compare the old search to a new one. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @namespace + * @extends DataTable.models.oSearch + */ + "oPreviousSearch": {}, + + /** + * Store the applied search for each column - see + * {@link DataTable.models.oSearch} for the format that is used for the + * filtering information for each column. + * @type array + * @default [] + */ + "aoPreSearchCols": [], + + /** + * Sorting that is applied to the table. Note that the inner arrays are + * used in the following manner: + *
      + *
    • Index 0 - column number
    • + *
    • Index 1 - current sorting direction
    • + *
    • Index 2 - index of asSorting for this column
    • + *
    + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @todo These inner arrays should really be objects + */ + "aaSorting": null, + + /** + * Sorting that is always applied to the table (i.e. prefixed in front of + * aaSorting). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array|null + * @default null + */ + "aaSortingFixed": null, + + /** + * Classes to use for the striping of a table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "asStripeClasses": null, + + /** + * If restoring a table - we should restore its striping classes as well + * @type array + * @default [] + */ + "asDestroyStripes": [], + + /** + * If restoring a table - we should restore its width + * @type int + * @default 0 + */ + "sDestroyWidth": 0, + + /** + * Callback functions array for every time a row is inserted (i.e. on a draw). + * @type array + * @default [] + */ + "aoRowCallback": [], + + /** + * Callback functions for the header on each draw. + * @type array + * @default [] + */ + "aoHeaderCallback": [], + + /** + * Callback function for the footer on each draw. + * @type array + * @default [] + */ + "aoFooterCallback": [], + + /** + * Array of callback functions for draw callback functions + * @type array + * @default [] + */ + "aoDrawCallback": [], + + /** + * Array of callback functions for row created function + * @type array + * @default [] + */ + "aoRowCreatedCallback": [], + + /** + * Callback functions for just before the table is redrawn. A return of + * false will be used to cancel the draw. + * @type array + * @default [] + */ + "aoPreDrawCallback": [], + + /** + * Callback functions for when the table has been initialised. + * @type array + * @default [] + */ + "aoInitComplete": [], + + + /** + * Callbacks for modifying the settings to be stored for state saving, prior to + * saving state. + * @type array + * @default [] + */ + "aoStateSaveParams": [], + + /** + * Callbacks for modifying the settings that have been stored for state saving + * prior to using the stored values to restore the state. + * @type array + * @default [] + */ + "aoStateLoadParams": [], + + /** + * Callbacks for operating on the settings object once the saved state has been + * loaded + * @type array + * @default [] + */ + "aoStateLoaded": [], + + /** + * Cache the table ID for quick access + * @type string + * @default Empty string + */ + "sTableId": "", + + /** + * The TABLE node for the main table + * @type node + * @default null + */ + "nTable": null, + + /** + * Permanent ref to the thead element + * @type node + * @default null + */ + "nTHead": null, + + /** + * Permanent ref to the tfoot element - if it exists + * @type node + * @default null + */ + "nTFoot": null, + + /** + * Permanent ref to the tbody element + * @type node + * @default null + */ + "nTBody": null, + + /** + * Cache the wrapper node (contains all DataTables controlled elements) + * @type node + * @default null + */ + "nTableWrapper": null, + + /** + * Indicate if when using server-side processing the loading of data + * should be deferred until the second draw. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + * @default false + */ + "bDeferLoading": false, + + /** + * Indicate if all required information has been read in + * @type boolean + * @default false + */ + "bInitialised": false, + + /** + * Information about open rows. Each object in the array has the parameters + * 'nTr' and 'nParent' + * @type array + * @default [] + */ + "aoOpenRows": [], + + /** + * Dictate the positioning of DataTables' control elements - see + * {@link DataTable.model.oInit.sDom}. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sDom": null, + + /** + * Which type of pagination should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default two_button + */ + "sPaginationType": "two_button", + + /** + * The cookie duration (for bStateSave) in seconds. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type int + * @default 0 + */ + "iCookieDuration": 0, + + /** + * The cookie name prefix. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default Empty string + */ + "sCookiePrefix": "", + + /** + * Callback function for cookie creation. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + * @default null + */ + "fnCookieCallback": null, + + /** + * Array of callback functions for state saving. 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
    • + *
    + * @type array + * @default [] + */ + "aoStateSave": [], + + /** + * Array of callback functions for state loading. 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
    • + *
    + * @type array + * @default [] + */ + "aoStateLoad": [], + + /** + * State that was loaded from the cookie. Useful for back reference + * @type object + * @default null + */ + "oLoadedState": null, + + /** + * Source url for AJAX data for the table. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + * @default null + */ + "sAjaxSource": null, + + /** + * Property from a given object from which to read the table data from. This + * can be an empty string (when not server-side processing), in which case + * it is assumed an an array is given directly. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sAjaxDataProp": null, + + /** + * Note if draw should be blocked while getting data + * @type boolean + * @default true + */ + "bAjaxDataGet": true, + + /** + * The last jQuery XHR object that was used for server-side data gathering. + * This can be used for working with the XHR information in one of the + * callbacks + * @type object + * @default null + */ + "jqXHR": null, + + /** + * Function to get the server-side data. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnServerData": null, + + /** + * Functions which are called prior to sending an Ajax request so extra + * parameters can easily be sent to the server + * @type array + * @default [] + */ + "aoServerParams": [], + + /** + * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if + * required). + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type string + */ + "sServerMethod": null, + + /** + * Format numbers for display. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type function + */ + "fnFormatNumber": null, + + /** + * List of options that can be used for the user selectable length menu. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type array + * @default [] + */ + "aLengthMenu": null, + + /** + * Counter for the draws that the table does. Also used as a tracker for + * server-side processing + * @type int + * @default 0 + */ + "iDraw": 0, + + /** + * Indicate if a redraw is being done - useful for Ajax + * @type boolean + * @default false + */ + "bDrawing": false, + + /** + * Draw index (iDraw) of the last error when parsing the returned data + * @type int + * @default -1 + */ + "iDrawError": -1, + + /** + * Paging display length + * @type int + * @default 10 + */ + "_iDisplayLength": 10, + + /** + * Paging start point - aiDisplay index + * @type int + * @default 0 + */ + "_iDisplayStart": 0, + + /** + * Paging end point - aiDisplay index. Use fnDisplayEnd rather than + * this property to get the end point + * @type int + * @default 10 + * @private + */ + "_iDisplayEnd": 10, + + /** + * Server-side processing - number of records in the result set + * (i.e. before filtering), Use fnRecordsTotal rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type int + * @default 0 + * @private + */ + "_iRecordsTotal": 0, + + /** + * Server-side processing - number of records in the current display set + * (i.e. after filtering). Use fnRecordsDisplay rather than + * this property to get the value of the number of records, regardless of + * the server-side processing setting. + * @type boolean + * @default 0 + * @private + */ + "_iRecordsDisplay": 0, + + /** + * Flag to indicate if jQuery UI marking and classes should be used. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bJUI": null, + + /** + * The classes to use for the table + * @type object + * @default {} + */ + "oClasses": {}, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if filtering has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bFiltered": false, + + /** + * Flag attached to the settings object so you can check in the draw + * callback if sorting has been done in the draw. Deprecated in favour of + * events. + * @type boolean + * @default false + * @deprecated + */ + "bSorted": false, + + /** + * Indicate that if multiple rows are in the header and there is more than + * one unique cell per column, if the top one (true) or bottom one (false) + * should be used for sorting / title by DataTables. + * Note that this parameter will be set by the initialisation routine. To + * set a default use {@link DataTable.defaults}. + * @type boolean + */ + "bSortCellsTop": null, + + /** + * Initialisation object that is used for the table + * @type object + * @default null + */ + "oInit": null, + + /** + * Destroy callback functions - for plug-ins to attach themselves to the + * destroy so they can clean up markup and events. + * @type array + * @default [] + */ + "aoDestroyCallback": [], + + + /** + * Get the number of records in the current record set, before filtering + * @type function + */ + "fnRecordsTotal": function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsTotal, 10); + } else { + return this.aiDisplayMaster.length; + } + }, + + /** + * Get the number of records in the current record set, after filtering + * @type function + */ + "fnRecordsDisplay": function () + { + if ( this.oFeatures.bServerSide ) { + return parseInt(this._iRecordsDisplay, 10); + } else { + return this.aiDisplay.length; + } + }, + + /** + * Set the display end point - aiDisplay index + * @type function + * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here + */ + "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; + } + }, + + /** + * The DataTables object for this table + * @type object + * @default null + */ + "oInstance": null, + + /** + * Unique identifier for each instance of the DataTables object. If there + * is an ID on the table node, then it takes that value, otherwise an + * incrementing internal counter is used. + * @type string + * @default null + */ + "sInstance": null, + + /** + * tabindex attribute value that is added to DataTables control elements, allowing + * keyboard navigation of the table and its controls. + */ + "iTabIndex": 0, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollHead": null, + + /** + * DIV container for the footer scrolling table if scrolling + */ + "nScrollFoot": null + }; + + /** + * Extension object for DataTables that is used to provide all extension options. + * + * Note that the DataTable.ext object is available through + * jQuery.fn.dataTable.ext where it may be accessed and manipulated. It is + * also aliased to jQuery.fn.dataTableExt for historic reasons. + * @namespace + * @extends DataTable.models.ext + */ + DataTable.ext = $.extend( true, {}, DataTable.models.ext ); + + $.extend( DataTable.ext.oStdClasses, { + "sTable": "dataTable", + + /* 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 paginate_button_disabled", + "sPageFirst": "first", + "sPagePrevious": "previous", + "sPageNext": "next", + "sPageLast": "last", + + /* Striping classes */ + "sStripeOdd": "odd", + "sStripeEven": "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": "", + "sSortIcon": "", + + /* Scrolling */ + "sScrollWrapper": "dataTables_scroll", + "sScrollHead": "dataTables_scrollHead", + "sScrollHeadInner": "dataTables_scrollHeadInner", + "sScrollBody": "dataTables_scrollBody", + "sScrollFoot": "dataTables_scrollFoot", + "sScrollFootInner": "dataTables_scrollFootInner", + + /* Misc */ + "sFooterTH": "" + } ); + + + $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, { + /* 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", + "sPageLast": "last ui-corner-tr ui-corner-br", + + /* Features */ + "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ + "ui-buttonset-multi paging_", /* Note that the type is postfixed */ + + /* 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", + "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", + "sSortIcon": "DataTables_sort_icon", + + /* Scrolling */ + "sScrollHead": "dataTables_scrollHead ui-state-default", + "sScrollFoot": "dataTables_scrollFoot ui-state-default", + + /* Misc */ + "sFooterTH": "ui-state-default" + } ); + + + /* + * Variable: oPagination + * Purpose: + * Scope: jQuery.fn.dataTableExt + */ + $.extend( DataTable.ext.oPagination, { + /* + * Variable: two_button + * Purpose: Standard two button (forward/back) pagination + * Scope: jQuery.fn.dataTableExt.oPagination + */ + "two_button": { + /* + * Function: oPagination.two_button.fnInit + * Purpose: Initialise 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 oLang = oSettings.oLanguage.oPaginate; + var oClasses = oSettings.oClasses; + var fnClickHandler = function ( e ) { + if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) ) + { + fnCallbackDraw( oSettings ); + } + }; + + var sAppend = (!oSettings.bJUI) ? + ''+oLang.sPrevious+''+ + ''+oLang.sNext+'' + : + ''+ + ''; + $(nPaging).append( sAppend ); + + var els = $('a', nPaging); + var nPrevious = els[0], + nNext = els[1]; + + oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); + + /* ID the first elements only */ + if ( !oSettings.aanFeatures.p ) + { + nPaging.id = oSettings.sTableId+'_paginate'; + nPrevious.id = oSettings.sTableId+'_previous'; + nNext.id = oSettings.sTableId+'_next'; + + nPrevious.setAttribute('aria-controls', oSettings.sTableId); + nNext.setAttribute('aria-controls', oSettings.sTableId); + } + }, + + /* + * 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; + } + + var oClasses = oSettings.oClasses; + var an = oSettings.aanFeatures.p; + + /* Loop over each instance of the pager */ + for ( var i=0, iLen=an.length ; i'+oLang.sFirst+''+ + ''+oLang.sPrevious+''+ + ''+ + ''+oLang.sNext+''+ + ''+oLang.sLast+'' + ); + var els = $('a', nPaging); + var nFirst = els[0], + nPrev = els[1], + nNext = els[2], + nLast = els[3]; + + oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); + oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler ); + + /* ID the first elements only */ + if ( !oSettings.aanFeatures.p ) + { + nPaging.id = oSettings.sTableId+'_paginate'; + nFirst.id =oSettings.sTableId+'_first'; + nPrev.id =oSettings.sTableId+'_previous'; + nNext.id =oSettings.sTableId+'_next'; + nLast.id =oSettings.sTableId+'_last'; + } + }, + + /* + * Function: oPagination.full_numbers.fnUpdate + * Purpose: Update the list of page buttons shows + * 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; + } + + var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages; + var iPageCountHalf = Math.floor(iPageCount / 2); + var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength); + var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1; + var sList = ""; + var iStartButton, iEndButton, i, iLen; + var oClasses = oSettings.oClasses; + var anButtons, anStatic, nPaginateList; + var an = oSettings.aanFeatures.p; + var fnBind = function (j) { + oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) { + /* Use the information in the element to jump to the required page */ + oSettings.oApi._fnPageChange( oSettings, e.data.page ); + fnCallbackDraw( oSettings ); + e.preventDefault(); + } ); + }; + + /* Pages calculation */ + if ( oSettings._iDisplayLength === -1 ) + { + iStartButton = 1; + iEndButton = 1; + iCurrentPage = 1; + } + else if (iPages < iPageCount) + { + iStartButton = 1; + iEndButton = iPages; + } + else if (iCurrentPage <= iPageCountHalf) + { + iStartButton = 1; + iEndButton = iPageCount; + } + else if (iCurrentPage >= (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++ ) + { + sList += (iCurrentPage !== i) ? + ''+oSettings.fnFormatNumber(i)+'' : + ''+oSettings.fnFormatNumber(i)+''; + } + + /* Loop over each instance of the pager */ + for ( i=0, iLen=an.length ; i y) ? 1 : 0)); + }, + + "string-desc": function ( x, y ) + { + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * html sorting (ignore html tags) + */ + "html-pre": function ( a ) + { + return a.replace( /<.*?>/g, "" ).toLowerCase(); + }, + + "html-asc": function ( x, y ) + { + return ((x < y) ? -1 : ((x > y) ? 1 : 0)); + }, + + "html-desc": function ( x, y ) + { + return ((x < y) ? 1 : ((x > y) ? -1 : 0)); + }, + + + /* + * date sorting + */ + "date-pre": function ( a ) + { + var x = Date.parse( a ); + + if ( isNaN(x) || x==="" ) + { + x = Date.parse( "01/01/1970 00:00:00" ); + } + return x; + }, + + "date-asc": function ( x, y ) + { + return x - y; + }, + + "date-desc": function ( x, y ) + { + return y - x; + }, + + + /* + * numerical sorting + */ + "numeric-pre": function ( a ) + { + return (a=="-" || a==="") ? 0 : a*1; + }, + + "numeric-asc": function ( x, y ) + { + return x - y; + }, + + "numeric-desc": function ( x, y ) + { + return y - x; + } + } ); + + + $.extend( DataTable.ext.aTypes, [ + /* + * Function: - + * Purpose: Check to see if a string is numeric + * Returns: string:'numeric' or null + * Inputs: mixed:sText - string to check + */ + function ( sData ) + { + /* Allow zero length strings as a number */ + if ( typeof sData === 'number' ) + { + return 'numeric'; + } + else if ( typeof sData !== 'string' ) + { + return null; + } + + 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; + } + ] ); + + + // jQuery aliases + $.fn.DataTable = DataTable; + $.fn.dataTable = DataTable; + $.fn.dataTableSettings = DataTable.settings; + $.fn.dataTableExt = DataTable.ext; + + + // Information about events fired by DataTables - for documentation. + /** + * Draw event, fired whenever the table is redrawn on the page, at the same point as + * fnDrawCallback. This may be useful for binding events or performing calculations when + * the table is altered at all. + * @name DataTable#draw + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Filter event, fired when the filtering applied to the table (using the build in global + * global filter, or column filters) is altered. + * @name DataTable#filter + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Page change event, fired when the paging of the table is altered. + * @name DataTable#page + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Sort event, fired when the sorting applied to the table is altered. + * @name DataTable#sort + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * DataTables initialisation complete event, fired when the table is fully drawn, + * including Ajax data loaded, if Ajax data is required. + * @name DataTable#init + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The JSON object request from the server - only + * present if client-side Ajax sourced data is used
  • + */ + + /** + * State save event, fired when the table has changed state a new state save is required. + * This method allows modification of the state saving object prior to actually doing the + * save, including addition or other state properties (for plug-ins) or modification + * of a DataTables core property. + * @name DataTable#stateSaveParams + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The state information to be saved + */ + + /** + * State load event, fired when the table is loading state from the stored data, but + * prior to the settings object being modified by the saved state - allowing modification + * of the saved state is required or loading of state for a plug-in. + * @name DataTable#stateLoadParams + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * State loaded event, fired when state has been loaded from stored data and the settings + * object has been modified by the loaded data. + * @name DataTable#stateLoaded + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {object} json The saved state information + */ + + /** + * Processing event, fired when DataTables is doing some kind of processing (be it, + * sort, filter or anything else). Can be used to indicate to the end user that + * there is something happening, or that something has finished. + * @name DataTable#processing + * @event + * @param {event} e jQuery event object + * @param {object} oSettings DataTables settings object + * @param {boolean} bShow Flag for if DataTables is doing processing or not + */ + + /** + * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to + * made to the server for new data (note that this trigger is called in fnServerData, + * if you override fnServerData and which to use this event, you need to trigger it in + * you success function). + * @name DataTable#xhr + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ + + /** + * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing + * the bDestroy:true parameter in the initialisation object. This can be used to remove + * bound events, added DOM nodes, etc. + * @name DataTable#destroy + * @event + * @param {event} e jQuery event object + * @param {object} o DataTables settings object {@link DataTable.models.oSettings} + */ +}(jQuery, window, document, undefined)); diff --git a/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.jgz b/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.jgz index 54687947c21bc42e5ad7537436c5bfe21c3c12cd..e7a91f87f757fb21c99dfd9591a0719b67c11b2d 100644 GIT binary patch literal 20946 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 v#nYlOJZ)AizI)88XllTZzjyO6Rj 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 BsZjs` diff --git a/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.js b/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.js index 1adfaf565fe..259fe2608cb 100644 --- a/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.js +++ b/htdocs/includes/jquery/plugins/datatables/js/jquery.dataTables.min.js @@ -1,151 +1,154 @@ /* * File: jquery.dataTables.min.js - * Version: 1.8.1 + * Version: 1.9.1 * Author: Allan Jardine (www.sprymedia.co.uk) * Info: www.datatables.net * - * Copyright 2008-2011 Allan Jardine, all rights reserved. + * Copyright 2008-2012 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. + * BSD style license, available at: + * http://datatables.net/license_gpl2 + * http://datatables.net/license_bsd * * 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. */ -(function(i,wa,p){i.fn.dataTableSettings=[];var D=i.fn.dataTableSettings;i.fn.dataTableExt={};var o=i.fn.dataTableExt;o.sVersion="1.8.1";o.sErrMode="alert";o.iApiIndex=0;o.oApi={};o.afnFiltering=[];o.aoFeatures=[];o.ofnSearch={};o.afnSortData=[];o.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active", -sPageButtonStaticDisabled:"paginate_button paginate_button_disabled",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled", -sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:""};o.oJUIClasses={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",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",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",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_",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",sSortIcon:"DataTables_sort_icon",sScrollWrapper:"dataTables_scroll", -sScrollHead:"dataTables_scrollHead ui-state-default",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot ui-state-default",sScrollFootInner:"dataTables_scrollFootInner",sFooterTH:"ui-state-default"};o.oPagination={two_button:{fnInit:function(g,l,r){var s,w,y;if(g.bJUI){s=p.createElement("a");w=p.createElement("a");y=p.createElement("span");y.className=g.oClasses.sPageJUINext;w.appendChild(y);y=p.createElement("span");y.className=g.oClasses.sPageJUIPrev; -s.appendChild(y)}else{s=p.createElement("div");w=p.createElement("div")}s.className=g.oClasses.sPagePrevDisabled;w.className=g.oClasses.sPageNextDisabled;s.title=g.oLanguage.oPaginate.sPrevious;w.title=g.oLanguage.oPaginate.sNext;l.appendChild(s);l.appendChild(w);i(s).bind("click.DT",function(){g.oApi._fnPageChange(g,"previous")&&r(g)});i(w).bind("click.DT",function(){g.oApi._fnPageChange(g,"next")&&r(g)});i(s).bind("selectstart.DT",function(){return false});i(w).bind("selectstart.DT",function(){return false}); -if(g.sTableId!==""&&typeof g.aanFeatures.p=="undefined"){l.setAttribute("id",g.sTableId+"_paginate");s.setAttribute("id",g.sTableId+"_previous");w.setAttribute("id",g.sTableId+"_next")}},fnUpdate:function(g){if(g.aanFeatures.p)for(var l=g.aanFeatures.p,r=0,s=l.length;r=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++)G+=y!=r?''+r+"":''+r+"";x=g.aanFeatures.p;var z,Y=function(L){g._iDisplayStart=(this.innerHTML*1-1)*g._iDisplayLength;l(g);L.preventDefault()},V=function(){return false};r=0;for(s=x.length;rl?1:0},"string-desc":function(g,l){if(typeof g!="string")g="";if(typeof l!="string")l="";g=g.toLowerCase();l=l.toLowerCase();return gl?-1:0},"html-asc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return g< -l?-1:g>l?1:0},"html-desc":function(g,l){g=g.replace(/<.*?>/g,"").toLowerCase();l=l.replace(/<.*?>/g,"").toLowerCase();return gl?-1:0},"date-asc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||l==="")l=Date.parse("01/01/1970 00:00:00");return g-l},"date-desc":function(g,l){g=Date.parse(g);l=Date.parse(l);if(isNaN(g)||g==="")g=Date.parse("01/01/1970 00:00:00");if(isNaN(l)||l==="")l=Date.parse("01/01/1970 00:00:00");return l- -g},"numeric-asc":function(g,l){return(g=="-"||g===""?0:g*1)-(l=="-"||l===""?0:l*1)},"numeric-desc":function(g,l){return(l=="-"||l===""?0:l*1)-(g=="-"||g===""?0:g*1)}};o.aTypes=[function(g){if(typeof g=="number")return"numeric";else if(typeof g!="string")return null;var l,r=false;l=g.charAt(0);if("0123456789-".indexOf(l)==-1)return null;for(var s=1;s")!=-1)return"html";return null}];o.fnVersionCheck=function(g){var l=function(x,v){for(;x.length=parseInt(w,10)};o._oExternConfig={iNextUnique:0};i.fn.dataTable=function(g){function l(){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,bDeferRender: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", -sLoadingRecords:"Loading...",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.aoHeader=[];this.aoFooter=[];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=this.fnPreDrawCallback=null;this.sTableId="";this.nTableWrapper=this.nTBody=this.nTFoot=this.nTHead=this.nTable=null;this.bInitialised=this.bDeferLoading=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.sAjaxDataProp="aaData";this.bAjaxDataGet=true;this.jqXHR=null;this.fnServerData=function(a,b,c,d){d.jqXHR=i.ajax({url:a,data:b,success:c,dataType:"json",cache:false,error:function(f,e){e=="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;dtr>th",a.nTFoot).addClass(a.oClasses.sFooterTH);if(a.nTFoot!==null){c=S(a,null,a.aoFooter);b=0;for(d=a.aoColumns.length;b=0;e--)!a.aoColumns[e].bVisible&&!c&&h[d].splice(e,1);j.push([])}d=0;for(f=h.length;d=a.fnRecordsDisplay()?0:a.iInitDisplayStart;a.iInitDisplayStart=-1;E(a)}if(a.bDeferLoading){a.bDeferLoading=false;a.iDraw++}else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!za(a))return}else a.iDraw++;if(a.aiDisplay.length!==0){var h=a._iDisplayStart,j=a._iDisplayEnd;if(a.oFeatures.bServerSide){h=0;j=a.aoData.length}for(h=h;htr",a.nTHead)[0],aa(a),a._iDisplayStart,a.fnDisplayEnd(),a.aiDisplay);typeof a.fnFooterCallback== -"function"&&a.fnFooterCallback.call(a.oInstance,i(">tr",a.nTFoot)[0],aa(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 ba(a){if(a.oFeatures.bSort)R(a,a.oPreviousSearch);else if(a.oFeatures.bFilter)M(a,a.oPreviousSearch);else{E(a);C(a)}}function za(a){if(a.bAjaxDataGet){K(a,true);var b=a.aoColumns.length,c=[],d,f;a.iDraw++;c.push({name:"sEcho",value:a.iDraw});c.push({name:"iColumns",value:b});c.push({name:"sColumns",value:ha(a)}); -c.push({name:"iDisplayStart",value:a._iDisplayStart});c.push({name:"iDisplayLength",value:a.oFeatures.bPaginate!==false?a._iDisplayLength:-1});for(f=0;f")c=c.parentNode;else if(h=="l"&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange){f=Ca(a);e=1}else if(h=="f"&&a.oFeatures.bFilter){f=Da(a);e=1}else if(h=="r"&&a.oFeatures.bProcessing){f=Ea(a);e=1}else if(h=="t"){f=Fa(a);e=1}else if(h=="i"&&a.oFeatures.bInfo){f=Ga(a);e=1}else if(h=="p"&&a.oFeatures.bPaginate){f=Ha(a);e=1}else if(o.aoFeatures.length!== -0){j=o.aoFeatures;t=0;for(k=j.length;tcaption",a.nTable);h=0;for(k=d.length;hi(a.nTable).height()-a.oScroll.iLoadGap)if(a.fnDisplayEnd()0&&a.nTable.removeChild(h[0]);if(a.nTFoot!==null){k=a.nTable.getElementsByTagName("tfoot");k.length>0&&a.nTable.removeChild(k[0])}h=a.nTHead.cloneNode(true);a.nTable.insertBefore(h,a.nTable.childNodes[0]);if(a.nTFoot!==null){k=a.nTFoot.cloneNode(true); -a.nTable.insertBefore(k,a.nTable.childNodes[1])}if(a.oScroll.sX===""){d.style.width="100%";b.parentNode.style.width="100%"}var O=S(a,h);f=0;for(e=O.length;ff-a.oScroll.iBarWidth)a.nTable.style.width=u(f)}else a.nTable.style.width=u(f);f=i(a.nTable).outerWidth();if(a.oScroll.sX===""){d.style.width=u(f+a.oScroll.iBarWidth);b.parentNode.style.width=u(f+a.oScroll.iBarWidth)}e=a.nTHead.getElementsByTagName("tr");h=h.getElementsByTagName("tr");P(function(B,F){m=B.style;m.paddingTop= -"0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;q=i(B).width();F.style.width=u(q);I.push(q)},h,e);i(h).height(0);if(a.nTFoot!==null){j=k.getElementsByTagName("tr");k=a.nTFoot.getElementsByTagName("tr");P(function(B,F){m=B.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;q=i(B).width();F.style.width=u(q);I.push(q)},j,k);i(j).height(0)}P(function(B){B.innerHTML="";B.style.width=u(I.shift())},h);a.nTFoot!==null&&P(function(B){B.innerHTML= -"";B.style.width=u(I.shift())},j);if(i(a.nTable).outerWidth()d.offsetWidth?a.oScroll.iBarWidth:0;if(a.nTable.offsetHeight'):b===""?'':b+' '; -var c=p.createElement("div");c.className=a.oClasses.sFilter;c.innerHTML="";a.sTableId!==""&&typeof a.aanFeatures.f=="undefined"&&c.setAttribute("id",a.sTableId+"_filter");b=i("input",c);b.val(a.oPreviousSearch.sSearch.replace('"',"""));b.bind("keyup.DT",function(){for(var d=a.aanFeatures.f,f=0,e=d.length;f=0;d--){f=ma(H(a,a.aiDisplay[d],c,"filter"),a.aoColumns[c].sType);if(!b.test(f)){a.aiDisplay.splice(d,1);e++}}}}function Ka(a,b,c,d,f){var e=la(b,d,f);if(typeof c=="undefined"||c===null)c=0;if(o.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);ka(a,1);for(c=0;c/g,"");else if(typeof a=="string")return a.replace(/\n/g," ");else if(a===null)return"";return a}function R(a,b){var c,d,f,e,h=[],j=[],k=o.oSort;d=a.aoData;var m=a.aoColumns;if(!a.oFeatures.bServerSide&&(a.aaSorting.length!==0||a.aaSortingFixed!==null)){h=a.aaSortingFixed!== -null?a.aaSortingFixed.concat(a.aaSorting):a.aaSorting.slice();for(c=0;c=h)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 J(a,0,"Unknown paging action: "+b);return c!=a._iDisplayStart}function Ga(a){var b=p.createElement("div");b.className=a.oClasses.sInfo;if(typeof a.aanFeatures.i=="undefined"){a.aoDrawCallback.push({fn:Na,sName:"information"});a.sTableId!==""&&b.setAttribute("id",a.sTableId+"_info")}return b}function Na(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),h=a.fnFormatNumber(c),j= -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_",j)+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfo.replace("_START_",e).replace("_END_",h).replace("_TOTAL_",k)+a.oLanguage.sInfoPostFix:a.oLanguage.sInfo.replace("_START_", -e).replace("_END_",h).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="";i('select option[value="'+ -a._iDisplayLength+'"]',f).attr("selected",true);i("select",f).bind("change.DT",function(){var e=i(this).val(),h=a.aanFeatures.l;c=0;for(d=h.length;ca.aiDisplay.length|| -a._iDisplayLength==-1?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Oa(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=u(a);b.appendChild(c);a=c.offsetWidth;b.removeChild(c);return a}function ea(a){var b=0,c,d=0,f=a.aoColumns.length,e,h=i("th",a.nTHead);for(e=0;etd",b);h=S(a,e);for(e=d=0;e0)a.aoColumns[e].sWidth=u(c);d++}a.nTable.style.width=u(i(b).outerWidth());b.parentNode.removeChild(b)}}function Qa(a,b){if(a.oScroll.sX===""&&a.oScroll.sY!==""){i(b).width();b.style.width=u(i(b).outerWidth()-a.oScroll.iBarWidth)}else if(a.oScroll.sX!=="")b.style.width=u(i(b).outerWidth())}function Pa(a,b){var c= -Ra(a,b);if(c<0)return null;if(a.aoData[c].nTr===null){var d=p.createElement("td");d.innerHTML=H(a,c,b,"");return d}return Q(a,c)[b]}function Ra(a,b){for(var c=-1,d=-1,f=0;f/g,"");if(e.length>c){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 Va(a,b){if(a.length!=b.length)return 1;for(var c= -0;cb&&a[d]--;c!=-1&&a.splice(c,1)}function Ba(a,b){b=b.split(",");for(var c=[],d=0,f=a.aoColumns.length;d4096){a=p.cookie.split(";");for(var j=0,k=a.length;j=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[o.iApiIndex]);ia(b);if(typeof a=="undefined"||a)C(b)};this.fnOpen=function(a,b,c){var d=A(this[o.iApiIndex]);this.fnClose(a);var f=p.createElement("tr"),e=p.createElement("td");f.appendChild(e);e.className=c;e.colSpan=X(d);if(typeof b.jquery!="undefined"||typeof b== -"object")e.appendChild(b);else e.innerHTML=b;b=i("tr",d.nTBody);i.inArray(a,b)!=-1&&i(f).insertAfter(a);d.aoOpenRows.push({nTr:f,nParent:a});return f};this.fnClose=function(a){for(var b=A(this[o.iApiIndex]),c=0;c=X(d);if(!j)for(f=a;ftr>td."+a.oClasses.sRowEmpty,a.nTable).parent().remove();if(a.nTable!=a.nTHead.parentNode){i(">thead",a.nTable).remove();a.nTable.appendChild(a.nTHead)}if(a.nTFoot&& -a.nTable!=a.nTFoot.parentNode){i(">tfoot",a.nTable).remove();a.nTable.appendChild(a.nTFoot)}a.nTable.parentNode.removeChild(a.nTable);i(a.nTableWrapper).remove();a.aaSorting=[];a.aaSortingFixed=[];T(a);i($(a)).removeClass(a.asStripClasses.join(" "));if(a.bJUI){i("th",a.nTHead).removeClass([o.oStdClasses.sSortable,o.oJUIClasses.sSortableAsc,o.oJUIClasses.sSortableDesc,o.oJUIClasses.sSortableNone].join(" "));i("th span."+o.oJUIClasses.sSortIcon,a.nTHead).remove();i("th",a.nTHead).each(function(){var e= -i("div."+o.oJUIClasses.sSortJUIWrapper,this),h=e.contents();i(this).append(h);e.remove()})}else i("th",a.nTHead).removeClass([o.oStdClasses.sSortable,o.oStdClasses.sSortableAsc,o.oStdClasses.sSortableDesc,o.oStdClasses.sSortableNone].join(" "));a.nTableReinsertBefore?b.insertBefore(a.nTable,a.nTableReinsertBefore):b.appendChild(a.nTable);d=0;for(f=a.aoData.length;dtr:even",c).addClass(a.asDestoryStrips[0]);i(">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=Ua();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;Ta(e,g);e.aoDrawCallback.push({fn:sa,sName:"state_save"})}if(typeof g.iDeferLoading!="undefined"){e.bDeferLoading=true;e._iRecordsTotal=g.iDeferLoading;e._iRecordsDisplay=g.iDeferLoading}if(typeof g.aaData!="undefined")j=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;i.getJSON(e.oLanguage.sUrl,null,function(t){y(e,t,true)});h=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=i(">tbody>tr",this);a=0;for(b=e.asStripClasses.length;a=0;a--){var m=g.aoColumnDefs[a].aTargets;i.isArray(m)||J(e,1,"aTargets must be an array of targets, not a "+typeof m);c=0;for(d=m.length;c=0){for(;e.aoColumns.length<=m[c];)G(e);x(e,m[c],g.aoColumnDefs[a])}else if(typeof m[c]== -"number"&&m[c]<0)x(e,e.aoColumns.length+m[c],g.aoColumnDefs[a]);else if(typeof m[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;cthead",this);if(a.length===0){a=[p.createElement("thead")];this.appendChild(a[0])}e.nTHead=a[0];a=i(">tbody",this);if(a.length===0){a=[p.createElement("tbody")];this.appendChild(a[0])}e.nTBody=a[0];a=i(">tfoot",this);if(a.length>0){e.nTFoot=a[0];W(e.aoFooter,e.nTFoot)}if(j)for(a=0;an[g])d(a.aoColumns.length+n[g],b[f]);else if("string"===typeof n[g])for(e=0,u=a.aoColumns.length;eb&&a[d]--; -1!=c&&a.splice(c,1)}function R(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mDataProp},w(a,b,c,"display"))}function ca(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;if(c._aData.DT_RowId)c.nTr.id=c._aData.DT_RowId;c._aData.DT_RowClass&&h(c.nTr).addClass(c._aData.DT_RowClass);for(var f=0,g=a.aoColumns.length;f=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,B(a);if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!wa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var i=a._iDisplayStart;c=a._iDisplayEnd;if(a.oFeatures.bServerSide)i=0,c=a.aoData.length;for(;i")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=h('
    ')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),f,g,i,e,u,n,o,k=0;k")[0];u=d[k+1];if("'"==u||'"'==u){n="";for(o=2;d[k+o]!=u;)n+=d[k+o],o++;"H"==n?n="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix": +"F"==n&&(n="fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix");-1!=n.indexOf(".")?(u=n.split("."),e.id=u[0].substr(1,u[0].length-1),e.className=u[1]):"#"==n.charAt(0)?e.id=n.substr(1,n.length-1):e.className=n;k+=o}c.appendChild(e);c=e}else if(">"==i)c=c.parentNode;else if("l"==i&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)f=ya(a),g=1;else if("f"==i&&a.oFeatures.bFilter)f=za(a),g=1;else if("r"==i&&a.oFeatures.bProcessing)f=Aa(a),g=1;else if("t"==i)f=Ba(a),g= +1;else if("i"==i&&a.oFeatures.bInfo)f=Ca(a),g=1;else if("p"==i&&a.oFeatures.bPaginate)f=Da(a),g=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;o=0;for(u=e.length;o'):""===c?'':c+' ',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";if(!a.aanFeatures.f)d.id=a.sTableId+"_filter";c=h('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=""===this.value?"":this.value,i=0,e=c.length;i=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||f.sSearch.length>b.length||1==c||0!==b.indexOf(f.sSearch)){a.aiDisplay.splice(0,a.aiDisplay.length);ja(a,1);for(b=0;b/g,""):"string"===typeof a? +a.replace(/[\r\n]/g," "):a}function na(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^)","g"),"\\$1")}function Ca(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;if(!a.aanFeatures.i)a.aoDrawCallback.push({fn:Ja,sName:"information"}),b.id=a.sTableId+"_info";a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function Ja(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(), +f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),i;i=0===g&&g==f?b.sInfoEmpty:0===g?b.sInfoEmpty+" "+b.sInfoFiltered:g==f?b.sInfo:b.sInfo+" "+b.sInfoFiltered;i+=b.sInfoPostFix;i=ha(a,i);null!==b.fnInfoCallback&&(i=b.fnInfoCallback.call(a.oInstance,a,c,d,f,g,i));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,f=a.aLengthMenu;if(2==f.length&&"object"===typeof f[0]&&"object"===typeof f[1])for(c=0,d=f[0].length;c'+f[1][c]+"";else for(c=0,d=f.length;c'+f[c]+"";b+="";f=l.createElement("div");if(!a.aanFeatures.l)f.id=a.sTableId+"_length";f.className=a.oClasses.sLength;f.innerHTML="";h('select option[value="'+a._iDisplayLength+'"]',f).attr("selected",!0);h("select",f).bind("change.DT",function(){var b=h(this).val(),f=a.aanFeatures.l;for(c=0,d=f.length;ca._iDisplayStart))a._iDisplayStart=0;if(-1==a._iDisplayLength)a._iDisplayStart=0;z(a)});h("select",f).attr("aria-controls",a.sTableId);return f}function B(a){a._iDisplayEnd=!1===a.oFeatures.bPaginate?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength} +function Da(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a,b,function(a){B(a);z(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){B(a);z(a)})},sName:"pagination"});return b}function pa(a,b){var c=a._iDisplayStart;if("number"===typeof b){if(a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay())a._iDisplayStart= +0}else if("first"==b)a._iDisplayStart=0;else if("previous"==b){if(a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart)a._iDisplayStart=0}else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthh(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()=h.browser.version;h(a.nTable).children("thead, tfoot").remove();i=h(a.nTHead).clone()[0];a.nTable.insertBefore(i,a.nTable.childNodes[0]);null!==a.nTFoot&&(j=h(a.nTFoot).clone()[0],a.nTable.insertBefore(j,a.nTable.childNodes[1]));if(""===a.oScroll.sX)d.style.width="100%",b.parentNode.style.width="100%";var r=O(a,i);for(f=0,g=r.length;fd.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width=q(h(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else if(""!==a.oScroll.sXInner)a.nTable.style.width=q(a.oScroll.sXInner);else if(f==h(d).width()&&h(d).height()f-a.oScroll.iBarWidth)a.nTable.style.width=q(f)}else a.nTable.style.width=q(f);f=h(a.nTable).outerWidth();g=a.nTHead.getElementsByTagName("tr");i=i.getElementsByTagName("tr");N(function(a,b){n=a.style;n.paddingTop="0";n.paddingBottom="0";n.borderTopWidth="0";n.borderBottomWidth="0";n.height=0;k=h(a).width();b.style.width=q(k);m.push(k)},i,g);h(i).height(0);null!==a.nTFoot&&(e=j.getElementsByTagName("tr"),j=a.nTFoot.getElementsByTagName("tr"),N(function(a, +b){n=a.style;n.paddingTop="0";n.paddingBottom="0";n.borderTopWidth="0";n.borderBottomWidth="0";n.height=0;k=h(a).width();b.style.width=q(k);m.push(k)},e,j),h(e).height(0));N(function(a){a.innerHTML="";a.style.width=q(m.shift())},i);null!==a.nTFoot&&N(function(a){a.innerHTML="";a.style.width=q(m.shift())},e);if(h(a.nTable).outerWidth()d.offsetHeight||"scroll"==h(d).css("overflow-y")?f+a.oScroll.iBarWidth:f;if(l&&(d.scrollHeight>d.offsetHeight||"scroll"==h(d).css("overflow-y")))a.nTable.style.width= +q(e-a.oScroll.iBarWidth);d.style.width=q(e);b.parentNode.style.width=q(e);if(null!==a.nTFoot)s.parentNode.style.width=q(e);""===a.oScroll.sX?F(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."):""!==a.oScroll.sXInner&&F(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else if(d.style.width= +q("100%"),b.parentNode.style.width=q("100%"),null!==a.nTFoot)s.parentNode.style.width=q("100%");if(""===a.oScroll.sY&&l)d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth);if(""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),l=""!==a.oScroll.sX&&a.nTable.offsetWidth>d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeight +d.clientHeight||"scroll"==h(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";if(null!==a.nTFoot)p.style.width=q(l),s.style.width=q(l),s.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px";h(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function N(a,b,c){for(var d=0,f=b.length;dtd",b));i=O(a,g);for(g=d=0;gc)return null; +if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=w(a,c,b,"");return d}return L(a,c)[b]}function Oa(a,b){for(var c=-1,d=-1,f=0;f/g,"");if(g.length>c)c=g.length,d=f}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1);return 48>b||57/g, +""),f=l[c].nTh,f.removeAttribute("aria-sort"),f.removeAttribute("aria-label"),l[c].bSortable?0=e)for(b=0;bj&&j++}}}function qa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b, +c;b=a.oScroll.bInfinite;var d={iCreate:(new Date).getTime(),iStart:b?0:a._iDisplayStart,iEnd:b?a._iDisplayLength:a._iDisplayEnd,iLength:a._iDisplayLength,aaSorting:h.extend(!0,[],a.aaSorting),oSearch:h.extend(!0,{},a.oPreviousSearch),aoSearchCols:h.extend(!0,[],a.aoPreSearchCols),abVisCols:[]};for(b=0,c=a.aoColumns.length;b=d.aiDisplay.length&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart))d._iDisplayStart=0;if(c===m||c)B(d),z(d);return e};this.fnDestroy=function(a){var b=t(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,f,g,a=a===m?!1:!0;b.bDestroying= +!0;D(b,"aoDestroyCallback","destroy",[b]);for(f=0,g=b.aoColumns.length;ftr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(h(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(h(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable); +h(b.nTableWrapper).remove();b.aaSorting=[];b.aaSortingFixed=[];Q(b);h(S(b)).removeClass(b.asStripeClasses.join(" "));h("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc,b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(h("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),h("th, td",b.nTHead).each(function(){var a=h("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();h(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore? +c.insertBefore(b.nTable,b.nTableReinsertBefore):a||c.appendChild(b.nTable);for(f=0,g=b.aoData.length;f=v(d);if(!n)for(f=a;ft<"F"ip>'}else h.extend(i.oClasses,j.ext.oStdClasses);h(this).addClass(i.oClasses.sTable);if(""!==i.oScroll.sX||""!==i.oScroll.sY)i.oScroll.iBarWidth=Pa();if(i.iInitDisplayStart===m)i.iInitDisplayStart=e.iDisplayStart,i._iDisplayStart=e.iDisplayStart;if(e.bStateSave)i.oFeatures.bStateSave=!0,Ra(i,e),C(i,"aoDrawCallback",qa,"state_save");if(null!==e.iDeferLoading)i.bDeferLoading= +!0,a=h.isArray(e.iDeferLoading),i._iRecordsDisplay=a?e.iDeferLoading[0]:e.iDeferLoading,i._iRecordsTotal=a?e.iDeferLoading[1]:e.iDeferLoading;null!==e.aaData&&(g=!0);""!==e.oLanguage.sUrl?(i.oLanguage.sUrl=e.oLanguage.sUrl,h.getJSON(i.oLanguage.sUrl,null,function(a){oa(a);h.extend(!0,i.oLanguage,e.oLanguage,a);aa(i)}),f=!0):h.extend(!0,i.oLanguage,e.oLanguage);if(null===e.asStripeClasses)i.asStripeClasses=[i.oClasses.sStripeOdd,i.oClasses.sStripeEven];c=!1;d=h(this).children("tbody").children("tr"); +for(a=0,b=i.asStripeClasses.length;a=i.aoColumns.length&& +(i.aaSorting[a][0]=0);var k=i.aoColumns[i.aaSorting[a][0]];i.aaSorting[a][2]===m&&(i.aaSorting[a][2]=0);e.aaSorting===m&&i.saved_aaSorting===m&&(i.aaSorting[a][1]=k.asSorting[0]);for(c=0,d=k.asSorting.length;c=parseInt(l,10)};j.fnIsDataTable=function(e){for(var h=j.settings,m=0;me)return e;for(var h=e+"",e=h.split(""),j="",h=h.length,k=0;k'+k.sPrevious+'
    '+k.sNext+"": +'';h(j).append(k);var r=h("a",j),k=r[0],r=r[1];e.oApi._fnBindAction(k,{action:"previous"},l);e.oApi._fnBindAction(r,{action:"next"},l);if(!e.aanFeatures.p)j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_previous",r.id=e.sTableId+ +"_next",k.setAttribute("aria-controls",e.sTableId),r.setAttribute("aria-controls",e.sTableId)},fnUpdate:function(e){if(e.aanFeatures.p)for(var h=e.oClasses,j=e.aanFeatures.p,k=0,m=j.length;k'+k.sFirst+''+k.sPrevious+''+k.sNext+''+k.sLast+"");var v=h("a",j),k=v[0],l=v[1],A=v[2],v=v[3]; +e.oApi._fnBindAction(k,{action:"first"},r);e.oApi._fnBindAction(l,{action:"previous"},r);e.oApi._fnBindAction(A,{action:"next"},r);e.oApi._fnBindAction(v,{action:"last"},r);if(!e.aanFeatures.p)j.id=e.sTableId+"_paginate",k.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",A.id=e.sTableId+"_next",v.id=e.sTableId+"_last"},fnUpdate:function(e,m){if(e.aanFeatures.p){var l=j.ext.oPagination.iFullNumbersShowPages,k=Math.floor(l/2),x=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),r=Math.ceil(e._iDisplayStart/ +e._iDisplayLength)+1,v="",A,E=e.oClasses,y,J=e.aanFeatures.p,H=function(h){e.oApi._fnBindAction(this,{page:h+A-1},function(h){e.oApi._fnPageChange(e,h.data.page);m(e);h.preventDefault()})};-1===e._iDisplayLength?r=k=A=1:x=x-k?(A=x-l+1,k=x):(A=r-Math.ceil(l/2)+1,k=A+l-1);for(l=A;l<=k;l++)v+=r!==l?''+e.fnFormatNumber(l)+"":''+e.fnFormatNumber(l)+""; +for(l=0,k=J.length;lh?1:0},"string-desc":function(e,h){return eh?-1:0},"html-pre":function(e){return e.replace(/<.*?>/g,"").toLowerCase()},"html-asc":function(e,h){return eh?1:0},"html-desc":function(e,h){return eh?-1:0},"date-pre":function(e){e=Date.parse(e);if(isNaN(e)||""===e)e=Date.parse("01/01/1970 00:00:00");return e},"date-asc":function(e,h){return e-h},"date-desc":function(e, +h){return h-e},"numeric-pre":function(e){return"-"==e||""===e?0:1*e},"numeric-asc":function(e,h){return e-h},"numeric-desc":function(e,h){return h-e}});h.extend(j.ext.aTypes,[function(e){if("number"===typeof e)return"numeric";if("string"!==typeof e)return null;var h,j=!1;h=e.charAt(0);if(-1=="0123456789-".indexOf(h))return null;for(var k=1;k")?"html":null}]);h.fn.DataTable=j;h.fn.dataTable=j;h.fn.dataTableSettings=j.settings;h.fn.dataTableExt=j.ext})(jQuery,window,document,void 0); From 8cf1da4ddbc2381aaa6f88709c4e946ff81926cb Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Thu, 26 Apr 2012 15:02:29 +0200 Subject: [PATCH 287/287] Fix: mac os compatibility --- htdocs/admin/tools/update.php | 47 ++++++++++++++++++++++++++--------- htdocs/core/lib/files.lib.php | 39 +++++++++++++++++++---------- 2 files changed, 61 insertions(+), 25 deletions(-) diff --git a/htdocs/admin/tools/update.php b/htdocs/admin/tools/update.php index 5658728c6a0..233bf9be7fd 100644 --- a/htdocs/admin/tools/update.php +++ b/htdocs/admin/tools/update.php @@ -75,20 +75,33 @@ if (GETPOST('action','alpha')=='install') $result=dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'],$newfile,1,0,$_FILES['fileinstall']['error']); if ($result > 0) { - $rutax=DOL_DOCUMENT_ROOT_ALT; - $result=dol_uncompress($newfile,$_FILES['fileinstall']['type'],$rutax); - if ($result==2) + $documentrootalt=DOL_DOCUMENT_ROOT_ALT; + $result=dol_uncompress($newfile,$_FILES['fileinstall']['type'],$documentrootalt); + if (! empty($result['error'])) { - $langs->load("errors"); - $mesg = "".$langs->trans("ErrorOSSystem").""; + if ($result['error'] == -1) + { + $langs->load("errors"); + $mesg = '
    '.$langs->trans("ErrorBadFileFormat").'
    '; + } + elseif ($result['error'] == -2) + { + $langs->load("errors"); + $mesg = '
    '.$langs->trans("ErrorOSSystem").'
    '; + } + elseif ($result['error'] == -3) + { + $langs->load("errors"); + $mesg = '
    '.$langs->trans("ErrorUncompFile",$_FILES['fileinstall']['name']).'
    '; + } + elseif ($result['error'] == -4) + { + $langs->load("errors"); + $mesg = '
    '.$langs->trans("ErrorUncompFile",$_FILES['fileinstall']['name']).'
    '; + } } - elseif ($result==3) + else { - $langs->load("errors"); - $mesg = "".$langs->trans("ErrorUncompFile",$_FILES['fileinstall']['name']).""; - } - - else { $mesg = "".$langs->trans("SetupIsReadyForUse").""; } } @@ -146,7 +159,7 @@ print ''.$langs->trans("StepNb",3).': '; print $langs->trans("UnpackPackageInDolibarrRoot",$dolibarrroot).'
    '; if (! empty($conf->global->MAIN_ONLINE_INSTALL_MODULE)) { - if ($vale == 1 && $dirins != 'DOL_DOCUMENT_ROOT_ALT' && ($system=="Linux")) + if ($vale == 1 && $dirins != 'DOL_DOCUMENT_ROOT_ALT' && ($system=="Linux" || $system=="Darwin")) { print '
    '; print ''; @@ -173,6 +186,16 @@ else } print '
    '; +if (! empty($result['return'])) +{ + print '
    '; + + foreach($result['return'] as $value) + { + echo $value.'
    '; + } +} + llxFooter(); $db->close(); ?> \ No newline at end of file diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 40897263a4f..85cd1c1eb7e 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -629,14 +629,16 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable function dol_uncompress($newfile,$typefile,$dstdir) { global $conf; - $error=0; + + $error=0; + $output=array(); $system=PHP_OS; //TODO: See best method for this - if ($system=="Linux") + if ($system=="Linux" || $system=="Darwin") { - if ($typefile == 'application/x-gzip') + if ($typefile == 'application/x-gzip' || $typefile == 'application/x-gtar') { $prog= "tar -xzvf "; } @@ -646,22 +648,33 @@ function dol_uncompress($newfile,$typefile,$dstdir) } else { - $error=1; + $output['error'] = -1; + $error++; } } else { - $error=2; + $output['error'] = -2; + $error++; } - $original_file=basename($_FILES["fileinstall"]["name"]); - $diruncom=$conf->admin->dir_temp.'/'.$original_file; - $ruta=$diruncom.'/'.$original_file; - chdir ($dstdir); - $command= $prog.$ruta; - $res=exec($command); - if (! $res) $error=3; - return $error; + if (! $error) + { + $original_file=basename($_FILES["fileinstall"]["name"]); + $dir=$conf->admin->dir_temp.'/'.$original_file; + $file=$dir.'/'.$original_file; + $command= $prog.$file.' 2>&1'; + + chdir($dstdir); + + exec($command, $out, $return_var); + if ($return_var == 1) $output['error'] = -3; // OK with Warning + elseif ($return_var == 127) $output['error'] = -4; // KO + + $output['return'] = $out; + } + + return $output; } /**