Dexxtz_Customer_Email - Version 1.0.0

Version Notes

Started

Download this release

Release Info

Developer Magento Core Team
Extension Dexxtz_Customer_Email
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (30) hide show
  1. app/code/community/Dexxtz/Customeremail/Block/System/Config/Source/List/Button.php +26 -0
  2. app/code/community/Dexxtz/Customeremail/Helper/Data.php +150 -0
  3. app/code/community/Dexxtz/Customeremail/Model/System/Config/Source/Customer/Options.php +21 -0
  4. app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ExportCsvController.php +45 -0
  5. app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ListController.php +18 -0
  6. app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ListajaxController.php +35 -0
  7. app/code/community/Dexxtz/Customeremail/etc/config.xml +136 -0
  8. app/code/community/Dexxtz/Customeremail/etc/system.xml +60 -0
  9. app/design/adminhtml/default/default/layout/dexxtz/customeremail.xml +26 -0
  10. app/design/adminhtml/default/default/template/dexxtz/customeremail/header.phtml +34 -0
  11. app/design/adminhtml/default/default/template/dexxtz/customeremail/list.phtml +127 -0
  12. app/etc/modules/Dexxtz_Customeremail.xml +18 -0
  13. app/locale/en_US/Dexxtz_Customeremail.csv +30 -0
  14. app/locale/pt_BR/Dexxtz_Customeremail.csv +31 -0
  15. package.xml +18 -0
  16. skin/adminhtml/default/default/dexxtz/customeremail/css/dexxtz.css +57 -0
  17. skin/adminhtml/default/default/dexxtz/customeremail/css/jquery.dataTables.css +474 -0
  18. skin/adminhtml/default/default/dexxtz/customeremail/images/btn_bg.gif +0 -0
  19. skin/adminhtml/default/default/dexxtz/customeremail/images/btn_over_bg.gif +0 -0
  20. skin/adminhtml/default/default/dexxtz/customeremail/images/details.gif +0 -0
  21. skin/adminhtml/default/default/dexxtz/customeremail/images/icon_btn_back.gif +0 -0
  22. skin/adminhtml/default/default/dexxtz/customeremail/images/massaction_bg.gif +0 -0
  23. skin/adminhtml/default/default/dexxtz/customeremail/images/sort_asc.png +0 -0
  24. skin/adminhtml/default/default/dexxtz/customeremail/images/sort_both.png +0 -0
  25. skin/adminhtml/default/default/dexxtz/customeremail/images/sort_desc.png +0 -0
  26. skin/adminhtml/default/default/dexxtz/customeremail/images/sort_row_bg.gif +0 -0
  27. skin/adminhtml/default/default/dexxtz/customeremail/images/tr_hover.png +0 -0
  28. skin/adminhtml/default/default/dexxtz/customeremail/js/dexxtz.js +144 -0
  29. skin/adminhtml/default/default/dexxtz/customeremail/js/jquery-1.11.1.js +4 -0
  30. skin/adminhtml/default/default/dexxtz/customeremail/js/jquery.dataTables.js +14622 -0
app/code/community/Dexxtz/Customeremail/Block/System/Config/Source/List/Button.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Block_System_Config_Source_List_Button extends Mage_Adminhtml_Block_System_Config_Form_Field
12
+ {
13
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
14
+ {
15
+ $this->setElement($element);
16
+ $url = $this->getUrl('dexxtz/adminhtml_list');
17
+ $html = $this->getLayout()
18
+ ->createBlock('adminhtml/widget_button')
19
+ ->setType('button')
20
+ ->setClass('scalable')
21
+ ->setLabel(Mage::helper('customeremail')->__('Click here'))
22
+ ->setOnClick("setLocation('$url')")->toHtml();
23
+ return $html;
24
+ }
25
+ }
26
+ ?>
app/code/community/Dexxtz/Customeremail/Helper/Data.php ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Helper_Data extends Mage_Core_Helper_Abstract
12
+ {
13
+ private $customerGroups = array();
14
+ private $customerArray = array();
15
+
16
+ private function getCustomerGroupsSelected()
17
+ {
18
+ $customer_groups = Mage::getStoreConfig('customeremail/dexxtz/customer_groups');
19
+ $this->customerGroups = explode(',', $customer_groups);
20
+ return $this->customerGroups;
21
+ }
22
+
23
+ public function checkListAccess()
24
+ {
25
+ $configUrl = Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/system_config/edit/section/customeremail/');
26
+ $selected = $this->getCustomerGroupsSelected();
27
+ if (strlen($selected[0]) == 0) {
28
+ $message = 'Para listar os e-mails de clientes, selecione pelo menos 1 grupo de cliente';
29
+ Mage::getSingleton('core/session')->addError($message);
30
+ Mage::app()->getResponse()->setRedirect($configUrl);
31
+ }
32
+ }
33
+
34
+ private function getStoreId() {
35
+ if ($_SESSION['store_id']) {
36
+ $storeId = $_SESSION['store_id'];
37
+ } else {
38
+ $storeId = 0;
39
+ }
40
+
41
+ return $storeId;
42
+ }
43
+
44
+ private function getCustomerCollection()
45
+ {
46
+ $storeId = Mage::app()->getStore()->getStoreId();
47
+ $groupsSelected = $this->getCustomerGroupsSelected();
48
+
49
+ $collection = Mage::getModel('customer/customer')->getCollection();
50
+
51
+ if ($this->getStoreId())
52
+ $collection->addFieldToFilter('store_id', $this->getStoreId());
53
+
54
+ $collection->addFieldToFilter('group_id', array($this->getCustomerGroupsSelected()));
55
+ $collection->addAttributeToSelect(array('firstname', 'lastname', 'dob'));
56
+
57
+ return $collection;
58
+ }
59
+
60
+ private function getCustomerName($first, $last)
61
+ {
62
+ $name = $first . ' ' . $last;
63
+
64
+ return $name;
65
+ }
66
+
67
+ private function getDateConverted($date, $time)
68
+ {
69
+ $dateConverted = '';
70
+
71
+ if ($time == true) {
72
+ $dateConverted = Mage::app()->getLocale()->date($date);
73
+ } else {
74
+ $dateConverted = Mage::helper('core')->formatDate($date, 'medium', false);
75
+ }
76
+
77
+ return $dateConverted;
78
+ }
79
+
80
+ private function getGroupLabel($groupId)
81
+ {
82
+ $group = Mage::getModel('customer/group')->load($groupId);
83
+
84
+ return $group->getCode();
85
+ }
86
+
87
+ private function getLastPurchaseDate($customerId)
88
+ {
89
+ $order = Mage::getModel('sales/order')->getCollection()
90
+ ->addFieldToSelect('created_at')
91
+ ->addFieldToFilter('customer_id', $customerId)
92
+ ->addAttributeToSort('created_at', 'DESC')
93
+ ->setPageSize(1);
94
+
95
+ if ($order->getFirstItem()->getCreatedAt()){
96
+ $date = $order->getFirstItem()->getCreatedAt();
97
+ } else {
98
+ $date = '';
99
+ }
100
+
101
+ return $date;
102
+ }
103
+
104
+ private function getCustomerUrl($customerId)
105
+ {
106
+ $helper = Mage::helper('adminhtml');
107
+ $url = $helper->getUrl('adminhtml/customer/edit/id/' .$customerId . '/');
108
+
109
+ return $url;
110
+ }
111
+
112
+ private function createArrayCustomer()
113
+ {
114
+ $skinUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_SKIN);
115
+ $skinPath = $skinUrl . 'adminhtml/default/default/dexxtz/customeremail/';
116
+ $editImage = $skinPath . "images/details.gif";
117
+
118
+ foreach ($this->getCustomerCollection() as $customer) {
119
+ $name = $this->getCustomerName($customer['firstname'], $customer['lastname']);
120
+ $email = $customer->getEmail();
121
+ $dob = ($customer['dob']) ? $this->getDateConverted($customer['dob'], false) : '-';
122
+ $group = $this->getGroupLabel($customer->getGroupId());
123
+ $dateCreate = $this->getDateConverted($customer->getCreatedAt(), true);
124
+ $lastPurcharse = $this->getLastPurchaseDate($customer->getId());
125
+ $dateLast = ($lastPurcharse) ? $this->getDateConverted($lastPurcharse, true) : '-';
126
+ $url = $this->getCustomerUrl($customer->getId());
127
+ $textEdit = $this->__('Details');
128
+ $edit = "<a class='edit' target='_blank' href='" . $url . "'>";
129
+ $edit .= "<img title='" . $textEdit . "' alt='" . $textEdit . "' src='" . $editImage ."' />";
130
+ $edit .= "</a>";
131
+
132
+ $array = array('name' => $name,
133
+ 'email' => $email,
134
+ 'dob' => $dob,
135
+ 'group' => $group,
136
+ 'dateCreate' => $dateCreate,
137
+ 'dateLast' => $dateLast,
138
+ 'edit' => $edit);
139
+
140
+ $this->customerArray[] = $array;
141
+ }
142
+ }
143
+
144
+ public function getCustomerArray()
145
+ {
146
+ $this->createArrayCustomer();
147
+
148
+ return $this->customerArray;
149
+ }
150
+ }
app/code/community/Dexxtz/Customeremail/Model/System/Config/Source/Customer/Options.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Model_System_Config_Source_Customer_Options
12
+ {
13
+ public function toOptionArray()
14
+ {
15
+ $groupCollection = Mage::getModel('customer/group')->getCollection();
16
+ foreach ($groupCollection as $item){
17
+ $options[] = array("value" => $item->getCustomerGroupId() , "label" => $item->getCustomerGroupCode());
18
+ }
19
+ return $options;
20
+ }
21
+ }
app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ExportCsvController.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Adminhtml_ExportCsvController extends Mage_Adminhtml_Controller_Action
12
+ {
13
+ public function indexAction()
14
+ {
15
+ // Aumentar tamanho no php.ini max_input_vars = 10000
16
+ if ($this->getRequest()->getPost('csv')) {
17
+ $_SESSION['dexxtz_export_csv_customeremail'] = $this->getRequest()->getPost('csv');
18
+ }
19
+
20
+ if ($this->getRequest()->getPost('empty') == 1 ){
21
+ $_SESSION['dexxtz_export_csv_customeremail'] = '';
22
+ }
23
+
24
+ header('Content-Type: text/csv; charset=utf-8');
25
+ header('Content-Disposition: attachment; filename=emails.csv');
26
+
27
+ // create a file pointer connected to the output stream
28
+ $output = fopen('php://output', 'w');
29
+
30
+ $titles = array ('Nome',
31
+ 'E-mail',
32
+ 'Nascido em',
33
+ 'Grupo',
34
+ 'Ultima Compra',
35
+ 'Cliente Desde'
36
+ );
37
+
38
+ fputcsv($output, $titles);
39
+ if ($_SESSION['dexxtz_export_csv_customeremail']) {
40
+ foreach ($_SESSION['dexxtz_export_csv_customeremail'] as $info) {
41
+ fputcsv($output, $info);
42
+ }
43
+ }
44
+ }
45
+ }
app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ListController.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Adminhtml_ListController extends Mage_Adminhtml_Controller_Action
12
+ {
13
+ public function indexAction()
14
+ {
15
+ $_SESSION['store_id'] = Mage::app()->getRequest()->getParam('store');
16
+ $this->loadLayout()->renderLayout();
17
+ }
18
+ }
app/code/community/Dexxtz/Customeremail/controllers/Adminhtml/ListajaxController.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ class Dexxtz_Customeremail_Adminhtml_ListajaxController extends Mage_Adminhtml_Controller_Action
12
+ {
13
+ public function indexAction()
14
+ {
15
+ $listArray = Mage::helper('customeremail')->getCustomerArray();
16
+
17
+ if ($listArray) {
18
+
19
+ $dataSet = '[';
20
+ $j = 1;
21
+ foreach ($listArray as $info) {
22
+ $i = 1;
23
+ $dataSet .= ($j > 1) ? ',[' : '[';
24
+ foreach ($info as $item) {
25
+ $dataSet .= (count($info) != $i) ? '"' . $item . '",' : '"' . $item . '"';
26
+ $i++;
27
+ }
28
+ $dataSet .= ']';
29
+ $j++;
30
+ }
31
+ $dataSet .= ']';
32
+ echo $dataSet;
33
+ }
34
+ }
35
+ }
app/code/community/Dexxtz/Customeremail/etc/config.xml ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+ -->
11
+ <config>
12
+ <modules>
13
+ <Dexxtz_Customeremail>
14
+ <version>1.0.0</version>
15
+ </Dexxtz_Customeremail>
16
+ </modules>
17
+ <frontend>
18
+ <routers>
19
+ <customeremail>
20
+ <use>standard</use>
21
+ <args>
22
+ <module>Dexxtz_Customeremail</module>
23
+ <frontName>customeremail</frontName>
24
+ </args>
25
+ </customeremail>
26
+ </routers>
27
+ <translate>
28
+ <modules>
29
+ <Dexxtz_Customeremail>
30
+ <files>
31
+ <default>Dexxtz_Customeremail.csv</default>
32
+ </files>
33
+ </Dexxtz_Customeremail>
34
+ </modules>
35
+ </translate>
36
+ </frontend>
37
+ <admin>
38
+ <routers>
39
+ <dexxtz>
40
+ <use>admin</use>
41
+ <args>
42
+ <module>Dexxtz_Customeremail</module>
43
+ <frontName>customeremail</frontName>
44
+ </args>
45
+ </dexxtz>
46
+ <adminhtml>
47
+ <args>
48
+ <modules>
49
+ <customeremail before="Mage_Adminhtml">Dexxtz_Customeremail</customeremail>
50
+ </modules>
51
+ </args>
52
+ </adminhtml>
53
+ </routers>
54
+ </admin>
55
+ <adminhtml>
56
+ <acl>
57
+ <resources>
58
+ <all>
59
+ <title>Allow Everything</title>
60
+ </all>
61
+ <admin>
62
+ <children>
63
+ <Dexxtz_Customeremail>
64
+ <title>Customeremail Module</title>
65
+ <sort_order>10</sort_order>
66
+ </Dexxtz_Customeremail>
67
+ <system>
68
+ <children>
69
+ <config>
70
+ <children>
71
+ <customeremail>
72
+ <title>Customeremail</title>
73
+ </customeremail>
74
+ </children>
75
+ </config>
76
+ </children>
77
+ </system>
78
+ </children>
79
+ </admin>
80
+ </resources>
81
+ </acl>
82
+ <translate>
83
+ <modules>
84
+ <Dexxtz_Customeremail>
85
+ <files>
86
+ <default>Dexxtz_Customeremail.csv</default>
87
+ </files>
88
+ </Dexxtz_Customeremail>
89
+ </modules>
90
+ </translate>
91
+ <layout>
92
+ <updates>
93
+ <pagseguro>
94
+ <file>dexxtz/customeremail.xml</file>
95
+ </pagseguro>
96
+ </updates>
97
+ </layout>
98
+ </adminhtml>
99
+ <global>
100
+ <resources>
101
+ <dexxtz_customeremail_setup>
102
+ <setup>
103
+ <module>Dexxtz_Customeremail</module>
104
+ </setup>
105
+ <connection>
106
+ <use>core_setup</use>
107
+ </connection>
108
+ </dexxtz_customeremail_setup>
109
+ <customeremail_write>
110
+ <connection>
111
+ <use>core_write</use>
112
+ </connection>
113
+ </customeremail_write>
114
+ <customeremail_read>
115
+ <connection>
116
+ <use>core_read</use>
117
+ </connection>
118
+ </customeremail_read>
119
+ </resources>
120
+ <blocks>
121
+ <dexxtz>
122
+ <class>Dexxtz_Customeremail_Block</class>
123
+ </dexxtz>
124
+ </blocks>
125
+ <models>
126
+ <dexxtz>
127
+ <class>Dexxtz_Customeremail_Model</class>
128
+ </dexxtz>
129
+ </models>
130
+ <helpers>
131
+ <customeremail>
132
+ <class>Dexxtz_Customeremail_Helper</class>
133
+ </customeremail>
134
+ </helpers>
135
+ </global>
136
+ </config>
app/code/community/Dexxtz/Customeremail/etc/system.xml ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+ -->
11
+ <config>
12
+ <tabs>
13
+ <dexxtz translate="label">
14
+ <label>Dexxtz</label>
15
+ <sort_order>150</sort_order>
16
+ </dexxtz>
17
+ </tabs>
18
+ <sections>
19
+ <customeremail translate="label" module="customeremail">
20
+ <label>List E-mails of Customers</label>
21
+ <tab>dexxtz</tab>
22
+ <frontend_type>text</frontend_type>
23
+ <sort_order>20</sort_order>
24
+ <show_in_default>1</show_in_default>
25
+ <show_in_website>1</show_in_website>
26
+ <show_in_store>1</show_in_store>
27
+ <groups>
28
+ <dexxtz translate="label">
29
+ <label>List Settings of E-mails</label>
30
+ <frontend_type>text</frontend_type>
31
+ <sort_order>1</sort_order>
32
+ <show_in_default>1</show_in_default>
33
+ <show_in_website>1</show_in_website>
34
+ <show_in_store>1</show_in_store>
35
+ <fields>
36
+ <customer_groups translate="label">
37
+ <label>Customer groups</label>
38
+ <comment>Select one or more groups of customers</comment>
39
+ <frontend_type>multiselect</frontend_type>
40
+ <source_model>dexxtz/system_config_source_customer_options</source_model>
41
+ <sort_order>10</sort_order>
42
+ <show_in_default>1</show_in_default>
43
+ <show_in_website>1</show_in_website>
44
+ <show_in_store>1</show_in_store>
45
+ </customer_groups>
46
+ <list_button translate="label">
47
+ <label>Access the client list</label>
48
+ <frontend_type>button</frontend_type>
49
+ <frontend_model>dexxtz/system_config_source_list_button</frontend_model>
50
+ <sort_order>20</sort_order>
51
+ <show_in_default>1</show_in_default>
52
+ <show_in_website>1</show_in_website>
53
+ <show_in_store>1</show_in_store>
54
+ </list_button>
55
+ </fields>
56
+ </dexxtz>
57
+ </groups>
58
+ </customeremail>
59
+ </sections>
60
+ </config>
app/design/adminhtml/default/default/layout/dexxtz/customeremail.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+ -->
11
+ <layout>
12
+ <dexxtz_adminhtml_list_index>
13
+ <update handle="dexxtz_list_index"/>
14
+ <reference name="head">
15
+ <action method="addCss"><stylesheet>dexxtz/customeremail/css/jquery.dataTables.css</stylesheet></action>
16
+ <action method="addCss"><stylesheet>dexxtz/customeremail/css/dexxtz.css</stylesheet></action>
17
+ <action method="addItem"><type>skin_js</type><name>dexxtz/customeremail/js/jquery-1.11.1.js</name><params/><if/></action>
18
+ <action method="addItem"><type>skin_js</type><name>dexxtz/customeremail/js/jquery.dataTables.js</name><params/><if/></action>
19
+ </reference>
20
+ <reference name="content">
21
+ <block type="adminhtml/template" name="header" template="dexxtz/customeremail/header.phtml"/>
22
+ <block type="adminhtml/store_switcher" name="store_switcher" template="store/switcher.phtml" />
23
+ <block type="adminhtml/template" name="list" template="dexxtz/customeremail/list.phtml"/>
24
+ </reference>
25
+ </dexxtz_adminhtml_list_index>
26
+ </layout>
app/design/adminhtml/default/default/template/dexxtz/customeremail/header.phtml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ ?>
12
+
13
+ <?php
14
+ $helper = Mage::helper('customeremail');
15
+ $helper->checkListAccess();
16
+ $newCustomerUrl = Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/customer/new/');
17
+ ?>
18
+
19
+ <div class="content-header">
20
+ <table cellspacing="0">
21
+ <tbody>
22
+ <tr>
23
+ <td style="width:50%;">
24
+ <h3 class="icon-head head-customer"><?php echo $helper->__('List Email of Customer');?></h3>
25
+ </td>
26
+ <td class="form-buttons">
27
+ <button onclick="popWin('<?php echo $newCustomerUrl; ?>')" class="scalable add" type="button" title="<?php echo $helper->__('Create Customer'); ?>">
28
+ <span><?php echo $helper->__('Create Customer'); ?></span>
29
+ </button>
30
+ </td>
31
+ </tr>
32
+ </tbody>
33
+ </table>
34
+ </div>
app/design/adminhtml/default/default/template/dexxtz/customeremail/list.phtml ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+
11
+ ?>
12
+
13
+ <?php
14
+ $helper = Mage::helper('customeremail');
15
+ $locale = Mage::app()->getLocale()->getLocaleCode();
16
+ $button = '<button onclick="exportCsv()" type="button" class="scalable">Exportar CSV</button>';
17
+ $buttonBack = Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/system_config/edit/section/customeremail');
18
+ ?>
19
+
20
+ <table id="htmlgrid" class="grid" border="0" cellpadding="10" cellspacing="10" width="100%">
21
+ <thead>
22
+ <tr>
23
+ <th width="16%"><?php echo $helper->__('Name'); ?></th>
24
+ <th width="22%"><?php echo $helper->__('E-mail'); ?></th>
25
+ <th width="13%"><?php echo $helper->__('Born in'); ?></th>
26
+ <th width="13%"><?php echo $helper->__('Group'); ?></th>
27
+ <th width="13%"><?php echo $helper->__('Client starting at'); ?></th>
28
+ <th width="13%"><?php echo $helper->__('Last purchase'); ?></th>
29
+ <th width="10%"><?php echo $helper->__('Details'); ?></th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ </tbody>
34
+ </table>
35
+
36
+ <button onclick="setLocation('<?php echo $buttonBack; ?>')" class="scalable add back-config" type="button" title="<?php echo $helper->__('Back'); ?>">
37
+ <span><?php echo $helper->__('Back'); ?></span>
38
+ </button>
39
+
40
+ <script type="text/javascript">
41
+
42
+ jQuery(document).ready(function(){
43
+
44
+ var totalRows = 0;
45
+ var oTable;
46
+ var table;
47
+ var totalFiltred = 0;
48
+ var info;
49
+ var qtyRowsSelected;
50
+ var locale = '<?php echo $locale ?>';
51
+ var string = '';
52
+ var newString = '';
53
+ var urlListAjax = '<?php echo Mage::getSingleton('adminhtml/url')->getUrl('dexxtz/adminhtml_listajax'); ?>';
54
+ var urlExportCsv = '<?php echo Mage::getSingleton('adminhtml/url')->getUrl('dexxtz/adminhtml_exportcsv'); ?>';
55
+ var formKey = '<?php echo Mage::getSingleton('core/session')->getFormKey();?>';
56
+
57
+ jQuery('#loading-mask').fadeIn('slow');
58
+
59
+ jQuery('#htmlgrid').dataTable({
60
+
61
+ "lengthMenu": [[10, 25, 50, 100, 500, -1], [10, 25, 50, 100, 500, "<?php echo $helper->__('ALL'); ?>"]],
62
+ "bStateSave": true,
63
+ "pageLength": 10,
64
+ "sPaginationType": "full_numbers",
65
+ "sDom": '<"dataTables_Toolbar"<"export-csv">lfr>t<"dataTables_ToolbarFooter"ip>',
66
+ "aaSorting": [[ 0, "asc" ]],
67
+ "aoColumnDefs": [
68
+ { 'bSortable': false, 'aTargets': [ 6 ] },
69
+ { "sClass": "field-sort a-left", 'aTargets': [ 0, 1 ] },
70
+ { "sClass": "field-sort a-center", 'aTargets': [ 2, 3, 4, 5 ] },
71
+ { "sClass": "a-center", 'aTargets': [ 6 ] }
72
+ ],
73
+
74
+ "oLanguage": {
75
+ //"sProcessing": "Processing...",
76
+ "sLengthMenu": "<?php echo $helper->__('Show _MENU_ records');?>",
77
+ "sEmptyTable": "<?php echo $helper->__('No record found.');?>",
78
+ "sZeroRecords": "<?php echo $helper->__('Filter: No Record found.');?>",
79
+ "sInfo": "<?php echo $helper->__('Showing _START_ to _END_ of _TOTAL_ records');?>",
80
+ "sInfoEmpty": "<?php echo $helper->__('Showing 0 to 0 of 0 records');?>",
81
+ "sInfoFiltered": "<?php echo $helper->__('(filtered from _MAX_ total records)');?>",
82
+ "sInfoPostFix": "",
83
+ "sSearch": "<?php echo $helper->__('Search:');?>",
84
+ "sUrl": "",
85
+ "oPaginate": {
86
+ "sFirst": "<?php echo $helper->__('First');?>",
87
+ "sPrevious": "<?php echo $helper->__('Previous');?>",
88
+ "sNext": "<?php echo $helper->__('Next');?>",
89
+ "sLast": "<?php echo $helper->__('Last');?>"
90
+ }
91
+ },
92
+
93
+ "fnDrawCallback": function(oSettings, nRow) {
94
+
95
+ trHoverClick();
96
+
97
+ oTable = this;
98
+ totalRows = oTable.fnGetData().length;
99
+ totalFiltred = jQuery("#htmlgrid").dataTable()._('tr', {"filter": "applied"}).length;
100
+ table = jQuery('#htmlgrid').DataTable();
101
+ info = table.page.info();
102
+ qtyRowsSelected = jQuery("#htmlgrid_length option:selected").val();
103
+
104
+ convertInfoCommaForPoint(locale);
105
+
106
+ removeNavPageOptions(totalRows, totalFiltred, info.page, info.pages);
107
+
108
+ removePageIndexSelection(qtyRowsSelected,totalFiltred);
109
+ },
110
+ });
111
+
112
+ jQuery('.dataTables_empty').text('<?php echo $helper->__('Loading...');?>');
113
+
114
+ configToolbar('<?php echo $button; ?>');
115
+
116
+ executeAjax(urlListAjax, formKey, '<?php echo $helper->__('No record found.');?>');
117
+ });
118
+
119
+ function exportCsv() {
120
+ var urlExportCsv = '<?php echo Mage::getSingleton('adminhtml/url')->getUrl('dexxtz/adminhtml_exportcsv'); ?>';
121
+ var formKey = '<?php echo Mage::getSingleton('core/session')->getFormKey();?>';
122
+
123
+ jQuery('#loading-mask').fadeIn('slow');
124
+ generateCsv(formKey, urlExportCsv);
125
+ }
126
+ </script>
127
+ <script type="text/javascript" src="<?php echo $this->getSkinUrl('dexxtz/customeremail/js/dexxtz.js');?>"></script>
app/etc/modules/Dexxtz_Customeremail.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Copyright [2014] [Dexxtz]
5
+ *
6
+ * @package Dexxtz_Customeremail
7
+ * @author Dexxtz
8
+ * @license http://www.apache.org/licenses/LICENSE-2.0
9
+ */
10
+ -->
11
+ <config>
12
+ <modules>
13
+ <Dexxtz_Customeremail>
14
+ <active>true</active>
15
+ <codePool>community</codePool>
16
+ </Dexxtz_Customeremail>
17
+ </modules>
18
+ </config>
app/locale/en_US/Dexxtz_Customeremail.csv ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "List E-mails of Customers","List E-mails of Customers"
2
+ "List Settings of E-mails","List Settings of E-mails"
3
+ "Customer groups","Customer groups"
4
+ "Select one or more groups of customers","Select one or more groups of customers"
5
+ "Access the client list","Access the client list"
6
+ "Click here","Click here"
7
+ "List Email of Customer","List Email of Customer"
8
+ "Create Customer","Create Customer"
9
+ "Choose Store View:","Choose Store View:"
10
+ "ALL","ALL"
11
+ "Name","Name"
12
+ "E-mail","E-mail"
13
+ "Born in","Born in"
14
+ "Group","Group"
15
+ "Client starting at","Client starting at"
16
+ "Last purchase","Last purchase"
17
+ "Details","Details"
18
+ "Show _MENU_ records","Show _MENU_ records"
19
+ "No record found.","No record found."
20
+ "Filter: No Record found.","Filter: No Record found."
21
+ "Showing _START_ to _END_ of _TOTAL_ records","Showing _START_ to _END_ of _TOTAL_ records"
22
+ "Showing 0 to 0 of 0 records","Showing 0 to 0 of 0 records"
23
+ "(filtered from _MAX_ total records)","(filtered from _MAX_ total records)"
24
+ "Search:","Search:"
25
+ "First","First"
26
+ "Previous","Previous"
27
+ "Next","Next"
28
+ "Last","Last"
29
+ "Loading...","Loading..."
30
+ "Back","Back"
app/locale/pt_BR/Dexxtz_Customeremail.csv ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "List E-mails of Customers","Lista de E-mails de Clientes"
2
+ "List Settings of E-mails","Configura&ccedil;&otilde;es da Lista de E-mails"
3
+ "Customer groups","Grupos de clientes"
4
+ "Select one or more groups of customers","Selecione um ou mais grupos de clientes"
5
+ "Access the client list","Acesse a lista de clientes"
6
+ "Click here","Clique aqui"
7
+ "List Email of Customer","Lista de E-mail de Clientes"
8
+ "Create Customer","Criar Cliente"
9
+ "Choose Store View:","Selecione um ambiente:"
10
+ "ALL","Todos"
11
+ "Name","Nome"
12
+ "E-mail","E-mail"
13
+ "Born in","Nascido em"
14
+ "Group","Grupo"
15
+ "Client starting at","Cliente desde"
16
+ "Last purchase","Última compra"
17
+ "Details","Detalhes"
18
+ "Show _MENU_ records","Listar _MENU_ registros"
19
+ "No record found.","Nenhum registro encontrado."
20
+ "Filter: No Record found.","Filtro: Nenhum registro encontrado."
21
+ "Showing _START_ to _END_ of _TOTAL_ records","Exibindo de _START_ até _END_ de _TOTAL_ registros"
22
+ "Showing 0 to 0 of 0 records","Exibindo 0 de 0 registros"
23
+ "(filtered from _MAX_ total records)","(filtrado do total de _MAX_ registros)"
24
+ "Search:","Filtrar:"
25
+ "First","Primeira"
26
+ "Previous","Anterior"
27
+ "Next","Próxima"
28
+ "Last","Última"
29
+ "Loading...","Carregando..."
30
+ "Back","Voltar"
31
+ "Please confirm site switching. All data that hasn't been saved will be lost.","Por favor, confirme a alteração de ambiente."
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Dexxtz_Customer_Email</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/apachepl.php">Apache Software License</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>List of email of customers</summary>
10
+ <description>Easily list the emails of your customers, with filter and export to csv</description>
11
+ <notes>Started</notes>
12
+ <authors><author><name>D&#xE9;cio Mattos</name><user>auto-converted</user><email>dexxtz@gmail.com</email></author></authors>
13
+ <date>2014-10-16</date>
14
+ <time>22:05:47</time>
15
+ <contents><target name="magecommunity"><dir name="Dexxtz"><dir name="Customeremail"><dir name="Block"><dir name="System"><dir name="Config"><dir name="Source"><dir name="List"><file name="Button.php" hash="690aa1135c1edb0338a7ebd729d48074"/></dir></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="39cb95dd95e0173efbef715104924c38"/></dir><dir name="Model"><dir name="System"><dir name="Config"><dir name="Source"><dir name="Customer"><file name="Options.php" hash="5ea8d4a2f721b9b28af60519bbd9b0f0"/></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="ExportCsvController.php" hash="3451a1f77f4bb0824f58ae59fe332846"/><file name="ListController.php" hash="00846fc7b1e22d04389a0c19eeefe00a"/><file name="ListajaxController.php" hash="67dc465152be6447a39699dcdda90e3a"/></dir></dir><dir name="etc"><file name="config.xml" hash="677e4899d603dae4a5e909b0a3b9b901"/><file name="system.xml" hash="41159f90a39335da873b29f167cfc088"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Dexxtz_Customeremail.xml" hash="4e43e3088d5d8b801c238d916a5befba"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="dexxtz"><dir name="customeremail"><file name="header.phtml" hash="1fcf4e588319607de35ae0fffced419b"/><file name="list.phtml" hash="db198c64340e2c07fd49029e8097480a"/></dir></dir></dir><dir name="layout"><dir name="dexxtz"><file name="customeremail.xml" hash="9b6f29fd33af8108b5417ed855699e10"/></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="pt_BR"><file name="Dexxtz_Customeremail.csv" hash="ffa7e599168ec29c889318d138bc1d24"/></dir><dir name="en_US"><file name="Dexxtz_Customeremail.csv" hash="0fe89bc51b85e4350c62f50f21f5624f"/></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="dexxtz"><dir name="customeremail"><dir name="css"><file name="dexxtz.css" hash="b4c790174b0bf3764fd0df3dd0d6dcac"/><file name="jquery.dataTables.css" hash="147487077531eca6abb91ff155ff5049"/></dir><dir name="images"><file name="btn_bg.gif" hash="37c51a4d48a92da9648dcd3ca011039f"/><file name="btn_over_bg.gif" hash="f91641168454c03d1fa72731ec97a2b3"/><file name="details.gif" hash="945d384963db2a1f1daae830c64a021b"/><file name="icon_btn_back.gif" hash="89ed97cede3f68241446a62c96e3ce4c"/><file name="massaction_bg.gif" hash="8b5f4db3ab3ea09cd5bd0164d67c4f0d"/><file name="sort_asc.png" hash="1d9061ce7c12f404388f3888057fa9fa"/><file name="sort_both.png" hash="32d7cb196243ffae4c4d7820e761452d"/><file name="sort_desc.png" hash="fa99d402d3f5b8885c3199afa40983ea"/><file name="sort_row_bg.gif" hash="f2e1c5cb26b9f5211419b99d30745244"/><file name="tr_hover.png" hash="3a315f8dc6236c20f329acec3665c242"/></dir><dir name="js"><file name="dexxtz.js" hash="8c9edc7eee77607bf7cd32c440013f59"/><file name="jquery-1.11.1.js" hash="4dc834d16a0d219d5c2b8a5b814569e4"/><file name="jquery.dataTables.js" hash="63eaebd530fec98840106c3d788e3a52"/></dir></dir></dir></dir></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies/>
18
+ </package>
skin/adminhtml/default/default/dexxtz/customeremail/css/dexxtz.css ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /**
3
+ * Copyright [2014] [Dexxtz]
4
+ *
5
+ * @package Dexxtz_Customeremail
6
+ * @author Dexxtz
7
+ * @license http://www.apache.org/licenses/LICENSE-2.0
8
+ */
9
+
10
+ br.clear { clear: both; height: 0; }
11
+ .grid tr:hover td { background-image: url(../images/tr_hover.png); cursor: pointer; }
12
+ .grid th::-moz-selection { background: none repeat scroll 0 0 rgba(0, 0, 0, 0); }
13
+ .grid thead th::-moz-selection { background: none repeat scroll 0 0 rgba(0, 0, 0, 0); }
14
+ .grid thead tr th { color: #2d444f !important; }
15
+ .grid thead tr th:hover,
16
+ .grid thead tr th.sorting_desc,
17
+ .grid thead tr th.sorting_asc { color: #ea7601 !important; }
18
+ .grid thead .sorting_disabled:hover { color: #2d444f !important; }
19
+ .grid { border-color: #cbd3d4 #cbd3d4 -moz-use-text-color; border-image: none; border-width: 1px 1px medium; width: 100%; padding-bottom: 0; }
20
+ .grid th, table.grid td { border-color: #dadfe0; border-style: solid; border-width: 0 1px 1px 0; }
21
+ .grid thead tr { background: url(../images/sort_row_bg.gif) repeat-x scroll 0 50% rgba(0, 0, 0, 0); }
22
+ .grid thead th { border-color: #f9f9f9 #d1cfcf #f9f9f9 #f9f9f9; border-style: solid; border-width: 1px; font-size: 0.9em; padding-bottom: 0; padding-top: 1px; text-align: left !important; }
23
+ table.dataTable thead th, table.dataTable thead td { padding: 3px 6px; }
24
+ .grid tbody tr td { padding: 2px 6px; vertical-align: middle; }
25
+ .grid tbody tr td .edit { display: block; height: 16px; }
26
+ .grid tbody tr td .edit a { width: 16px; height: 16px; }
27
+ p.switcher { float: right; background: none; border: medium none; float: right; margin: 0 10% -40px 0; position: relative; z-index: 9999; border-right: 1px solid #dadfe0; padding: 0; line-height: 35px;}
28
+ p.switcher label { font-size: 0.9em; font-weight: bold; }
29
+ p.switcher select { padding: 2px 0; text-align: left; }
30
+ p.switcher .link-store-scope { margin-right: 10px; }
31
+ .dataTables_Toolbar { background: url(../images/massaction_bg.gif) repeat-x scroll 0 100% #ebebeb; border-color: #d1cfcf #d1cfcf -moz-use-text-color; border-image: none; border-width: 1px 1px medium; font-size: 0.9em; font-weight: bold; line-height: 35px; width: 100%; margin-bottom: 10px; }
32
+ .dataTables_length { float: left !important; width: 16%; border-right: 1px solid #dadfe0; }
33
+ .dataTables_length label { margin-left: 6px; }
34
+ .dataTables_length select { padding: 2px 0; text-align: center; text-align:-webkit-center; }
35
+ #htmlgrid_length option { text-align: center; }
36
+ .dataTables_filter { float: left !important; padding-left: 6px; }
37
+ .dataTables_filter input { padding: 2px 6px; width: 210px; }
38
+ .export-csv { float: right; }
39
+ .export-csv button { display: none; margin-right: 6px; }
40
+ .dataTables_ToolbarFooter { background: url(../images/massaction_bg.gif) repeat-x scroll 0 100% #ebebeb; border-color: #d1cfcf #d1cfcf -moz-use-text-color; border-image: none; border-width: 1px 1px medium; font-size: 0.9em; font-weight: bold; line-height: 35px; width: 100%; margin-top: 10px; }
41
+ .dataTables_info { margin-left: 6px; padding-top: 0 !important; line-height: 34px; }
42
+ .dataTables_paginate { margin: 4px 6px 0 0; line-height: 16px; }
43
+ .paginate_button { color: #000; }
44
+ .paginate_button.current { color: #ea7601 !important; }
45
+ .paginate_button.current:hover { color: #ea7601 !important; }
46
+ .paginate_button:hover { background-color: #ea7601; }
47
+ .paginate_button.first,
48
+ .paginate_button.previous,
49
+ .paginate_button.next,
50
+ .paginate_button.last { background: url(../images/btn_bg.gif) repeat-x scroll 0 100% #ffac47 !important; border-color: #ed6502 #a04300 #a04300 #ed6502 !important; border-style: solid !important; border-width: 1px !important; color: #fff; cursor: pointer !important; font: bold 12px arial,helvetica,sans-serif; padding: 1px 7px 2px !important; text-align: center !important; white-space: nowrap; margin-right: 5px !important; }
51
+ .paginate_button.first:hover,
52
+ .paginate_button.previous:hover,
53
+ .paginate_button.next:hover,
54
+ .paginate_button.last:hover { background: url(../images/btn_over_bg.gif) repeat-x scroll 0 100% #ffac47 !important; }
55
+ .dataTables_empty:hover { background-image: none !important; cursor: text !important; }
56
+ .back-config { margin-top: 20px; }
57
+ .back-config span { background-image: none !important; padding-left: 3px !important; }
skin/adminhtml/default/default/dexxtz/customeremail/css/jquery.dataTables.css ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Table styles
3
+ */
4
+ table.dataTable {
5
+ width: 100%;
6
+ margin: 0 auto;
7
+ clear: both;
8
+ border-collapse: separate;
9
+ border-spacing: 0;
10
+ /*
11
+ * Header and footer styles
12
+ */
13
+ /*
14
+ * Body styles
15
+ */
16
+ }
17
+ table.dataTable thead th,
18
+ table.dataTable tfoot th {
19
+ font-weight: bold;
20
+ }
21
+ table.dataTable thead th,
22
+ table.dataTable thead td {
23
+ padding: 10px 18px;
24
+ /*border-bottom: 1px solid #111111;*/
25
+ }
26
+ table.dataTable thead th:active,
27
+ table.dataTable thead td:active {
28
+ outline: none;
29
+ }
30
+ table.dataTable tfoot th,
31
+ table.dataTable tfoot td {
32
+ padding: 10px 18px 6px 18px;
33
+ border-top: 1px solid #111111;
34
+ }
35
+ table.dataTable thead .sorting_asc,
36
+ table.dataTable thead .sorting_desc,
37
+ table.dataTable thead .sorting {
38
+ cursor: pointer;
39
+ *cursor: hand;
40
+ }
41
+ table.dataTable thead .sorting {
42
+ background: url("../images/sort_both.png") no-repeat center right;
43
+ }
44
+ table.dataTable thead .sorting_asc {
45
+ background: url("../images/sort_asc.png") no-repeat center right;
46
+ }
47
+ table.dataTable thead .sorting_desc {
48
+ background: url("../images/sort_desc.png") no-repeat center right;
49
+ }
50
+ table.dataTable thead .sorting_asc_disabled {
51
+ background: url("../images/sort_asc_disabled.png") no-repeat center right;
52
+ }
53
+ table.dataTable thead .sorting_desc_disabled {
54
+ background: url("../images/sort_desc_disabled.png") no-repeat center right;
55
+ }
56
+ table.dataTable tbody tr {
57
+ background-color: white;
58
+ }
59
+ table.dataTable tbody tr.selected {
60
+ background-color: #b0bed9;
61
+ }
62
+ table.dataTable tbody th,
63
+ table.dataTable tbody td {
64
+ padding: 8px 10px;
65
+ }
66
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
67
+ border-top: 1px solid #dddddd;
68
+ }
69
+ table.dataTable.row-border tbody tr:first-child th,
70
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
71
+ table.dataTable.display tbody tr:first-child td {
72
+ border-top: none;
73
+ }
74
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
75
+ border-top: 1px solid #dddddd;
76
+ border-right: 1px solid #dddddd;
77
+ }
78
+ table.dataTable.cell-border tbody tr th:first-child,
79
+ table.dataTable.cell-border tbody tr td:first-child {
80
+ border-left: 1px solid #dddddd;
81
+ }
82
+ table.dataTable.cell-border tbody tr:first-child th,
83
+ table.dataTable.cell-border tbody tr:first-child td {
84
+ border-top: none;
85
+ }
86
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
87
+ background-color: #f9f9f9;
88
+ }
89
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
90
+ background-color: #abb9d3;
91
+ }
92
+ table.dataTable.hover tbody tr:hover,
93
+ table.dataTable.hover tbody tr.odd:hover,
94
+ table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
95
+ table.dataTable.display tbody tr.odd:hover,
96
+ table.dataTable.display tbody tr.even:hover {
97
+ background-color: whitesmoke;
98
+ }
99
+ table.dataTable.hover tbody tr:hover.selected,
100
+ table.dataTable.hover tbody tr.odd:hover.selected,
101
+ table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
102
+ table.dataTable.display tbody tr.odd:hover.selected,
103
+ table.dataTable.display tbody tr.even:hover.selected {
104
+ background-color: #a9b7d1;
105
+ }
106
+ table.dataTable.order-column tbody tr > .sorting_1,
107
+ table.dataTable.order-column tbody tr > .sorting_2,
108
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
109
+ table.dataTable.display tbody tr > .sorting_2,
110
+ table.dataTable.display tbody tr > .sorting_3 {
111
+ background-color: #f9f9f9;
112
+ }
113
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
114
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
115
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
116
+ table.dataTable.display tbody tr.selected > .sorting_2,
117
+ table.dataTable.display tbody tr.selected > .sorting_3 {
118
+ background-color: #acbad4;
119
+ }
120
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
121
+ background-color: #f1f1f1;
122
+ }
123
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
124
+ background-color: #f3f3f3;
125
+ }
126
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
127
+ background-color: whitesmoke;
128
+ }
129
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
130
+ background-color: #a6b3cd;
131
+ }
132
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
133
+ background-color: #a7b5ce;
134
+ }
135
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
136
+ background-color: #a9b6d0;
137
+ }
138
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
139
+ background-color: #f9f9f9;
140
+ }
141
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
142
+ background-color: #fbfbfb;
143
+ }
144
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
145
+ background-color: #fdfdfd;
146
+ }
147
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
148
+ background-color: #acbad4;
149
+ }
150
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
151
+ background-color: #adbbd6;
152
+ }
153
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
154
+ background-color: #afbdd8;
155
+ }
156
+ table.dataTable.display tbody tr:hover > .sorting_1,
157
+ table.dataTable.display tbody tr.odd:hover > .sorting_1,
158
+ table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
159
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
160
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
161
+ background-color: #eaeaea;
162
+ }
163
+ table.dataTable.display tbody tr:hover > .sorting_2,
164
+ table.dataTable.display tbody tr.odd:hover > .sorting_2,
165
+ table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
166
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
167
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
168
+ background-color: #ebebeb;
169
+ }
170
+ table.dataTable.display tbody tr:hover > .sorting_3,
171
+ table.dataTable.display tbody tr.odd:hover > .sorting_3,
172
+ table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
173
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
174
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
175
+ background-color: #eeeeee;
176
+ }
177
+ table.dataTable.display tbody tr:hover.selected > .sorting_1,
178
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
179
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
180
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
181
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
182
+ background-color: #a1aec7;
183
+ }
184
+ table.dataTable.display tbody tr:hover.selected > .sorting_2,
185
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
186
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
187
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
188
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
189
+ background-color: #a2afc8;
190
+ }
191
+ table.dataTable.display tbody tr:hover.selected > .sorting_3,
192
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
193
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
194
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
195
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
196
+ background-color: #a4b2cb;
197
+ }
198
+ table.dataTable.no-footer {
199
+ /*border-bottom: 1px solid #111111;*/
200
+ }
201
+ table.dataTable.nowrap th, table.dataTable.nowrap td {
202
+ white-space: nowrap;
203
+ }
204
+ table.dataTable.compact thead th,
205
+ table.dataTable.compact thead td {
206
+ padding: 5px 9px;
207
+ }
208
+ table.dataTable.compact tfoot th,
209
+ table.dataTable.compact tfoot td {
210
+ padding: 5px 9px 3px 9px;
211
+ }
212
+ table.dataTable.compact tbody th,
213
+ table.dataTable.compact tbody td {
214
+ padding: 4px 5px;
215
+ }
216
+ table.dataTable th.dt-left,
217
+ table.dataTable td.dt-left {
218
+ text-align: left;
219
+ }
220
+ table.dataTable th.dt-center,
221
+ table.dataTable td.dt-center,
222
+ table.dataTable td.dataTables_empty {
223
+ text-align: center;
224
+ }
225
+ table.dataTable th.dt-right,
226
+ table.dataTable td.dt-right {
227
+ text-align: right;
228
+ }
229
+ table.dataTable th.dt-justify,
230
+ table.dataTable td.dt-justify {
231
+ text-align: justify;
232
+ }
233
+ table.dataTable th.dt-nowrap,
234
+ table.dataTable td.dt-nowrap {
235
+ white-space: nowrap;
236
+ }
237
+ table.dataTable thead th.dt-head-left,
238
+ table.dataTable thead td.dt-head-left,
239
+ table.dataTable tfoot th.dt-head-left,
240
+ table.dataTable tfoot td.dt-head-left {
241
+ text-align: left;
242
+ }
243
+ table.dataTable thead th.dt-head-center,
244
+ table.dataTable thead td.dt-head-center,
245
+ table.dataTable tfoot th.dt-head-center,
246
+ table.dataTable tfoot td.dt-head-center {
247
+ text-align: center;
248
+ }
249
+ table.dataTable thead th.dt-head-right,
250
+ table.dataTable thead td.dt-head-right,
251
+ table.dataTable tfoot th.dt-head-right,
252
+ table.dataTable tfoot td.dt-head-right {
253
+ text-align: right;
254
+ }
255
+ table.dataTable thead th.dt-head-justify,
256
+ table.dataTable thead td.dt-head-justify,
257
+ table.dataTable tfoot th.dt-head-justify,
258
+ table.dataTable tfoot td.dt-head-justify {
259
+ text-align: justify;
260
+ }
261
+ table.dataTable thead th.dt-head-nowrap,
262
+ table.dataTable thead td.dt-head-nowrap,
263
+ table.dataTable tfoot th.dt-head-nowrap,
264
+ table.dataTable tfoot td.dt-head-nowrap {
265
+ white-space: nowrap;
266
+ }
267
+ table.dataTable tbody th.dt-body-left,
268
+ table.dataTable tbody td.dt-body-left {
269
+ text-align: left;
270
+ }
271
+ table.dataTable tbody th.dt-body-center,
272
+ table.dataTable tbody td.dt-body-center {
273
+ text-align: center;
274
+ }
275
+ table.dataTable tbody th.dt-body-right,
276
+ table.dataTable tbody td.dt-body-right {
277
+ text-align: right;
278
+ }
279
+ table.dataTable tbody th.dt-body-justify,
280
+ table.dataTable tbody td.dt-body-justify {
281
+ text-align: justify;
282
+ }
283
+ table.dataTable tbody th.dt-body-nowrap,
284
+ table.dataTable tbody td.dt-body-nowrap {
285
+ white-space: nowrap;
286
+ }
287
+
288
+ table.dataTable,
289
+ table.dataTable th,
290
+ table.dataTable td {
291
+ -webkit-box-sizing: content-box;
292
+ -moz-box-sizing: content-box;
293
+ box-sizing: content-box;
294
+ }
295
+
296
+ /*
297
+ * Control feature layout
298
+ */
299
+ .dataTables_wrapper {
300
+ position: relative;
301
+ clear: both;
302
+ *zoom: 1;
303
+ zoom: 1;
304
+ }
305
+ .dataTables_wrapper .dataTables_length {
306
+ float: left;
307
+ }
308
+ .dataTables_wrapper .dataTables_filter {
309
+ float: right;
310
+ text-align: right;
311
+ }
312
+ .dataTables_wrapper .dataTables_filter input {
313
+ margin-left: 0.5em;
314
+ }
315
+ .dataTables_wrapper .dataTables_info {
316
+ clear: both;
317
+ float: left;
318
+ padding-top: 0.755em;
319
+ }
320
+ .dataTables_wrapper .dataTables_paginate {
321
+ float: right;
322
+ text-align: right;
323
+ padding-top: 0.25em;
324
+ }
325
+ .dataTables_wrapper .dataTables_paginate .paginate_button {
326
+ box-sizing: border-box;
327
+ display: inline-block;
328
+ min-width: 1.5em;
329
+ margin:0 0 2px 2px;
330
+ text-align: center;
331
+ text-decoration: none !important;
332
+ cursor: pointer;
333
+ *cursor: hand;
334
+ border: 1px solid transparent;
335
+ }
336
+ .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
337
+ color: #333333;
338
+ border: 1px solid #cacaca;
339
+ background-color: white;
340
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, gainsboro));
341
+ /* Chrome,Safari4+ */
342
+ background: -webkit-linear-gradient(top, white 0%, gainsboro 100%);
343
+ /* Chrome10+,Safari5.1+ */
344
+ background: -moz-linear-gradient(top, white 0%, gainsboro 100%);
345
+ /* FF3.6+ */
346
+ background: -ms-linear-gradient(top, white 0%, gainsboro 100%);
347
+ /* IE10+ */
348
+ background: -o-linear-gradient(top, white 0%, gainsboro 100%);
349
+ /* Opera 11.10+ */
350
+ background: linear-gradient(to bottom, white 0%, gainsboro 100%);
351
+ /* W3C */
352
+ }
353
+ .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
354
+ cursor: default;
355
+ color: #666;
356
+ border: 1px solid transparent;
357
+ background: transparent;
358
+ box-shadow: none;
359
+ }
360
+ .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
361
+ color: white;
362
+ border: 1px solid #111111;
363
+ background-color: #585858;
364
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111111));
365
+ /* Chrome,Safari4+ */
366
+ background: -webkit-linear-gradient(top, #585858 0%, #111111 100%);
367
+ /* Chrome10+,Safari5.1+ */
368
+ background: -moz-linear-gradient(top, #585858 0%, #111111 100%);
369
+ /* FF3.6+ */
370
+ background: -ms-linear-gradient(top, #585858 0%, #111111 100%);
371
+ /* IE10+ */
372
+ background: -o-linear-gradient(top, #585858 0%, #111111 100%);
373
+ /* Opera 11.10+ */
374
+ background: linear-gradient(to bottom, #585858 0%, #111111 100%);
375
+ /* W3C */
376
+ }
377
+ .dataTables_wrapper .dataTables_paginate .paginate_button:active {
378
+ outline: none;
379
+ background-color: #2b2b2b;
380
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
381
+ /* Chrome,Safari4+ */
382
+ background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
383
+ /* Chrome10+,Safari5.1+ */
384
+ background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
385
+ /* FF3.6+ */
386
+ background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
387
+ /* IE10+ */
388
+ background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
389
+ /* Opera 11.10+ */
390
+ background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
391
+ /* W3C */
392
+ box-shadow: inset 0 0 3px #111;
393
+ }
394
+ .dataTables_wrapper .dataTables_processing {
395
+ position: absolute;
396
+ top: 50%;
397
+ left: 50%;
398
+ width: 100%;
399
+ height: 40px;
400
+ margin-left: -50%;
401
+ margin-top: -25px;
402
+ padding-top: 20px;
403
+ text-align: center;
404
+ font-size: 1.2em;
405
+ background-color: white;
406
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
407
+ /* Chrome,Safari4+ */
408
+ background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
409
+ /* Chrome10+,Safari5.1+ */
410
+ background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
411
+ /* FF3.6+ */
412
+ background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
413
+ /* IE10+ */
414
+ background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
415
+ /* Opera 11.10+ */
416
+ background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
417
+ /* W3C */
418
+ }
419
+ .dataTables_wrapper .dataTables_length,
420
+ .dataTables_wrapper .dataTables_filter,
421
+ .dataTables_wrapper .dataTables_info,
422
+ .dataTables_wrapper .dataTables_processing,
423
+ .dataTables_wrapper .dataTables_paginate {
424
+ color: #333333;
425
+ }
426
+ .dataTables_wrapper .dataTables_scroll {
427
+ clear: both;
428
+ }
429
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
430
+ *margin-top: -1px;
431
+ -webkit-overflow-scrolling: touch;
432
+ }
433
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,
434
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {
435
+ height: 0;
436
+ overflow: hidden;
437
+ margin: 0 !important;
438
+ padding: 0 !important;
439
+ }
440
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
441
+ border-bottom: 1px solid #111111;
442
+ }
443
+ .dataTables_wrapper.no-footer div.dataTables_scrollHead table,
444
+ .dataTables_wrapper.no-footer div.dataTables_scrollBody table {
445
+ border-bottom: none;
446
+ }
447
+ .dataTables_wrapper:after {
448
+ visibility: hidden;
449
+ display: block;
450
+ content: "";
451
+ clear: both;
452
+ height: 0;
453
+ }
454
+
455
+ @media screen and (max-width: 767px) {
456
+ .dataTables_wrapper .dataTables_info,
457
+ .dataTables_wrapper .dataTables_paginate {
458
+ float: none;
459
+ text-align: center;
460
+ }
461
+ .dataTables_wrapper .dataTables_paginate {
462
+ margin-top: 0.5em;
463
+ }
464
+ }
465
+ @media screen and (max-width: 640px) {
466
+ .dataTables_wrapper .dataTables_length,
467
+ .dataTables_wrapper .dataTables_filter {
468
+ float: none;
469
+ text-align: center;
470
+ }
471
+ .dataTables_wrapper .dataTables_filter {
472
+ margin-top: 0.5em;
473
+ }
474
+ }
skin/adminhtml/default/default/dexxtz/customeremail/images/btn_bg.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/btn_over_bg.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/details.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/icon_btn_back.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/massaction_bg.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/sort_asc.png ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/sort_both.png ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/sort_desc.png ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/sort_row_bg.gif ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/images/tr_hover.png ADDED
Binary file
skin/adminhtml/default/default/dexxtz/customeremail/js/dexxtz.js ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ /**
3
+ * Copyright [2014] [Dexxtz]
4
+ *
5
+ * @package Dexxtz_Customeremail
6
+ * @author Dexxtz
7
+ * @license http://www.apache.org/licenses/LICENSE-2.0
8
+ */
9
+
10
+ function convertInfoCommaForPoint(locale) {
11
+ if (locale == 'pt_BR') {
12
+ string = jQuery('#htmlgrid_info').html().split(',');
13
+ newString = '';
14
+
15
+ for(var i = 0; i < string.length; i++){
16
+ if (i > 0) {
17
+ newString += '.' + string[i];
18
+ } else {
19
+ newString += string[i];
20
+ }
21
+ }
22
+ jQuery('#htmlgrid_info').html(newString);
23
+ }
24
+ }
25
+
26
+ function removePageIndexSelection(qtyRowsSelected,totalFiltred) {
27
+ if (qtyRowsSelected == '-1') {
28
+ jQuery('a.paginate_button.current').css('display','none');
29
+ } else {
30
+ if (qtyRowsSelected == 500 && totalFiltred <= 500) {
31
+ jQuery('a.paginate_button.current').css('display','none');
32
+ } else {
33
+ if (qtyRowsSelected == 100 && totalFiltred <= 100) {
34
+ jQuery('a.paginate_button.current').css('display','none');
35
+ } else {
36
+ if (qtyRowsSelected == 50 && totalFiltred <= 50) {
37
+ jQuery('a.paginate_button.current').css('display','none');
38
+ } else {
39
+ if (qtyRowsSelected == 25 && totalFiltred <= 25) {
40
+ jQuery('a.paginate_button.current').css('display','none');
41
+ } else {
42
+ jQuery('a.paginate_button.current').removeAttr('style');
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ function removeNavPageOptions(totalRows, totalFiltred, curPage, pages) {
51
+ if (totalFiltred < 10) {
52
+ jQuery('a#htmlgrid_next').css('display','none');
53
+ jQuery('a#htmlgrid_last').css('display','none');
54
+ }
55
+
56
+ if (totalRows > 10) {
57
+ jQuery('.dataTables_paginate').css('display','block');
58
+ } else {
59
+ jQuery('.dataTables_paginate').css('display','none');
60
+ }
61
+
62
+ if (curPage == 0) {
63
+ jQuery('a#htmlgrid_previous').css('display','none');
64
+ jQuery('a#htmlgrid_first').css('display','none');
65
+ }
66
+
67
+ if ((curPage + 1) == pages) {
68
+ jQuery('a#htmlgrid_next').css('display','none');
69
+ jQuery('a#htmlgrid_last').css('display','none');
70
+ }
71
+ }
72
+
73
+ function executeAjax(url, formKey, notFound) {
74
+ jQuery.ajax({
75
+ url: url,
76
+ type: "POST",
77
+ data: { form_key: formKey },
78
+ success: function(result) {
79
+ jQuery('#loading-mask').css('display','none');
80
+ jQuery('.export-csv button').fadeIn('slow');
81
+ if (result != "") {
82
+ converted = JSON.parse(result);
83
+ jQuery('#htmlgrid').dataTable().fnClearTable(true);
84
+ jQuery('#htmlgrid').dataTable().fnAddData(converted);
85
+ } else {
86
+ jQuery('.dataTables_empty').text(notFound);
87
+ }
88
+ },
89
+ error: function() { jQuery('#loading-mask').css('display','none'); }
90
+ });
91
+ }
92
+
93
+ function generateCsv(formKey, urlExportCsv) {
94
+ var rowEmpty = 0;
95
+
96
+ if (jQuery('#htmlgrid tbody tr td.dataTables_empty').text() != '') {
97
+ rowEmpty = 1;
98
+ }
99
+
100
+ var jsonArr = [];
101
+
102
+ jQuery('#htmlgrid tbody tr').each(function(index) {
103
+ jsonArr[index] = [];
104
+ jQuery(this).find('td.field-sort').each(function() {
105
+ jsonArr[index].push(jQuery(this).text());
106
+ });
107
+ });
108
+
109
+ jQuery.ajax({
110
+ url: urlExportCsv,
111
+ type: "POST",
112
+ data: {
113
+ form_key: formKey,
114
+ csv: jsonArr,
115
+ empty: rowEmpty
116
+ },
117
+ success: function(result) {
118
+ jQuery('#loading-mask').fadeOut('slow');
119
+ window.location.href = urlExportCsv;
120
+ },
121
+ error: function() { jQuery('#loading-mask').css('display','none'); }
122
+ });
123
+ }
124
+
125
+ function trHoverClick() {
126
+ jQuery('.grid tr td').click(function(){
127
+
128
+ var link = jQuery(this).parent('tr').find('a.edit').attr('href');
129
+
130
+ if (jQuery(this).attr('class') != 'dataTables_empty'){
131
+ if (!jQuery(this).find('a').length && !jQuery(this).find('input[name="send_emails[]"]').length) {
132
+ if(!jQuery(this).find('.dataTables_empty').length) {
133
+ window.open(link, 'edit');
134
+ }
135
+ }
136
+ }
137
+ });
138
+ }
139
+
140
+ function configToolbar(button) {
141
+ jQuery('div.export-csv').html(button);
142
+ jQuery('.dataTables_Toolbar').append('<br class="clear" />');
143
+ jQuery('.dataTables_ToolbarFooter').append('<br class="clear" />');
144
+ }
skin/adminhtml/default/default/dexxtz/customeremail/js/jquery-1.11.1.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ /*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
2
+ !function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
3
+ if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==cb()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===cb()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?ab:bb):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:bb,isPropagationStopped:bb,isImmediatePropagationStopped:bb,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=ab,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=ab,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=ab,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=bb;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=bb),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function db(a){var b=eb.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var eb="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fb=/ jQuery\d+="(?:null|\d+)"/g,gb=new RegExp("<(?:"+eb+")[\\s/>]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/<tbody/i,lb=/<|&#?\w+;/,mb=/<(?:script|style|link)/i,nb=/checked\s*(?:[^=]|=\s*.checked.)/i,ob=/^$|\/(?:java|ecma)script/i,pb=/^true\/(.*)/,qb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,rb={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?"<table>"!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
4
+ },cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$b=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_b||(_b=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_b),_b=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
skin/adminhtml/default/default/dexxtz/customeremail/js/jquery.dataTables.js ADDED
@@ -0,0 +1,14622 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.2
2
+ * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary DataTables
7
+ * @description Paginate, search and order HTML tables
8
+ * @version 1.10.2
9
+ * @file jquery.dataTables.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2008-2014 SpryMedia Ltd.
13
+ *
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license
16
+ *
17
+ * This source file is distributed in the hope that it will be useful, but
18
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20
+ *
21
+ * For details please refer to: http://www.datatables.net
22
+ */
23
+
24
+ /*jslint evil: true, undef: true, browser: true */
25
+ /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidateRow,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
+
27
+ (/** @lends <global> */function( window, document, undefined ) {
28
+ jQuery.noConflict();
29
+ (function( factory ) {
30
+ "use strict";
31
+
32
+ if ( typeof define === 'function' && define.amd ) {
33
+ // Define as an AMD module if possible
34
+ define( 'datatables', ['jquery'], factory );
35
+ }
36
+ else if ( typeof exports === 'object' ) {
37
+ // Node/CommonJS
38
+ factory( require( 'jquery' ) );
39
+ }
40
+ else if ( jQuery && !jQuery.fn.dataTable ) {
41
+ // Define using browser globals otherwise
42
+ // Prevent multiple instantiations if the script is loaded twice
43
+ factory( jQuery );
44
+ }
45
+ }
46
+ (/** @lends <global> */function( $ ) {
47
+ "use strict";
48
+
49
+ /**
50
+ * DataTables is a plug-in for the jQuery Javascript library. It is a highly
51
+ * flexible tool, based upon the foundations of progressive enhancement,
52
+ * which will add advanced interaction controls to any HTML table. For a
53
+ * full list of features please refer to
54
+ * [DataTables.net](href="http://datatables.net).
55
+ *
56
+ * Note that the `DataTable` object is not a global variable but is aliased
57
+ * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
58
+ * be accessed.
59
+ *
60
+ * @class
61
+ * @param {object} [init={}] Configuration object for DataTables. Options
62
+ * are defined by {@link DataTable.defaults}
63
+ * @requires jQuery 1.7+
64
+ *
65
+ * @example
66
+ * // Basic initialisation
67
+ * $(document).ready( function {
68
+ * $('#example').dataTable();
69
+ * } );
70
+ *
71
+ * @example
72
+ * // Initialisation with configuration options - in this case, disable
73
+ * // pagination and sorting.
74
+ * $(document).ready( function {
75
+ * $('#example').dataTable( {
76
+ * "paginate": false,
77
+ * "sort": false
78
+ * } );
79
+ * } );
80
+ */
81
+ var DataTable;
82
+
83
+
84
+ /*
85
+ * It is useful to have variables which are scoped locally so only the
86
+ * DataTables functions can access them and they don't leak into global space.
87
+ * At the same time these functions are often useful over multiple files in the
88
+ * core and API, so we list, or at least document, all variables which are used
89
+ * by DataTables as private variables here. This also ensures that there is no
90
+ * clashing of variable names and that they can easily referenced for reuse.
91
+ */
92
+
93
+
94
+ // Defined else where
95
+ // _selector_run
96
+ // _selector_opts
97
+ // _selector_first
98
+ // _selector_row_indexes
99
+
100
+ var _ext; // DataTable.ext
101
+ var _Api; // DataTable.Api
102
+ var _api_register; // DataTable.Api.register
103
+ var _api_registerPlural; // DataTable.Api.registerPlural
104
+
105
+ var _re_dic = {};
106
+ var _re_new_lines = /[\r\n]/g;
107
+ var _re_html = /<.*?>/g;
108
+ var _re_date_start = /^[\w\+\-]/;
109
+ var _re_date_end = /[\w\+\-]$/;
110
+
111
+ // Escape regular expression special characters
112
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
+
114
+ // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115
+ // standards as thousands separators
116
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
117
+
118
+
119
+ var _empty = function ( d ) {
120
+ return !d || d === true || d === '-' ? true : false;
121
+ };
122
+
123
+
124
+ var _intVal = function ( s ) {
125
+ var integer = parseInt( s, 10 );
126
+ return !isNaN(integer) && isFinite(s) ? integer : null;
127
+ };
128
+
129
+ // Convert from a formatted number with characters other than `.` as the
130
+ // decimal place, to a Javascript number
131
+ var _numToDecimal = function ( num, decimalPoint ) {
132
+ // Cache created regular expressions for speed as this function is called often
133
+ if ( ! _re_dic[ decimalPoint ] ) {
134
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
135
+ }
136
+ return typeof num === 'string' ?
137
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
138
+ num;
139
+ };
140
+
141
+
142
+ var _isNumber = function ( d, decimalPoint, formatted ) {
143
+ var strType = typeof d === 'string';
144
+
145
+ if ( decimalPoint && strType ) {
146
+ d = _numToDecimal( d, decimalPoint );
147
+ }
148
+
149
+ if ( formatted && strType ) {
150
+ d = d.replace( _re_formatted_numeric, '' );
151
+ }
152
+
153
+ return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
154
+ };
155
+
156
+
157
+ // A string without HTML in it can be considered to be HTML still
158
+ var _isHtml = function ( d ) {
159
+ return _empty( d ) || typeof d === 'string';
160
+ };
161
+
162
+
163
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
164
+ if ( _empty( d ) ) {
165
+ return true;
166
+ }
167
+
168
+ var html = _isHtml( d );
169
+ return ! html ?
170
+ null :
171
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
172
+ true :
173
+ null;
174
+ };
175
+
176
+
177
+ var _pluck = function ( a, prop, prop2 ) {
178
+ var out = [];
179
+ var i=0, ien=a.length;
180
+
181
+ // Could have the test in the loop for slightly smaller code, but speed
182
+ // is essential here
183
+ if ( prop2 !== undefined ) {
184
+ for ( ; i<ien ; i++ ) {
185
+ if ( a[i] && a[i][ prop ] ) {
186
+ out.push( a[i][ prop ][ prop2 ] );
187
+ }
188
+ }
189
+ }
190
+ else {
191
+ for ( ; i<ien ; i++ ) {
192
+ if ( a[i] ) {
193
+ out.push( a[i][ prop ] );
194
+ }
195
+ }
196
+ }
197
+
198
+ return out;
199
+ };
200
+
201
+
202
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
203
+ // as the indexes to pick from `a`
204
+ var _pluck_order = function ( a, order, prop, prop2 )
205
+ {
206
+ var out = [];
207
+ var i=0, ien=order.length;
208
+
209
+ // Could have the test in the loop for slightly smaller code, but speed
210
+ // is essential here
211
+ if ( prop2 !== undefined ) {
212
+ for ( ; i<ien ; i++ ) {
213
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
214
+ }
215
+ }
216
+ else {
217
+ for ( ; i<ien ; i++ ) {
218
+ out.push( a[ order[i] ][ prop ] );
219
+ }
220
+ }
221
+
222
+ return out;
223
+ };
224
+
225
+
226
+ var _range = function ( len, start )
227
+ {
228
+ var out = [];
229
+ var end;
230
+
231
+ if ( start === undefined ) {
232
+ start = 0;
233
+ end = len;
234
+ }
235
+ else {
236
+ end = start;
237
+ start = len;
238
+ }
239
+
240
+ for ( var i=start ; i<end ; i++ ) {
241
+ out.push( i );
242
+ }
243
+
244
+ return out;
245
+ };
246
+
247
+
248
+ var _stripHtml = function ( d ) {
249
+ return d.replace( _re_html, '' );
250
+ };
251
+
252
+
253
+ /**
254
+ * Find the unique elements in a source array.
255
+ *
256
+ * @param {array} src Source array
257
+ * @return {array} Array of unique items
258
+ * @ignore
259
+ */
260
+ var _unique = function ( src )
261
+ {
262
+ // A faster unique method is to use object keys to identify used values,
263
+ // but this doesn't work with arrays or objects, which we must also
264
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
265
+ // information.
266
+ var
267
+ out = [],
268
+ val,
269
+ i, ien=src.length,
270
+ j, k=0;
271
+
272
+ again: for ( i=0 ; i<ien ; i++ ) {
273
+ val = src[i];
274
+
275
+ for ( j=0 ; j<k ; j++ ) {
276
+ if ( out[j] === val ) {
277
+ continue again;
278
+ }
279
+ }
280
+
281
+ out.push( val );
282
+ k++;
283
+ }
284
+
285
+ return out;
286
+ };
287
+
288
+
289
+
290
+ /**
291
+ * Create a mapping object that allows camel case parameters to be looked up
292
+ * for their Hungarian counterparts. The mapping is stored in a private
293
+ * parameter called `_hungarianMap` which can be accessed on the source object.
294
+ * @param {object} o
295
+ * @memberof DataTable#oApi
296
+ */
297
+ function _fnHungarianMap ( o )
298
+ {
299
+ var
300
+ hungarian = 'a aa ai ao as b fn i m o s ',
301
+ match,
302
+ newKey,
303
+ map = {};
304
+
305
+ $.each( o, function (key, val) {
306
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
307
+
308
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
309
+ {
310
+ newKey = key.replace( match[0], match[2].toLowerCase() );
311
+ map[ newKey ] = key;
312
+
313
+ //console.log( key, match );
314
+ if ( match[1] === 'o' )
315
+ {
316
+ _fnHungarianMap( o[key] );
317
+ }
318
+ }
319
+ } );
320
+
321
+ o._hungarianMap = map;
322
+ }
323
+
324
+
325
+ /**
326
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
327
+ * created by _fnHungarianMap.
328
+ * @param {object} src The model object which holds all parameters that can be
329
+ * mapped.
330
+ * @param {object} user The object to convert from camel case to Hungarian.
331
+ * @param {boolean} force When set to `true`, properties which already have a
332
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
333
+ * won't be.
334
+ * @memberof DataTable#oApi
335
+ */
336
+ function _fnCamelToHungarian ( src, user, force )
337
+ {
338
+ if ( ! src._hungarianMap ) {
339
+ _fnHungarianMap( src );
340
+ }
341
+
342
+ var hungarianKey;
343
+
344
+ $.each( user, function (key, val) {
345
+ hungarianKey = src._hungarianMap[ key ];
346
+
347
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
348
+ {
349
+ // For objects, we need to buzz down into the object to copy parameters
350
+ if ( hungarianKey.charAt(0) === 'o' )
351
+ {
352
+ // Copy the camelCase options over to the hungarian
353
+ if ( ! user[ hungarianKey ] ) {
354
+ user[ hungarianKey ] = {};
355
+ }
356
+ $.extend( true, user[hungarianKey], user[key] );
357
+
358
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
359
+ }
360
+ else {
361
+ user[hungarianKey] = user[ key ];
362
+ }
363
+ }
364
+ } );
365
+ }
366
+
367
+
368
+ /**
369
+ * Language compatibility - when certain options are given, and others aren't, we
370
+ * need to duplicate the values over, in order to provide backwards compatibility
371
+ * with older language files.
372
+ * @param {object} oSettings dataTables settings object
373
+ * @memberof DataTable#oApi
374
+ */
375
+ function _fnLanguageCompat( lang )
376
+ {
377
+ var defaults = DataTable.defaults.oLanguage;
378
+ var zeroRecords = lang.sZeroRecords;
379
+
380
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
381
+ * sZeroRecords - assuming that is given.
382
+ */
383
+ if ( ! lang.sEmptyTable && zeroRecords &&
384
+ defaults.sEmptyTable === "No data available in table" )
385
+ {
386
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
387
+ }
388
+
389
+ /* Likewise with loading records */
390
+ if ( ! lang.sLoadingRecords && zeroRecords &&
391
+ defaults.sLoadingRecords === "Loading..." )
392
+ {
393
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
394
+ }
395
+
396
+ // Old parameter name of the thousands separator mapped onto the new
397
+ if ( lang.sInfoThousands ) {
398
+ lang.sThousands = lang.sInfoThousands;
399
+ }
400
+
401
+ var decimal = lang.sDecimal;
402
+ if ( decimal ) {
403
+ _addNumericSort( decimal );
404
+ }
405
+ }
406
+
407
+
408
+ /**
409
+ * Map one parameter onto another
410
+ * @param {object} o Object to map
411
+ * @param {*} knew The new parameter name
412
+ * @param {*} old The old parameter name
413
+ */
414
+ var _fnCompatMap = function ( o, knew, old ) {
415
+ if ( o[ knew ] !== undefined ) {
416
+ o[ old ] = o[ knew ];
417
+ }
418
+ };
419
+
420
+
421
+ /**
422
+ * Provide backwards compatibility for the main DT options. Note that the new
423
+ * options are mapped onto the old parameters, so this is an external interface
424
+ * change only.
425
+ * @param {object} init Object to map
426
+ */
427
+ function _fnCompatOpts ( init )
428
+ {
429
+ _fnCompatMap( init, 'ordering', 'bSort' );
430
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
431
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
432
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
433
+ _fnCompatMap( init, 'order', 'aaSorting' );
434
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
435
+ _fnCompatMap( init, 'paging', 'bPaginate' );
436
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
437
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
438
+ _fnCompatMap( init, 'searching', 'bFilter' );
439
+
440
+ // Column search objects are in an array, so it needs to be converted
441
+ // element by element
442
+ var searchCols = init.aoSearchCols;
443
+
444
+ if ( searchCols ) {
445
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
446
+ if ( searchCols[i] ) {
447
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
448
+ }
449
+ }
450
+ }
451
+ }
452
+
453
+
454
+ /**
455
+ * Provide backwards compatibility for column options. Note that the new options
456
+ * are mapped onto the old parameters, so this is an external interface change
457
+ * only.
458
+ * @param {object} init Object to map
459
+ */
460
+ function _fnCompatCols ( init )
461
+ {
462
+ _fnCompatMap( init, 'orderable', 'bSortable' );
463
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
464
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
465
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
466
+ }
467
+
468
+
469
+ /**
470
+ * Browser feature detection for capabilities, quirks
471
+ * @param {object} settings dataTables settings object
472
+ * @memberof DataTable#oApi
473
+ */
474
+ function _fnBrowserDetect( settings )
475
+ {
476
+ var browser = settings.oBrowser;
477
+
478
+ // Scrolling feature / quirks detection
479
+ var n = $('<div/>')
480
+ .css( {
481
+ position: 'absolute',
482
+ top: 0,
483
+ left: 0,
484
+ height: 1,
485
+ width: 1,
486
+ overflow: 'hidden'
487
+ } )
488
+ .append(
489
+ $('<div/>')
490
+ .css( {
491
+ position: 'absolute',
492
+ top: 1,
493
+ left: 1,
494
+ width: 100,
495
+ overflow: 'scroll'
496
+ } )
497
+ .append(
498
+ $('<div class="test"/>')
499
+ .css( {
500
+ width: '100%',
501
+ height: 10
502
+ } )
503
+ )
504
+ )
505
+ .appendTo( 'body' );
506
+
507
+ var test = n.find('.test');
508
+
509
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
510
+ // include the width of the scrollbar, while other browsers ensure the inner
511
+ // element is contained without forcing scrolling
512
+ browser.bScrollOversize = test[0].offsetWidth === 100;
513
+
514
+ // In rtl text layout, some browsers (most, but not all) will place the
515
+ // scrollbar on the left, rather than the right.
516
+ browser.bScrollbarLeft = test.offset().left !== 1;
517
+
518
+ n.remove();
519
+ }
520
+
521
+
522
+ /**
523
+ * Array.prototype reduce[Right] method, used for browsers which don't support
524
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
525
+ * @param {object} settings dataTables settings object
526
+ * @memberof DataTable#oApi
527
+ */
528
+ function _fnReduce ( that, fn, init, start, end, inc )
529
+ {
530
+ var
531
+ i = start,
532
+ value,
533
+ isSet = false;
534
+
535
+ if ( init !== undefined ) {
536
+ value = init;
537
+ isSet = true;
538
+ }
539
+
540
+ while ( i !== end ) {
541
+ if ( ! that.hasOwnProperty(i) ) {
542
+ continue;
543
+ }
544
+
545
+ value = isSet ?
546
+ fn( value, that[i], i, that ) :
547
+ that[i];
548
+
549
+ isSet = true;
550
+ i += inc;
551
+ }
552
+
553
+ return value;
554
+ }
555
+
556
+ /**
557
+ * Add a column to the list used for the table with default values
558
+ * @param {object} oSettings dataTables settings object
559
+ * @param {node} nTh The th element for this column
560
+ * @memberof DataTable#oApi
561
+ */
562
+ function _fnAddColumn( oSettings, nTh )
563
+ {
564
+ // Add column to aoColumns array
565
+ var oDefaults = DataTable.defaults.column;
566
+ var iCol = oSettings.aoColumns.length;
567
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
568
+ "nTh": nTh ? nTh : document.createElement('th'),
569
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
570
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
571
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
572
+ idx: iCol
573
+ } );
574
+ oSettings.aoColumns.push( oCol );
575
+
576
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
577
+ // passed into extend can be undefined. This allows the user to give a default
578
+ // with only some of the parameters defined, and also not give a default
579
+ var searchCols = oSettings.aoPreSearchCols;
580
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
581
+
582
+ // Use the default column options function to initialise classes etc
583
+ _fnColumnOptions( oSettings, iCol, null );
584
+ }
585
+
586
+
587
+ /**
588
+ * Apply options for a column
589
+ * @param {object} oSettings dataTables settings object
590
+ * @param {int} iCol column index to consider
591
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
592
+ * @memberof DataTable#oApi
593
+ */
594
+ function _fnColumnOptions( oSettings, iCol, oOptions )
595
+ {
596
+ var oCol = oSettings.aoColumns[ iCol ];
597
+ var oClasses = oSettings.oClasses;
598
+ var th = $(oCol.nTh);
599
+
600
+ // Try to get width information from the DOM. We can't get it from CSS
601
+ // as we'd need to parse the CSS stylesheet. `width` option can override
602
+ if ( ! oCol.sWidthOrig ) {
603
+ // Width attribute
604
+ oCol.sWidthOrig = th.attr('width') || null;
605
+
606
+ // Style attribute
607
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
608
+ if ( t ) {
609
+ oCol.sWidthOrig = t[1];
610
+ }
611
+ }
612
+
613
+ /* User specified column options */
614
+ if ( oOptions !== undefined && oOptions !== null )
615
+ {
616
+ // Backwards compatibility
617
+ _fnCompatCols( oOptions );
618
+
619
+ // Map camel case parameters to their Hungarian counterparts
620
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions );
621
+
622
+ /* Backwards compatibility for mDataProp */
623
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
624
+ {
625
+ oOptions.mData = oOptions.mDataProp;
626
+ }
627
+
628
+ if ( oOptions.sType )
629
+ {
630
+ oCol._sManualType = oOptions.sType;
631
+ }
632
+
633
+ // `class` is a reserved word in Javascript, so we need to provide
634
+ // the ability to use a valid name for the camel case input
635
+ if ( oOptions.className && ! oOptions.sClass )
636
+ {
637
+ oOptions.sClass = oOptions.className;
638
+ }
639
+
640
+ $.extend( oCol, oOptions );
641
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
642
+
643
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
644
+ * priority if defined
645
+ */
646
+ if ( typeof oOptions.iDataSort === 'number' )
647
+ {
648
+ oCol.aDataSort = [ oOptions.iDataSort ];
649
+ }
650
+ _fnMap( oCol, oOptions, "aDataSort" );
651
+ }
652
+
653
+ /* Cache the data get and set functions for speed */
654
+ var mDataSrc = oCol.mData;
655
+ var mData = _fnGetObjectDataFn( mDataSrc );
656
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
657
+
658
+ var attrTest = function( src ) {
659
+ return typeof src === 'string' && src.indexOf('@') !== -1;
660
+ };
661
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
662
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
663
+ );
664
+
665
+ oCol.fnGetData = function (rowData, type, meta) {
666
+ var innerData = mData( rowData, type, undefined, meta );
667
+
668
+ return mRender && type ?
669
+ mRender( innerData, type, rowData, meta ) :
670
+ innerData;
671
+ };
672
+ oCol.fnSetData = function ( rowData, val, meta ) {
673
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
674
+ };
675
+
676
+ /* Feature sorting overrides column specific when off */
677
+ if ( !oSettings.oFeatures.bSort )
678
+ {
679
+ oCol.bSortable = false;
680
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
681
+ }
682
+
683
+ /* Check that the class assignment is correct for sorting */
684
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
685
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
686
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
687
+ {
688
+ oCol.sSortingClass = oClasses.sSortableNone;
689
+ oCol.sSortingClassJUI = "";
690
+ }
691
+ else if ( bAsc && !bDesc )
692
+ {
693
+ oCol.sSortingClass = oClasses.sSortableAsc;
694
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
695
+ }
696
+ else if ( !bAsc && bDesc )
697
+ {
698
+ oCol.sSortingClass = oClasses.sSortableDesc;
699
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
700
+ }
701
+ else
702
+ {
703
+ oCol.sSortingClass = oClasses.sSortable;
704
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
705
+ }
706
+ }
707
+
708
+
709
+ /**
710
+ * Adjust the table column widths for new data. Note: you would probably want to
711
+ * do a redraw after calling this function!
712
+ * @param {object} settings dataTables settings object
713
+ * @memberof DataTable#oApi
714
+ */
715
+ function _fnAdjustColumnSizing ( settings )
716
+ {
717
+ /* Not interested in doing column width calculation if auto-width is disabled */
718
+ if ( settings.oFeatures.bAutoWidth !== false )
719
+ {
720
+ var columns = settings.aoColumns;
721
+
722
+ _fnCalculateColumnWidths( settings );
723
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
724
+ {
725
+ columns[i].nTh.style.width = columns[i].sWidth;
726
+ }
727
+ }
728
+
729
+ var scroll = settings.oScroll;
730
+ if ( scroll.sY !== '' || scroll.sX !== '')
731
+ {
732
+ _fnScrollDraw( settings );
733
+ }
734
+
735
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
736
+ }
737
+
738
+
739
+ /**
740
+ * Covert the index of a visible column to the index in the data array (take account
741
+ * of hidden columns)
742
+ * @param {object} oSettings dataTables settings object
743
+ * @param {int} iMatch Visible column index to lookup
744
+ * @returns {int} i the data index
745
+ * @memberof DataTable#oApi
746
+ */
747
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
748
+ {
749
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
750
+
751
+ return typeof aiVis[iMatch] === 'number' ?
752
+ aiVis[iMatch] :
753
+ null;
754
+ }
755
+
756
+
757
+ /**
758
+ * Covert the index of an index in the data array and convert it to the visible
759
+ * column index (take account of hidden columns)
760
+ * @param {int} iMatch Column index to lookup
761
+ * @param {object} oSettings dataTables settings object
762
+ * @returns {int} i the data index
763
+ * @memberof DataTable#oApi
764
+ */
765
+ function _fnColumnIndexToVisible( oSettings, iMatch )
766
+ {
767
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
768
+ var iPos = $.inArray( iMatch, aiVis );
769
+
770
+ return iPos !== -1 ? iPos : null;
771
+ }
772
+
773
+
774
+ /**
775
+ * Get the number of visible columns
776
+ * @param {object} oSettings dataTables settings object
777
+ * @returns {int} i the number of visible columns
778
+ * @memberof DataTable#oApi
779
+ */
780
+ function _fnVisbleColumns( oSettings )
781
+ {
782
+ return _fnGetColumns( oSettings, 'bVisible' ).length;
783
+ }
784
+
785
+
786
+ /**
787
+ * Get an array of column indexes that match a given property
788
+ * @param {object} oSettings dataTables settings object
789
+ * @param {string} sParam Parameter in aoColumns to look for - typically
790
+ * bVisible or bSearchable
791
+ * @returns {array} Array of indexes with matched properties
792
+ * @memberof DataTable#oApi
793
+ */
794
+ function _fnGetColumns( oSettings, sParam )
795
+ {
796
+ var a = [];
797
+
798
+ $.map( oSettings.aoColumns, function(val, i) {
799
+ if ( val[sParam] ) {
800
+ a.push( i );
801
+ }
802
+ } );
803
+
804
+ return a;
805
+ }
806
+
807
+
808
+ /**
809
+ * Calculate the 'type' of a column
810
+ * @param {object} settings dataTables settings object
811
+ * @memberof DataTable#oApi
812
+ */
813
+ function _fnColumnTypes ( settings )
814
+ {
815
+ var columns = settings.aoColumns;
816
+ var data = settings.aoData;
817
+ var types = DataTable.ext.type.detect;
818
+ var i, ien, j, jen, k, ken;
819
+ var col, cell, detectedType, cache;
820
+
821
+ // For each column, spin over the
822
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
823
+ col = columns[i];
824
+ cache = [];
825
+
826
+ if ( ! col.sType && col._sManualType ) {
827
+ col.sType = col._sManualType;
828
+ }
829
+ else if ( ! col.sType ) {
830
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
831
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
832
+ // Use a cache array so we only need to get the type data
833
+ // from the formatter once (when using multiple detectors)
834
+ if ( cache[k] === undefined ) {
835
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
836
+ }
837
+
838
+ detectedType = types[j]( cache[k], settings );
839
+
840
+ // Doesn't match, so break early, since this type can't
841
+ // apply to this column. Also, HTML is a special case since
842
+ // it is so similar to `string`. Just a single match is
843
+ // needed for a column to be html type
844
+ if ( ! detectedType || detectedType === 'html' ) {
845
+ break;
846
+ }
847
+ }
848
+
849
+ // Type is valid for all data points in the column - use this
850
+ // type
851
+ if ( detectedType ) {
852
+ col.sType = detectedType;
853
+ break;
854
+ }
855
+ }
856
+
857
+ // Fall back - if no type was detected, always use string
858
+ if ( ! col.sType ) {
859
+ col.sType = 'string';
860
+ }
861
+ }
862
+ }
863
+ }
864
+
865
+
866
+ /**
867
+ * Take the column definitions and static columns arrays and calculate how
868
+ * they relate to column indexes. The callback function will then apply the
869
+ * definition found for a column to a suitable configuration object.
870
+ * @param {object} oSettings dataTables settings object
871
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
872
+ * @param {array} aoCols The aoColumns array that defines columns individually
873
+ * @param {function} fn Callback function - takes two parameters, the calculated
874
+ * column index and the definition for that column.
875
+ * @memberof DataTable#oApi
876
+ */
877
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
878
+ {
879
+ var i, iLen, j, jLen, k, kLen, def;
880
+ var columns = oSettings.aoColumns;
881
+
882
+ // Column definitions with aTargets
883
+ if ( aoColDefs )
884
+ {
885
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
886
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
887
+ {
888
+ def = aoColDefs[i];
889
+
890
+ /* Each definition can target multiple columns, as it is an array */
891
+ var aTargets = def.targets !== undefined ?
892
+ def.targets :
893
+ def.aTargets;
894
+
895
+ if ( ! $.isArray( aTargets ) )
896
+ {
897
+ aTargets = [ aTargets ];
898
+ }
899
+
900
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
901
+ {
902
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
903
+ {
904
+ /* Add columns that we don't yet know about */
905
+ while( columns.length <= aTargets[j] )
906
+ {
907
+ _fnAddColumn( oSettings );
908
+ }
909
+
910
+ /* Integer, basic index */
911
+ fn( aTargets[j], def );
912
+ }
913
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
914
+ {
915
+ /* Negative integer, right to left column counting */
916
+ fn( columns.length+aTargets[j], def );
917
+ }
918
+ else if ( typeof aTargets[j] === 'string' )
919
+ {
920
+ /* Class name matching on TH element */
921
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
922
+ {
923
+ if ( aTargets[j] == "_all" ||
924
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
925
+ {
926
+ fn( k, def );
927
+ }
928
+ }
929
+ }
930
+ }
931
+ }
932
+ }
933
+
934
+ // Statically defined columns array
935
+ if ( aoCols )
936
+ {
937
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
938
+ {
939
+ fn( i, aoCols[i] );
940
+ }
941
+ }
942
+ }
943
+
944
+ /**
945
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
946
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
947
+ * DOM source.
948
+ * @param {object} oSettings dataTables settings object
949
+ * @param {array} aData data array to be added
950
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
951
+ * DataTables will create a row automatically
952
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
953
+ * if nTr is.
954
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
955
+ * @memberof DataTable#oApi
956
+ */
957
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
958
+ {
959
+ /* Create the object for storing information about this new row */
960
+ var iRow = oSettings.aoData.length;
961
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
962
+ src: nTr ? 'dom' : 'data'
963
+ } );
964
+
965
+ oData._aData = aDataIn;
966
+ oSettings.aoData.push( oData );
967
+
968
+ /* Create the cells */
969
+ var nTd, sThisType;
970
+ var columns = oSettings.aoColumns;
971
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
972
+ {
973
+ // When working with a row, the data source object must be populated. In
974
+ // all other cases, the data source object is already populated, so we
975
+ // don't overwrite it, which might break bindings etc
976
+ if ( nTr ) {
977
+ _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
978
+ }
979
+ columns[i].sType = null;
980
+ }
981
+
982
+ /* Add to the display array */
983
+ oSettings.aiDisplayMaster.push( iRow );
984
+
985
+ /* Create the DOM information, or register it if already present */
986
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
987
+ {
988
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
989
+ }
990
+
991
+ return iRow;
992
+ }
993
+
994
+
995
+ /**
996
+ * Add one or more TR elements to the table. Generally we'd expect to
997
+ * use this for reading data from a DOM sourced table, but it could be
998
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
999
+ * it is not cloned).
1000
+ * @param {object} settings dataTables settings object
1001
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
1002
+ * @returns {array} Array of indexes for the added rows
1003
+ * @memberof DataTable#oApi
1004
+ */
1005
+ function _fnAddTr( settings, trs )
1006
+ {
1007
+ var row;
1008
+
1009
+ // Allow an individual node to be passed in
1010
+ if ( ! (trs instanceof $) ) {
1011
+ trs = $(trs);
1012
+ }
1013
+
1014
+ return trs.map( function (i, el) {
1015
+ row = _fnGetRowElements( settings, el );
1016
+ return _fnAddData( settings, row.data, el, row.cells );
1017
+ } );
1018
+ }
1019
+
1020
+
1021
+ /**
1022
+ * Take a TR element and convert it to an index in aoData
1023
+ * @param {object} oSettings dataTables settings object
1024
+ * @param {node} n the TR element to find
1025
+ * @returns {int} index if the node is found, null if not
1026
+ * @memberof DataTable#oApi
1027
+ */
1028
+ function _fnNodeToDataIndex( oSettings, n )
1029
+ {
1030
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1031
+ }
1032
+
1033
+
1034
+ /**
1035
+ * Take a TD element and convert it into a column data index (not the visible index)
1036
+ * @param {object} oSettings dataTables settings object
1037
+ * @param {int} iRow The row number the TD/TH can be found in
1038
+ * @param {node} n The TD/TH element to find
1039
+ * @returns {int} index if the node is found, -1 if not
1040
+ * @memberof DataTable#oApi
1041
+ */
1042
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
1043
+ {
1044
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1045
+ }
1046
+
1047
+
1048
+ /**
1049
+ * Get the data for a given cell from the internal cache, taking into account data mapping
1050
+ * @param {object} settings dataTables settings object
1051
+ * @param {int} rowIdx aoData row id
1052
+ * @param {int} colIdx Column index
1053
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1054
+ * @returns {*} Cell data
1055
+ * @memberof DataTable#oApi
1056
+ */
1057
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
1058
+ {
1059
+ var draw = settings.iDraw;
1060
+ var col = settings.aoColumns[colIdx];
1061
+ var rowData = settings.aoData[rowIdx]._aData;
1062
+ var defaultContent = col.sDefaultContent;
1063
+ var cellData = col.fnGetData( rowData, type, {
1064
+ settings: settings,
1065
+ row: rowIdx,
1066
+ col: colIdx
1067
+ } );
1068
+
1069
+ if ( cellData === undefined ) {
1070
+ if ( settings.iDrawError != draw && defaultContent === null ) {
1071
+ _fnLog( settings, 0, "Requested unknown parameter "+
1072
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1073
+ " for row "+rowIdx, 4 );
1074
+ settings.iDrawError = draw;
1075
+ }
1076
+ return defaultContent;
1077
+ }
1078
+
1079
+ /* When the data source is null, we can use default column data */
1080
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1081
+ cellData = defaultContent;
1082
+ }
1083
+ else if ( typeof cellData === 'function' ) {
1084
+ // If the data source is a function, then we run it and use the return,
1085
+ // executing in the scope of the data object (for instances)
1086
+ return cellData.call( rowData );
1087
+ }
1088
+
1089
+ if ( cellData === null && type == 'display' ) {
1090
+ return '';
1091
+ }
1092
+ return cellData;
1093
+ }
1094
+
1095
+
1096
+ /**
1097
+ * Set the value for a specific cell, into the internal data cache
1098
+ * @param {object} settings dataTables settings object
1099
+ * @param {int} rowIdx aoData row id
1100
+ * @param {int} colIdx Column index
1101
+ * @param {*} val Value to set
1102
+ * @memberof DataTable#oApi
1103
+ */
1104
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
1105
+ {
1106
+ var col = settings.aoColumns[colIdx];
1107
+ var rowData = settings.aoData[rowIdx]._aData;
1108
+
1109
+ col.fnSetData( rowData, val, {
1110
+ settings: settings,
1111
+ row: rowIdx,
1112
+ col: colIdx
1113
+ } );
1114
+ }
1115
+
1116
+
1117
+ // Private variable that is used to match action syntax in the data property object
1118
+ var __reArray = /\[.*?\]$/;
1119
+ var __reFn = /\(\)$/;
1120
+
1121
+ /**
1122
+ * Split string on periods, taking into account escaped periods
1123
+ * @param {string} str String to split
1124
+ * @return {array} Split string
1125
+ */
1126
+ function _fnSplitObjNotation( str )
1127
+ {
1128
+ return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1129
+ return s.replace(/\\./g, '.');
1130
+ } );
1131
+ }
1132
+
1133
+
1134
+ /**
1135
+ * Return a function that can be used to get data from a source object, taking
1136
+ * into account the ability to use nested objects as a source
1137
+ * @param {string|int|function} mSource The data source for the object
1138
+ * @returns {function} Data get function
1139
+ * @memberof DataTable#oApi
1140
+ */
1141
+ function _fnGetObjectDataFn( mSource )
1142
+ {
1143
+ if ( $.isPlainObject( mSource ) )
1144
+ {
1145
+ /* Build an object of get functions, and wrap them in a single call */
1146
+ var o = {};
1147
+ $.each( mSource, function (key, val) {
1148
+ if ( val ) {
1149
+ o[key] = _fnGetObjectDataFn( val );
1150
+ }
1151
+ } );
1152
+
1153
+ return function (data, type, row, meta) {
1154
+ var t = o[type] || o._;
1155
+ return t !== undefined ?
1156
+ t(data, type, row, meta) :
1157
+ data;
1158
+ };
1159
+ }
1160
+ else if ( mSource === null )
1161
+ {
1162
+ /* Give an empty string for rendering / sorting etc */
1163
+ return function (data) { // type, row and meta also passed, but not used
1164
+ return data;
1165
+ };
1166
+ }
1167
+ else if ( typeof mSource === 'function' )
1168
+ {
1169
+ return function (data, type, row, meta) {
1170
+ return mSource( data, type, row, meta );
1171
+ };
1172
+ }
1173
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1174
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1175
+ {
1176
+ /* If there is a . in the source string then the data source is in a
1177
+ * nested object so we loop over the data for each level to get the next
1178
+ * level down. On each loop we test for undefined, and if found immediately
1179
+ * return. This allows entire objects to be missing and sDefaultContent to
1180
+ * be used if defined, rather than throwing an error
1181
+ */
1182
+ var fetchData = function (data, type, src) {
1183
+ var arrayNotation, funcNotation, out, innerSrc;
1184
+
1185
+ if ( src !== "" )
1186
+ {
1187
+ var a = _fnSplitObjNotation( src );
1188
+
1189
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1190
+ {
1191
+ // Check if we are dealing with special notation
1192
+ arrayNotation = a[i].match(__reArray);
1193
+ funcNotation = a[i].match(__reFn);
1194
+
1195
+ if ( arrayNotation )
1196
+ {
1197
+ // Array notation
1198
+ a[i] = a[i].replace(__reArray, '');
1199
+
1200
+ // Condition allows simply [] to be passed in
1201
+ if ( a[i] !== "" ) {
1202
+ data = data[ a[i] ];
1203
+ }
1204
+ out = [];
1205
+
1206
+ // Get the remainder of the nested object to get
1207
+ a.splice( 0, i+1 );
1208
+ innerSrc = a.join('.');
1209
+
1210
+ // Traverse each entry in the array getting the properties requested
1211
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1212
+ out.push( fetchData( data[j], type, innerSrc ) );
1213
+ }
1214
+
1215
+ // If a string is given in between the array notation indicators, that
1216
+ // is used to join the strings together, otherwise an array is returned
1217
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1218
+ data = (join==="") ? out : out.join(join);
1219
+
1220
+ // The inner call to fetchData has already traversed through the remainder
1221
+ // of the source requested, so we exit from the loop
1222
+ break;
1223
+ }
1224
+ else if ( funcNotation )
1225
+ {
1226
+ // Function call
1227
+ a[i] = a[i].replace(__reFn, '');
1228
+ data = data[ a[i] ]();
1229
+ continue;
1230
+ }
1231
+
1232
+ if ( data === null || data[ a[i] ] === undefined )
1233
+ {
1234
+ return undefined;
1235
+ }
1236
+ data = data[ a[i] ];
1237
+ }
1238
+ }
1239
+
1240
+ return data;
1241
+ };
1242
+
1243
+ return function (data, type) { // row and meta also passed, but not used
1244
+ return fetchData( data, type, mSource );
1245
+ };
1246
+ }
1247
+ else
1248
+ {
1249
+ /* Array or flat object mapping */
1250
+ return function (data, type) { // row and meta also passed, but not used
1251
+ return data[mSource];
1252
+ };
1253
+ }
1254
+ }
1255
+
1256
+
1257
+ /**
1258
+ * Return a function that can be used to set data from a source object, taking
1259
+ * into account the ability to use nested objects as a source
1260
+ * @param {string|int|function} mSource The data source for the object
1261
+ * @returns {function} Data set function
1262
+ * @memberof DataTable#oApi
1263
+ */
1264
+ function _fnSetObjectDataFn( mSource )
1265
+ {
1266
+ if ( $.isPlainObject( mSource ) )
1267
+ {
1268
+ /* Unlike get, only the underscore (global) option is used for for
1269
+ * setting data since we don't know the type here. This is why an object
1270
+ * option is not documented for `mData` (which is read/write), but it is
1271
+ * for `mRender` which is read only.
1272
+ */
1273
+ return _fnSetObjectDataFn( mSource._ );
1274
+ }
1275
+ else if ( mSource === null )
1276
+ {
1277
+ /* Nothing to do when the data source is null */
1278
+ return function () {};
1279
+ }
1280
+ else if ( typeof mSource === 'function' )
1281
+ {
1282
+ return function (data, val, meta) {
1283
+ mSource( data, 'set', val, meta );
1284
+ };
1285
+ }
1286
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1287
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1288
+ {
1289
+ /* Like the get, we need to get data from a nested object */
1290
+ var setData = function (data, val, src) {
1291
+ var a = _fnSplitObjNotation( src ), b;
1292
+ var aLast = a[a.length-1];
1293
+ var arrayNotation, funcNotation, o, innerSrc;
1294
+
1295
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1296
+ {
1297
+ // Check if we are dealing with an array notation request
1298
+ arrayNotation = a[i].match(__reArray);
1299
+ funcNotation = a[i].match(__reFn);
1300
+
1301
+ if ( arrayNotation )
1302
+ {
1303
+ a[i] = a[i].replace(__reArray, '');
1304
+ data[ a[i] ] = [];
1305
+
1306
+ // Get the remainder of the nested object to set so we can recurse
1307
+ b = a.slice();
1308
+ b.splice( 0, i+1 );
1309
+ innerSrc = b.join('.');
1310
+
1311
+ // Traverse each entry in the array setting the properties requested
1312
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1313
+ {
1314
+ o = {};
1315
+ setData( o, val[j], innerSrc );
1316
+ data[ a[i] ].push( o );
1317
+ }
1318
+
1319
+ // The inner call to setData has already traversed through the remainder
1320
+ // of the source and has set the data, thus we can exit here
1321
+ return;
1322
+ }
1323
+ else if ( funcNotation )
1324
+ {
1325
+ // Function call
1326
+ a[i] = a[i].replace(__reFn, '');
1327
+ data = data[ a[i] ]( val );
1328
+ }
1329
+
1330
+ // If the nested object doesn't currently exist - since we are
1331
+ // trying to set the value - create it
1332
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1333
+ {
1334
+ data[ a[i] ] = {};
1335
+ }
1336
+ data = data[ a[i] ];
1337
+ }
1338
+
1339
+ // Last item in the input - i.e, the actual set
1340
+ if ( aLast.match(__reFn ) )
1341
+ {
1342
+ // Function call
1343
+ data = data[ aLast.replace(__reFn, '') ]( val );
1344
+ }
1345
+ else
1346
+ {
1347
+ // If array notation is used, we just want to strip it and use the property name
1348
+ // and assign the value. If it isn't used, then we get the result we want anyway
1349
+ data[ aLast.replace(__reArray, '') ] = val;
1350
+ }
1351
+ };
1352
+
1353
+ return function (data, val) { // meta is also passed in, but not used
1354
+ return setData( data, val, mSource );
1355
+ };
1356
+ }
1357
+ else
1358
+ {
1359
+ /* Array or flat object mapping */
1360
+ return function (data, val) { // meta is also passed in, but not used
1361
+ data[mSource] = val;
1362
+ };
1363
+ }
1364
+ }
1365
+
1366
+
1367
+ /**
1368
+ * Return an array with the full table data
1369
+ * @param {object} oSettings dataTables settings object
1370
+ * @returns array {array} aData Master data array
1371
+ * @memberof DataTable#oApi
1372
+ */
1373
+ function _fnGetDataMaster ( settings )
1374
+ {
1375
+ return _pluck( settings.aoData, '_aData' );
1376
+ }
1377
+
1378
+
1379
+ /**
1380
+ * Nuke the table
1381
+ * @param {object} oSettings dataTables settings object
1382
+ * @memberof DataTable#oApi
1383
+ */
1384
+ function _fnClearTable( settings )
1385
+ {
1386
+ settings.aoData.length = 0;
1387
+ settings.aiDisplayMaster.length = 0;
1388
+ settings.aiDisplay.length = 0;
1389
+ }
1390
+
1391
+
1392
+ /**
1393
+ * Take an array of integers (index array) and remove a target integer (value - not
1394
+ * the key!)
1395
+ * @param {array} a Index array to target
1396
+ * @param {int} iTarget value to find
1397
+ * @memberof DataTable#oApi
1398
+ */
1399
+ function _fnDeleteIndex( a, iTarget, splice )
1400
+ {
1401
+ var iTargetIndex = -1;
1402
+
1403
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1404
+ {
1405
+ if ( a[i] == iTarget )
1406
+ {
1407
+ iTargetIndex = i;
1408
+ }
1409
+ else if ( a[i] > iTarget )
1410
+ {
1411
+ a[i]--;
1412
+ }
1413
+ }
1414
+
1415
+ if ( iTargetIndex != -1 && splice === undefined )
1416
+ {
1417
+ a.splice( iTargetIndex, 1 );
1418
+ }
1419
+ }
1420
+
1421
+
1422
+ /**
1423
+ * Mark cached data as invalid such that a re-read of the data will occur when
1424
+ * the cached data is next requested. Also update from the data source object.
1425
+ *
1426
+ * @param {object} settings DataTables settings object
1427
+ * @param {int} rowIdx Row index to invalidate
1428
+ * @memberof DataTable#oApi
1429
+ *
1430
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
1431
+ * the sort and filter methods can subscribe to it. That will required
1432
+ * initialisation options for sorting, which is why it is not already baked in
1433
+ */
1434
+ function _fnInvalidateRow( settings, rowIdx, src, column )
1435
+ {
1436
+ var row = settings.aoData[ rowIdx ];
1437
+ var i, ien;
1438
+
1439
+ // Are we reading last data from DOM or the data object?
1440
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1441
+ // Read the data from the DOM
1442
+ row._aData = _fnGetRowElements( settings, row ).data;
1443
+ }
1444
+ else {
1445
+ // Reading from data object, update the DOM
1446
+ var cells = row.anCells;
1447
+ var cell;
1448
+
1449
+ if ( cells ) {
1450
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1451
+ cell = cells[i];
1452
+
1453
+ // This is very frustrating, but in IE if you just write directly
1454
+ // to innerHTML, and elements that are overwritten are GC'ed,
1455
+ // even if there is a reference to them elsewhere
1456
+ while ( cell.childNodes.length ) {
1457
+ cell.removeChild( cell.firstChild );
1458
+ }
1459
+
1460
+ cells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );
1461
+ }
1462
+ }
1463
+ }
1464
+
1465
+ row._aSortData = null;
1466
+ row._aFilterData = null;
1467
+
1468
+ // Invalidate the type for a specific column (if given) or all columns since
1469
+ // the data might have changed
1470
+ var cols = settings.aoColumns;
1471
+ if ( column !== undefined ) {
1472
+ cols[ column ].sType = null;
1473
+ }
1474
+ else {
1475
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1476
+ cols[i].sType = null;
1477
+ }
1478
+ }
1479
+
1480
+ // Update DataTables special `DT_*` attributes for the row
1481
+ _fnRowAttributes( row );
1482
+ }
1483
+
1484
+
1485
+ /**
1486
+ * Build a data source object from an HTML row, reading the contents of the
1487
+ * cells that are in the row.
1488
+ *
1489
+ * @param {object} settings DataTables settings object
1490
+ * @param {node|object} TR element from which to read data or existing row
1491
+ * object from which to re-read the data from the cells
1492
+ * @returns {object} Object with two parameters: `data` the data read, in
1493
+ * document order, and `cells` and array of nodes (they can be useful to the
1494
+ * caller, so rather than needing a second traversal to get them, just return
1495
+ * them from here).
1496
+ * @memberof DataTable#oApi
1497
+ */
1498
+ function _fnGetRowElements( settings, row )
1499
+ {
1500
+ var
1501
+ d = [],
1502
+ tds = [],
1503
+ td = row.firstChild,
1504
+ name, col, o, i=0, contents,
1505
+ columns = settings.aoColumns;
1506
+
1507
+ var attr = function ( str, data, td ) {
1508
+ if ( typeof str === 'string' ) {
1509
+ var idx = str.indexOf('@');
1510
+
1511
+ if ( idx !== -1 ) {
1512
+ var src = str.substring( idx+1 );
1513
+ o[ '@'+src ] = td.getAttribute( src );
1514
+ }
1515
+ }
1516
+ };
1517
+
1518
+ var cellProcess = function ( cell ) {
1519
+ col = columns[i];
1520
+ contents = $.trim(cell.innerHTML);
1521
+
1522
+ if ( col && col._bAttrSrc ) {
1523
+ o = {
1524
+ display: contents
1525
+ };
1526
+
1527
+ attr( col.mData.sort, o, cell );
1528
+ attr( col.mData.type, o, cell );
1529
+ attr( col.mData.filter, o, cell );
1530
+
1531
+ d.push( o );
1532
+ }
1533
+ else {
1534
+ d.push( contents );
1535
+ }
1536
+
1537
+ i++;
1538
+ };
1539
+
1540
+ if ( td ) {
1541
+ // `tr` element passed in
1542
+ while ( td ) {
1543
+ name = td.nodeName.toUpperCase();
1544
+
1545
+ if ( name == "TD" || name == "TH" ) {
1546
+ cellProcess( td );
1547
+ tds.push( td );
1548
+ }
1549
+
1550
+ td = td.nextSibling;
1551
+ }
1552
+ }
1553
+ else {
1554
+ // Existing row object passed in
1555
+ tds = row.anCells;
1556
+
1557
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1558
+ cellProcess( tds[j] );
1559
+ }
1560
+ }
1561
+
1562
+ return {
1563
+ data: d,
1564
+ cells: tds
1565
+ };
1566
+ }
1567
+ /**
1568
+ * Create a new TR element (and it's TD children) for a row
1569
+ * @param {object} oSettings dataTables settings object
1570
+ * @param {int} iRow Row to consider
1571
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1572
+ * DataTables will create a row automatically
1573
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1574
+ * if nTr is.
1575
+ * @memberof DataTable#oApi
1576
+ */
1577
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1578
+ {
1579
+ var
1580
+ row = oSettings.aoData[iRow],
1581
+ rowData = row._aData,
1582
+ cells = [],
1583
+ nTr, nTd, oCol,
1584
+ i, iLen;
1585
+
1586
+ if ( row.nTr === null )
1587
+ {
1588
+ nTr = nTrIn || document.createElement('tr');
1589
+
1590
+ row.nTr = nTr;
1591
+ row.anCells = cells;
1592
+
1593
+ /* Use a private property on the node to allow reserve mapping from the node
1594
+ * to the aoData array for fast look up
1595
+ */
1596
+ nTr._DT_RowIndex = iRow;
1597
+
1598
+ /* Special parameters can be given by the data source to be used on the row */
1599
+ _fnRowAttributes( row );
1600
+
1601
+ /* Process each column */
1602
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1603
+ {
1604
+ oCol = oSettings.aoColumns[i];
1605
+
1606
+ nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1607
+ cells.push( nTd );
1608
+
1609
+ // Need to create the HTML if new, or if a rendering function is defined
1610
+ if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1611
+ {
1612
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1613
+ }
1614
+
1615
+ /* Add user defined class */
1616
+ if ( oCol.sClass )
1617
+ {
1618
+ nTd.className += ' '+oCol.sClass;
1619
+ }
1620
+
1621
+ // Visibility - add or remove as required
1622
+ if ( oCol.bVisible && ! nTrIn )
1623
+ {
1624
+ nTr.appendChild( nTd );
1625
+ }
1626
+ else if ( ! oCol.bVisible && nTrIn )
1627
+ {
1628
+ nTd.parentNode.removeChild( nTd );
1629
+ }
1630
+
1631
+ if ( oCol.fnCreatedCell )
1632
+ {
1633
+ oCol.fnCreatedCell.call( oSettings.oInstance,
1634
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1635
+ );
1636
+ }
1637
+ }
1638
+
1639
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1640
+ }
1641
+
1642
+ // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1643
+ // and deployed
1644
+ row.nTr.setAttribute( 'role', 'row' );
1645
+ }
1646
+
1647
+
1648
+ /**
1649
+ * Add attributes to a row based on the special `DT_*` parameters in a data
1650
+ * source object.
1651
+ * @param {object} DataTables row object for the row to be modified
1652
+ * @memberof DataTable#oApi
1653
+ */
1654
+ function _fnRowAttributes( row )
1655
+ {
1656
+ var tr = row.nTr;
1657
+ var data = row._aData;
1658
+
1659
+ if ( tr ) {
1660
+ if ( data.DT_RowId ) {
1661
+ tr.id = data.DT_RowId;
1662
+ }
1663
+
1664
+ if ( data.DT_RowClass ) {
1665
+ // Remove any classes added by DT_RowClass before
1666
+ var a = data.DT_RowClass.split(' ');
1667
+ row.__rowc = row.__rowc ?
1668
+ _unique( row.__rowc.concat( a ) ) :
1669
+ a;
1670
+
1671
+ $(tr)
1672
+ .removeClass( row.__rowc.join(' ') )
1673
+ .addClass( data.DT_RowClass );
1674
+ }
1675
+
1676
+ if ( data.DT_RowData ) {
1677
+ $(tr).data( data.DT_RowData );
1678
+ }
1679
+ }
1680
+ }
1681
+
1682
+
1683
+ /**
1684
+ * Create the HTML header for the table
1685
+ * @param {object} oSettings dataTables settings object
1686
+ * @memberof DataTable#oApi
1687
+ */
1688
+ function _fnBuildHead( oSettings )
1689
+ {
1690
+ var i, ien, cell, row, column;
1691
+ var thead = oSettings.nTHead;
1692
+ var tfoot = oSettings.nTFoot;
1693
+ var createHeader = $('th, td', thead).length === 0;
1694
+ var classes = oSettings.oClasses;
1695
+ var columns = oSettings.aoColumns;
1696
+
1697
+ if ( createHeader ) {
1698
+ row = $('<tr/>').appendTo( thead );
1699
+ }
1700
+
1701
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1702
+ column = columns[i];
1703
+ cell = $( column.nTh ).addClass( column.sClass );
1704
+
1705
+ if ( createHeader ) {
1706
+ cell.appendTo( row );
1707
+ }
1708
+
1709
+ // 1.11 move into sorting
1710
+ if ( oSettings.oFeatures.bSort ) {
1711
+ cell.addClass( column.sSortingClass );
1712
+
1713
+ if ( column.bSortable !== false ) {
1714
+ cell
1715
+ .attr( 'tabindex', oSettings.iTabIndex )
1716
+ .attr( 'aria-controls', oSettings.sTableId );
1717
+
1718
+ _fnSortAttachListener( oSettings, column.nTh, i );
1719
+ }
1720
+ }
1721
+
1722
+ if ( column.sTitle != cell.html() ) {
1723
+ cell.html( column.sTitle );
1724
+ }
1725
+
1726
+ _fnRenderer( oSettings, 'header' )(
1727
+ oSettings, cell, column, classes
1728
+ );
1729
+ }
1730
+
1731
+ if ( createHeader ) {
1732
+ _fnDetectHeader( oSettings.aoHeader, thead );
1733
+ }
1734
+
1735
+ /* ARIA role for the rows */
1736
+ $(thead).find('>tr').attr('role', 'row');
1737
+
1738
+ /* Deal with the footer - add classes if required */
1739
+ $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1740
+ $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1741
+
1742
+ // Cache the footer cells. Note that we only take the cells from the first
1743
+ // row in the footer. If there is more than one row the user wants to
1744
+ // interact with, they need to use the table().foot() method. Note also this
1745
+ // allows cells to be used for multiple columns using colspan
1746
+ if ( tfoot !== null ) {
1747
+ var cells = oSettings.aoFooter[0];
1748
+
1749
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1750
+ column = columns[i];
1751
+ column.nTf = cells[i].cell;
1752
+
1753
+ if ( column.sClass ) {
1754
+ $(column.nTf).addClass( column.sClass );
1755
+ }
1756
+ }
1757
+ }
1758
+ }
1759
+
1760
+
1761
+ /**
1762
+ * Draw the header (or footer) element based on the column visibility states. The
1763
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
1764
+ * the instantaneous column visibility, to construct the new layout. The grid is
1765
+ * traversed over cell at a time in a rows x columns grid fashion, although each
1766
+ * cell insert can cover multiple elements in the grid - which is tracks using the
1767
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
1768
+ * already a cell in that position.
1769
+ * @param {object} oSettings dataTables settings object
1770
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
1771
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1772
+ * @memberof DataTable#oApi
1773
+ */
1774
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1775
+ {
1776
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1777
+ var aoLocal = [];
1778
+ var aApplied = [];
1779
+ var iColumns = oSettings.aoColumns.length;
1780
+ var iRowspan, iColspan;
1781
+
1782
+ if ( ! aoSource )
1783
+ {
1784
+ return;
1785
+ }
1786
+
1787
+ if ( bIncludeHidden === undefined )
1788
+ {
1789
+ bIncludeHidden = false;
1790
+ }
1791
+
1792
+ /* Make a copy of the master layout array, but without the visible columns in it */
1793
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1794
+ {
1795
+ aoLocal[i] = aoSource[i].slice();
1796
+ aoLocal[i].nTr = aoSource[i].nTr;
1797
+
1798
+ /* Remove any columns which are currently hidden */
1799
+ for ( j=iColumns-1 ; j>=0 ; j-- )
1800
+ {
1801
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1802
+ {
1803
+ aoLocal[i].splice( j, 1 );
1804
+ }
1805
+ }
1806
+
1807
+ /* Prep the applied array - it needs an element for each row */
1808
+ aApplied.push( [] );
1809
+ }
1810
+
1811
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1812
+ {
1813
+ nLocalTr = aoLocal[i].nTr;
1814
+
1815
+ /* All cells are going to be replaced, so empty out the row */
1816
+ if ( nLocalTr )
1817
+ {
1818
+ while( (n = nLocalTr.firstChild) )
1819
+ {
1820
+ nLocalTr.removeChild( n );
1821
+ }
1822
+ }
1823
+
1824
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1825
+ {
1826
+ iRowspan = 1;
1827
+ iColspan = 1;
1828
+
1829
+ /* Check to see if there is already a cell (row/colspan) covering our target
1830
+ * insert point. If there is, then there is nothing to do.
1831
+ */
1832
+ if ( aApplied[i][j] === undefined )
1833
+ {
1834
+ nLocalTr.appendChild( aoLocal[i][j].cell );
1835
+ aApplied[i][j] = 1;
1836
+
1837
+ /* Expand the cell to cover as many rows as needed */
1838
+ while ( aoLocal[i+iRowspan] !== undefined &&
1839
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1840
+ {
1841
+ aApplied[i+iRowspan][j] = 1;
1842
+ iRowspan++;
1843
+ }
1844
+
1845
+ /* Expand the cell to cover as many columns as needed */
1846
+ while ( aoLocal[i][j+iColspan] !== undefined &&
1847
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1848
+ {
1849
+ /* Must update the applied array over the rows for the columns */
1850
+ for ( k=0 ; k<iRowspan ; k++ )
1851
+ {
1852
+ aApplied[i+k][j+iColspan] = 1;
1853
+ }
1854
+ iColspan++;
1855
+ }
1856
+
1857
+ /* Do the actual expansion in the DOM */
1858
+ $(aoLocal[i][j].cell)
1859
+ .attr('rowspan', iRowspan)
1860
+ .attr('colspan', iColspan);
1861
+ }
1862
+ }
1863
+ }
1864
+ }
1865
+
1866
+
1867
+ /**
1868
+ * Insert the required TR nodes into the table for display
1869
+ * @param {object} oSettings dataTables settings object
1870
+ * @memberof DataTable#oApi
1871
+ */
1872
+ function _fnDraw( oSettings )
1873
+ {
1874
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1875
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1876
+ if ( $.inArray( false, aPreDraw ) !== -1 )
1877
+ {
1878
+ _fnProcessingDisplay( oSettings, false );
1879
+ return;
1880
+ }
1881
+
1882
+ var i, iLen, n;
1883
+ var anRows = [];
1884
+ var iRowCount = 0;
1885
+ var asStripeClasses = oSettings.asStripeClasses;
1886
+ var iStripes = asStripeClasses.length;
1887
+ var iOpenRows = oSettings.aoOpenRows.length;
1888
+ var oLang = oSettings.oLanguage;
1889
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
1890
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1891
+ var aiDisplay = oSettings.aiDisplay;
1892
+
1893
+ oSettings.bDrawing = true;
1894
+
1895
+ /* Check and see if we have an initial draw position from state saving */
1896
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1897
+ {
1898
+ oSettings._iDisplayStart = bServerSide ?
1899
+ iInitDisplayStart :
1900
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1901
+ 0 :
1902
+ iInitDisplayStart;
1903
+
1904
+ oSettings.iInitDisplayStart = -1;
1905
+ }
1906
+
1907
+ var iDisplayStart = oSettings._iDisplayStart;
1908
+ var iDisplayEnd = oSettings.fnDisplayEnd();
1909
+
1910
+ /* Server-side processing draw intercept */
1911
+ if ( oSettings.bDeferLoading )
1912
+ {
1913
+ oSettings.bDeferLoading = false;
1914
+ oSettings.iDraw++;
1915
+ _fnProcessingDisplay( oSettings, false );
1916
+ }
1917
+ else if ( !bServerSide )
1918
+ {
1919
+ oSettings.iDraw++;
1920
+ }
1921
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1922
+ {
1923
+ return;
1924
+ }
1925
+
1926
+ if ( aiDisplay.length !== 0 )
1927
+ {
1928
+ var iStart = bServerSide ? 0 : iDisplayStart;
1929
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
1930
+
1931
+ for ( var j=iStart ; j<iEnd ; j++ )
1932
+ {
1933
+ var iDataIndex = aiDisplay[j];
1934
+ var aoData = oSettings.aoData[ iDataIndex ];
1935
+ if ( aoData.nTr === null )
1936
+ {
1937
+ _fnCreateTr( oSettings, iDataIndex );
1938
+ }
1939
+
1940
+ var nRow = aoData.nTr;
1941
+
1942
+ /* Remove the old striping classes and then add the new one */
1943
+ if ( iStripes !== 0 )
1944
+ {
1945
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
1946
+ if ( aoData._sRowStripe != sStripe )
1947
+ {
1948
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
1949
+ aoData._sRowStripe = sStripe;
1950
+ }
1951
+ }
1952
+
1953
+ /* Row callback functions - might want to manipulate the row */
1954
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
1955
+ [nRow, aoData._aData, iRowCount, j] );
1956
+
1957
+ anRows.push( nRow );
1958
+ iRowCount++;
1959
+ }
1960
+ }
1961
+ else
1962
+ {
1963
+ /* Table is empty - create a row with an empty message in it */
1964
+ var sZero = oLang.sZeroRecords;
1965
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
1966
+ {
1967
+ sZero = oLang.sLoadingRecords;
1968
+ }
1969
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
1970
+ {
1971
+ sZero = oLang.sEmptyTable;
1972
+ }
1973
+
1974
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
1975
+ .append( $('<td />', {
1976
+ 'valign': 'top',
1977
+ 'colSpan': _fnVisbleColumns( oSettings ),
1978
+ 'class': oSettings.oClasses.sRowEmpty
1979
+ } ).html( sZero ) )[0];
1980
+ }
1981
+
1982
+ /* Header and footer callbacks */
1983
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
1984
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
1985
+
1986
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
1987
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
1988
+
1989
+ var body = $(oSettings.nTBody);
1990
+
1991
+ body.children().detach();
1992
+ body.append( $(anRows) );
1993
+
1994
+ /* Call all required callback functions for the end of a draw */
1995
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
1996
+
1997
+ /* Draw is complete, sorting and filtering must be as well */
1998
+ oSettings.bSorted = false;
1999
+ oSettings.bFiltered = false;
2000
+ oSettings.bDrawing = false;
2001
+ }
2002
+
2003
+
2004
+ /**
2005
+ * Redraw the table - taking account of the various features which are enabled
2006
+ * @param {object} oSettings dataTables settings object
2007
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
2008
+ * the paging is reset to the first page
2009
+ * @memberof DataTable#oApi
2010
+ */
2011
+ function _fnReDraw( settings, holdPosition )
2012
+ {
2013
+ var
2014
+ features = settings.oFeatures,
2015
+ sort = features.bSort,
2016
+ filter = features.bFilter;
2017
+
2018
+ if ( sort ) {
2019
+ _fnSort( settings );
2020
+ }
2021
+
2022
+ if ( filter ) {
2023
+ _fnFilterComplete( settings, settings.oPreviousSearch );
2024
+ }
2025
+ else {
2026
+ // No filtering, so we want to just use the display master
2027
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
2028
+ }
2029
+
2030
+ if ( holdPosition !== true ) {
2031
+ settings._iDisplayStart = 0;
2032
+ }
2033
+
2034
+ // Let any modules know about the draw hold position state (used by
2035
+ // scrolling internally)
2036
+ settings._drawHold = holdPosition;
2037
+
2038
+ _fnDraw( settings );
2039
+
2040
+ settings._drawHold = false;
2041
+ }
2042
+
2043
+
2044
+ /**
2045
+ * Add the options to the page HTML for the table
2046
+ * @param {object} oSettings dataTables settings object
2047
+ * @memberof DataTable#oApi
2048
+ */
2049
+ function _fnAddOptionsHtml ( oSettings )
2050
+ {
2051
+ var classes = oSettings.oClasses;
2052
+ var table = $(oSettings.nTable);
2053
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2054
+ var features = oSettings.oFeatures;
2055
+
2056
+ // All DataTables are wrapped in a div
2057
+ var insert = $('<div/>', {
2058
+ id: oSettings.sTableId+'_wrapper',
2059
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2060
+ } );
2061
+
2062
+ oSettings.nHolding = holding[0];
2063
+ oSettings.nTableWrapper = insert[0];
2064
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2065
+
2066
+ /* Loop over the user set positioning and place the elements as needed */
2067
+ var aDom = oSettings.sDom.split('');
2068
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
2069
+ for ( var i=0 ; i<aDom.length ; i++ )
2070
+ {
2071
+ featureNode = null;
2072
+ cOption = aDom[i];
2073
+
2074
+ if ( cOption == '<' )
2075
+ {
2076
+ /* New container div */
2077
+ nNewNode = $('<div/>')[0];
2078
+
2079
+ /* Check to see if we should append an id and/or a class name to the container */
2080
+ cNext = aDom[i+1];
2081
+ if ( cNext == "'" || cNext == '"' )
2082
+ {
2083
+ sAttr = "";
2084
+ j = 2;
2085
+ while ( aDom[i+j] != cNext )
2086
+ {
2087
+ sAttr += aDom[i+j];
2088
+ j++;
2089
+ }
2090
+
2091
+ /* Replace jQuery UI constants @todo depreciated */
2092
+ if ( sAttr == "H" )
2093
+ {
2094
+ sAttr = classes.sJUIHeader;
2095
+ }
2096
+ else if ( sAttr == "F" )
2097
+ {
2098
+ sAttr = classes.sJUIFooter;
2099
+ }
2100
+
2101
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2102
+ * breaks the string into parts and applies them as needed
2103
+ */
2104
+ if ( sAttr.indexOf('.') != -1 )
2105
+ {
2106
+ var aSplit = sAttr.split('.');
2107
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2108
+ nNewNode.className = aSplit[1];
2109
+ }
2110
+ else if ( sAttr.charAt(0) == "#" )
2111
+ {
2112
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
2113
+ }
2114
+ else
2115
+ {
2116
+ nNewNode.className = sAttr;
2117
+ }
2118
+
2119
+ i += j; /* Move along the position array */
2120
+ }
2121
+
2122
+ insert.append( nNewNode );
2123
+ insert = $(nNewNode);
2124
+ }
2125
+ else if ( cOption == '>' )
2126
+ {
2127
+ /* End container div */
2128
+ insert = insert.parent();
2129
+ }
2130
+ // @todo Move options into their own plugins?
2131
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2132
+ {
2133
+ /* Length */
2134
+ featureNode = _fnFeatureHtmlLength( oSettings );
2135
+ }
2136
+ else if ( cOption == 'f' && features.bFilter )
2137
+ {
2138
+ /* Filter */
2139
+ featureNode = _fnFeatureHtmlFilter( oSettings );
2140
+ }
2141
+ else if ( cOption == 'r' && features.bProcessing )
2142
+ {
2143
+ /* pRocessing */
2144
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
2145
+ }
2146
+ else if ( cOption == 't' )
2147
+ {
2148
+ /* Table */
2149
+ featureNode = _fnFeatureHtmlTable( oSettings );
2150
+ }
2151
+ else if ( cOption == 'i' && features.bInfo )
2152
+ {
2153
+ /* Info */
2154
+ featureNode = _fnFeatureHtmlInfo( oSettings );
2155
+ }
2156
+ else if ( cOption == 'p' && features.bPaginate )
2157
+ {
2158
+ /* Pagination */
2159
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
2160
+ }
2161
+ else if ( DataTable.ext.feature.length !== 0 )
2162
+ {
2163
+ /* Plug-in features */
2164
+ var aoFeatures = DataTable.ext.feature;
2165
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2166
+ {
2167
+ if ( cOption == aoFeatures[k].cFeature )
2168
+ {
2169
+ featureNode = aoFeatures[k].fnInit( oSettings );
2170
+ break;
2171
+ }
2172
+ }
2173
+ }
2174
+
2175
+ /* Add to the 2D features array */
2176
+ if ( featureNode )
2177
+ {
2178
+ var aanFeatures = oSettings.aanFeatures;
2179
+
2180
+ if ( ! aanFeatures[cOption] )
2181
+ {
2182
+ aanFeatures[cOption] = [];
2183
+ }
2184
+
2185
+ aanFeatures[cOption].push( featureNode );
2186
+ insert.append( featureNode );
2187
+ }
2188
+ }
2189
+
2190
+ /* Built our DOM structure - replace the holding div with what we want */
2191
+ holding.replaceWith( insert );
2192
+ }
2193
+
2194
+
2195
+ /**
2196
+ * Use the DOM source to create up an array of header cells. The idea here is to
2197
+ * create a layout grid (array) of rows x columns, which contains a reference
2198
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
2199
+ * any column / row could be removed and the new grid constructed
2200
+ * @param array {object} aLayout Array to store the calculated layout in
2201
+ * @param {node} nThead The header/footer element for the table
2202
+ * @memberof DataTable#oApi
2203
+ */
2204
+ function _fnDetectHeader ( aLayout, nThead )
2205
+ {
2206
+ var nTrs = $(nThead).children('tr');
2207
+ var nTr, nCell;
2208
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2209
+ var bUnique;
2210
+ var fnShiftCol = function ( a, i, j ) {
2211
+ var k = a[i];
2212
+ while ( k[j] ) {
2213
+ j++;
2214
+ }
2215
+ return j;
2216
+ };
2217
+
2218
+ aLayout.splice( 0, aLayout.length );
2219
+
2220
+ /* We know how many rows there are in the layout - so prep it */
2221
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2222
+ {
2223
+ aLayout.push( [] );
2224
+ }
2225
+
2226
+ /* Calculate a layout array */
2227
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2228
+ {
2229
+ nTr = nTrs[i];
2230
+ iColumn = 0;
2231
+
2232
+ /* For every cell in the row... */
2233
+ nCell = nTr.firstChild;
2234
+ while ( nCell ) {
2235
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
2236
+ nCell.nodeName.toUpperCase() == "TH" )
2237
+ {
2238
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
2239
+ iColspan = nCell.getAttribute('colspan') * 1;
2240
+ iRowspan = nCell.getAttribute('rowspan') * 1;
2241
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2242
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2243
+
2244
+ /* There might be colspan cells already in this row, so shift our target
2245
+ * accordingly
2246
+ */
2247
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
2248
+
2249
+ /* Cache calculation for unique columns */
2250
+ bUnique = iColspan === 1 ? true : false;
2251
+
2252
+ /* If there is col / rowspan, copy the information into the layout grid */
2253
+ for ( l=0 ; l<iColspan ; l++ )
2254
+ {
2255
+ for ( k=0 ; k<iRowspan ; k++ )
2256
+ {
2257
+ aLayout[i+k][iColShifted+l] = {
2258
+ "cell": nCell,
2259
+ "unique": bUnique
2260
+ };
2261
+ aLayout[i+k].nTr = nTr;
2262
+ }
2263
+ }
2264
+ }
2265
+ nCell = nCell.nextSibling;
2266
+ }
2267
+ }
2268
+ }
2269
+
2270
+
2271
+ /**
2272
+ * Get an array of unique th elements, one for each column
2273
+ * @param {object} oSettings dataTables settings object
2274
+ * @param {node} nHeader automatically detect the layout from this node - optional
2275
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2276
+ * @returns array {node} aReturn list of unique th's
2277
+ * @memberof DataTable#oApi
2278
+ */
2279
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2280
+ {
2281
+ var aReturn = [];
2282
+ if ( !aLayout )
2283
+ {
2284
+ aLayout = oSettings.aoHeader;
2285
+ if ( nHeader )
2286
+ {
2287
+ aLayout = [];
2288
+ _fnDetectHeader( aLayout, nHeader );
2289
+ }
2290
+ }
2291
+
2292
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2293
+ {
2294
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2295
+ {
2296
+ if ( aLayout[i][j].unique &&
2297
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
2298
+ {
2299
+ aReturn[j] = aLayout[i][j].cell;
2300
+ }
2301
+ }
2302
+ }
2303
+
2304
+ return aReturn;
2305
+ }
2306
+
2307
+
2308
+
2309
+ /**
2310
+ * Create an Ajax call based on the table's settings, taking into account that
2311
+ * parameters can have multiple forms, and backwards compatibility.
2312
+ *
2313
+ * @param {object} oSettings dataTables settings object
2314
+ * @param {array} data Data to send to the server, required by
2315
+ * DataTables - may be augmented by developer callbacks
2316
+ * @param {function} fn Callback function to run when data is obtained
2317
+ */
2318
+ function _fnBuildAjax( oSettings, data, fn )
2319
+ {
2320
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
2321
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2322
+
2323
+ // Convert to object based for 1.10+ if using the old array scheme which can
2324
+ // come from server-side processing or serverParams
2325
+ if ( data && $.isArray(data) ) {
2326
+ var tmp = {};
2327
+ var rbracket = /(.*?)\[\]$/;
2328
+
2329
+ $.each( data, function (key, val) {
2330
+ var match = val.name.match(rbracket);
2331
+
2332
+ if ( match ) {
2333
+ // Support for arrays
2334
+ var name = match[0];
2335
+
2336
+ if ( ! tmp[ name ] ) {
2337
+ tmp[ name ] = [];
2338
+ }
2339
+ tmp[ name ].push( val.value );
2340
+ }
2341
+ else {
2342
+ tmp[val.name] = val.value;
2343
+ }
2344
+ } );
2345
+ data = tmp;
2346
+ }
2347
+
2348
+ var ajaxData;
2349
+ var ajax = oSettings.ajax;
2350
+ var instance = oSettings.oInstance;
2351
+
2352
+ if ( $.isPlainObject( ajax ) && ajax.data )
2353
+ {
2354
+ ajaxData = ajax.data;
2355
+
2356
+ var newData = $.isFunction( ajaxData ) ?
2357
+ ajaxData( data ) : // fn can manipulate data or return an object
2358
+ ajaxData; // object or array to merge
2359
+
2360
+ // If the function returned an object, use that alone
2361
+ data = $.isFunction( ajaxData ) && newData ?
2362
+ newData :
2363
+ $.extend( true, data, newData );
2364
+
2365
+ // Remove the data property as we've resolved it already and don't want
2366
+ // jQuery to do it again (it is restored at the end of the function)
2367
+ delete ajax.data;
2368
+ }
2369
+
2370
+ var baseAjax = {
2371
+ "data": data,
2372
+ "success": function (json) {
2373
+ var error = json.error || json.sError;
2374
+ if ( error ) {
2375
+ oSettings.oApi._fnLog( oSettings, 0, error );
2376
+ }
2377
+
2378
+ oSettings.json = json;
2379
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2380
+ fn( json );
2381
+ },
2382
+ "dataType": "json",
2383
+ "cache": false,
2384
+ "type": oSettings.sServerMethod,
2385
+ "error": function (xhr, error, thrown) {
2386
+ var log = oSettings.oApi._fnLog;
2387
+
2388
+ if ( error == "parsererror" ) {
2389
+ log( oSettings, 0, 'Invalid JSON response', 1 );
2390
+ }
2391
+ else if ( xhr.readyState === 4 ) {
2392
+ log( oSettings, 0, 'Ajax error', 7 );
2393
+ }
2394
+
2395
+ _fnProcessingDisplay( oSettings, false );
2396
+ }
2397
+ };
2398
+
2399
+ // Store the data submitted for the API
2400
+ oSettings.oAjaxData = data;
2401
+
2402
+ // Allow plug-ins and external processes to modify the data
2403
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2404
+
2405
+ if ( oSettings.fnServerData )
2406
+ {
2407
+ // DataTables 1.9- compatibility
2408
+ oSettings.fnServerData.call( instance,
2409
+ oSettings.sAjaxSource,
2410
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2411
+ return { name: key, value: val };
2412
+ } ),
2413
+ fn,
2414
+ oSettings
2415
+ );
2416
+ }
2417
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2418
+ {
2419
+ // DataTables 1.9- compatibility
2420
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2421
+ url: ajax || oSettings.sAjaxSource
2422
+ } ) );
2423
+ }
2424
+ else if ( $.isFunction( ajax ) )
2425
+ {
2426
+ // Is a function - let the caller define what needs to be done
2427
+ oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2428
+ }
2429
+ else
2430
+ {
2431
+ // Object to extend the base settings
2432
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2433
+
2434
+ // Restore for next time around
2435
+ ajax.data = ajaxData;
2436
+ }
2437
+ }
2438
+
2439
+
2440
+ /**
2441
+ * Update the table using an Ajax call
2442
+ * @param {object} settings dataTables settings object
2443
+ * @returns {boolean} Block the table drawing or not
2444
+ * @memberof DataTable#oApi
2445
+ */
2446
+ function _fnAjaxUpdate( settings )
2447
+ {
2448
+ if ( settings.bAjaxDataGet ) {
2449
+ settings.iDraw++;
2450
+ _fnProcessingDisplay( settings, true );
2451
+
2452
+ _fnBuildAjax(
2453
+ settings,
2454
+ _fnAjaxParameters( settings ),
2455
+ function(json) {
2456
+ _fnAjaxUpdateDraw( settings, json );
2457
+ }
2458
+ );
2459
+
2460
+ return false;
2461
+ }
2462
+ return true;
2463
+ }
2464
+
2465
+
2466
+ /**
2467
+ * Build up the parameters in an object needed for a server-side processing
2468
+ * request. Note that this is basically done twice, is different ways - a modern
2469
+ * method which is used by default in DataTables 1.10 which uses objects and
2470
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2471
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
2472
+ * option is set.
2473
+ * @param {object} oSettings dataTables settings object
2474
+ * @returns {bool} block the table drawing or not
2475
+ * @memberof DataTable#oApi
2476
+ */
2477
+ function _fnAjaxParameters( settings )
2478
+ {
2479
+ var
2480
+ columns = settings.aoColumns,
2481
+ columnCount = columns.length,
2482
+ features = settings.oFeatures,
2483
+ preSearch = settings.oPreviousSearch,
2484
+ preColSearch = settings.aoPreSearchCols,
2485
+ i, data = [], dataProp, column, columnSearch,
2486
+ sort = _fnSortFlatten( settings ),
2487
+ displayStart = settings._iDisplayStart,
2488
+ displayLength = features.bPaginate !== false ?
2489
+ settings._iDisplayLength :
2490
+ -1;
2491
+
2492
+ var param = function ( name, value ) {
2493
+ data.push( { 'name': name, 'value': value } );
2494
+ };
2495
+
2496
+ // DataTables 1.9- compatible method
2497
+ param( 'sEcho', settings.iDraw );
2498
+ param( 'iColumns', columnCount );
2499
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2500
+ param( 'iDisplayStart', displayStart );
2501
+ param( 'iDisplayLength', displayLength );
2502
+
2503
+ // DataTables 1.10+ method
2504
+ var d = {
2505
+ draw: settings.iDraw,
2506
+ columns: [],
2507
+ order: [],
2508
+ start: displayStart,
2509
+ length: displayLength,
2510
+ search: {
2511
+ value: preSearch.sSearch,
2512
+ regex: preSearch.bRegex
2513
+ }
2514
+ };
2515
+
2516
+ for ( i=0 ; i<columnCount ; i++ ) {
2517
+ column = columns[i];
2518
+ columnSearch = preColSearch[i];
2519
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2520
+
2521
+ d.columns.push( {
2522
+ data: dataProp,
2523
+ name: column.sName,
2524
+ searchable: column.bSearchable,
2525
+ orderable: column.bSortable,
2526
+ search: {
2527
+ value: columnSearch.sSearch,
2528
+ regex: columnSearch.bRegex
2529
+ }
2530
+ } );
2531
+
2532
+ param( "mDataProp_"+i, dataProp );
2533
+
2534
+ if ( features.bFilter ) {
2535
+ param( 'sSearch_'+i, columnSearch.sSearch );
2536
+ param( 'bRegex_'+i, columnSearch.bRegex );
2537
+ param( 'bSearchable_'+i, column.bSearchable );
2538
+ }
2539
+
2540
+ if ( features.bSort ) {
2541
+ param( 'bSortable_'+i, column.bSortable );
2542
+ }
2543
+ }
2544
+
2545
+ if ( features.bFilter ) {
2546
+ param( 'sSearch', preSearch.sSearch );
2547
+ param( 'bRegex', preSearch.bRegex );
2548
+ }
2549
+
2550
+ if ( features.bSort ) {
2551
+ $.each( sort, function ( i, val ) {
2552
+ d.order.push( { column: val.col, dir: val.dir } );
2553
+
2554
+ param( 'iSortCol_'+i, val.col );
2555
+ param( 'sSortDir_'+i, val.dir );
2556
+ } );
2557
+
2558
+ param( 'iSortingCols', sort.length );
2559
+ }
2560
+
2561
+ // If the legacy.ajax parameter is null, then we automatically decide which
2562
+ // form to use, based on sAjaxSource
2563
+ var legacy = DataTable.ext.legacy.ajax;
2564
+ if ( legacy === null ) {
2565
+ return settings.sAjaxSource ? data : d;
2566
+ }
2567
+
2568
+ // Otherwise, if legacy has been specified then we use that to decide on the
2569
+ // form
2570
+ return legacy ? data : d;
2571
+ }
2572
+
2573
+
2574
+ /**
2575
+ * Data the data from the server (nuking the old) and redraw the table
2576
+ * @param {object} oSettings dataTables settings object
2577
+ * @param {object} json json data return from the server.
2578
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
2579
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2580
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2581
+ * @param {array} json.aaData The data to display on this page
2582
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2583
+ * @memberof DataTable#oApi
2584
+ */
2585
+ function _fnAjaxUpdateDraw ( settings, json )
2586
+ {
2587
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2588
+ // Support both
2589
+ var compat = function ( old, modern ) {
2590
+ return json[old] !== undefined ? json[old] : json[modern];
2591
+ };
2592
+
2593
+ var draw = compat( 'sEcho', 'draw' );
2594
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2595
+ var rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2596
+
2597
+ if ( draw ) {
2598
+ // Protect against out of sequence returns
2599
+ if ( draw*1 < settings.iDraw ) {
2600
+ return;
2601
+ }
2602
+ settings.iDraw = draw * 1;
2603
+ }
2604
+
2605
+ _fnClearTable( settings );
2606
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
2607
+ settings._iRecordsDisplay = parseInt(rocordsFiltered, 10);
2608
+
2609
+ var data = _fnAjaxDataSrc( settings, json );
2610
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2611
+ _fnAddData( settings, data[i] );
2612
+ }
2613
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
2614
+
2615
+ settings.bAjaxDataGet = false;
2616
+ _fnDraw( settings );
2617
+
2618
+ if ( ! settings._bInitComplete ) {
2619
+ _fnInitComplete( settings, json );
2620
+ }
2621
+
2622
+ settings.bAjaxDataGet = true;
2623
+ _fnProcessingDisplay( settings, false );
2624
+ }
2625
+
2626
+
2627
+ /**
2628
+ * Get the data from the JSON data source to use for drawing a table. Using
2629
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2630
+ * source object, or from a processing function.
2631
+ * @param {object} oSettings dataTables settings object
2632
+ * @param {object} json Data source object / array from the server
2633
+ * @return {array} Array of data to use
2634
+ */
2635
+ function _fnAjaxDataSrc ( oSettings, json )
2636
+ {
2637
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2638
+ oSettings.ajax.dataSrc :
2639
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2640
+
2641
+ // Compatibility with 1.9-. In order to read from aaData, check if the
2642
+ // default has been changed, if not, check for aaData
2643
+ if ( dataSrc === 'data' ) {
2644
+ return json.aaData || json[dataSrc];
2645
+ }
2646
+
2647
+ return dataSrc !== "" ?
2648
+ _fnGetObjectDataFn( dataSrc )( json ) :
2649
+ json;
2650
+ }
2651
+
2652
+
2653
+ /**
2654
+ * Generate the node required for filtering text
2655
+ * @returns {node} Filter control element
2656
+ * @param {object} oSettings dataTables settings object
2657
+ * @memberof DataTable#oApi
2658
+ */
2659
+ function _fnFeatureHtmlFilter ( settings )
2660
+ {
2661
+ var classes = settings.oClasses;
2662
+ var tableId = settings.sTableId;
2663
+ var language = settings.oLanguage;
2664
+ var previousSearch = settings.oPreviousSearch;
2665
+ var features = settings.aanFeatures;
2666
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2667
+
2668
+ var str = language.sSearch;
2669
+ str = str.match(/_INPUT_/) ?
2670
+ str.replace('_INPUT_', input) :
2671
+ str+input;
2672
+
2673
+ var filter = $('<div/>', {
2674
+ 'id': ! features.f ? tableId+'_filter' : null,
2675
+ 'class': classes.sFilter
2676
+ } )
2677
+ .append( $('<label/>' ).append( str ) );
2678
+
2679
+ var searchFn = function() {
2680
+ /* Update all other filter input elements for the new display */
2681
+ var n = features.f;
2682
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2683
+
2684
+ /* Now do the filter */
2685
+ if ( val != previousSearch.sSearch ) {
2686
+ _fnFilterComplete( settings, {
2687
+ "sSearch": val,
2688
+ "bRegex": previousSearch.bRegex,
2689
+ "bSmart": previousSearch.bSmart ,
2690
+ "bCaseInsensitive": previousSearch.bCaseInsensitive
2691
+ } );
2692
+
2693
+ // Need to redraw, without resorting
2694
+ settings._iDisplayStart = 0;
2695
+ _fnDraw( settings );
2696
+ }
2697
+ };
2698
+ var jqFilter = $('input', filter)
2699
+ .val( previousSearch.sSearch )
2700
+ .attr( 'placeholder', language.sSearchPlaceholder )
2701
+ .bind(
2702
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
2703
+ _fnDataSource( settings ) === 'ssp' ?
2704
+ _fnThrottle( searchFn, 400 ):
2705
+ searchFn
2706
+ )
2707
+ .bind( 'keypress.DT', function(e) {
2708
+ /* Prevent form submission */
2709
+ if ( e.keyCode == 13 ) {
2710
+ return false;
2711
+ }
2712
+ } )
2713
+ .attr('aria-controls', tableId);
2714
+
2715
+ // Update the input elements whenever the table is filtered
2716
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2717
+ if ( settings === s ) {
2718
+ // IE9 throws an 'unknown error' if document.activeElement is used
2719
+ // inside an iframe or frame...
2720
+ try {
2721
+ if ( jqFilter[0] !== document.activeElement ) {
2722
+ jqFilter.val( previousSearch.sSearch );
2723
+ }
2724
+ }
2725
+ catch ( e ) {}
2726
+ }
2727
+ } );
2728
+
2729
+ return filter[0];
2730
+ }
2731
+
2732
+
2733
+ /**
2734
+ * Filter the table using both the global filter and column based filtering
2735
+ * @param {object} oSettings dataTables settings object
2736
+ * @param {object} oSearch search information
2737
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2738
+ * @memberof DataTable#oApi
2739
+ */
2740
+ function _fnFilterComplete ( oSettings, oInput, iForce )
2741
+ {
2742
+ var oPrevSearch = oSettings.oPreviousSearch;
2743
+ var aoPrevSearch = oSettings.aoPreSearchCols;
2744
+ var fnSaveFilter = function ( oFilter ) {
2745
+ /* Save the filtering values */
2746
+ oPrevSearch.sSearch = oFilter.sSearch;
2747
+ oPrevSearch.bRegex = oFilter.bRegex;
2748
+ oPrevSearch.bSmart = oFilter.bSmart;
2749
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2750
+ };
2751
+ var fnRegex = function ( o ) {
2752
+ // Backwards compatibility with the bEscapeRegex option
2753
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2754
+ };
2755
+
2756
+ // Resolve any column types that are unknown due to addition or invalidation
2757
+ // @todo As per sort - can this be moved into an event handler?
2758
+ _fnColumnTypes( oSettings );
2759
+
2760
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
2761
+ if ( _fnDataSource( oSettings ) != 'ssp' )
2762
+ {
2763
+ /* Global filter */
2764
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2765
+ fnSaveFilter( oInput );
2766
+
2767
+ /* Now do the individual column filter */
2768
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2769
+ {
2770
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2771
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2772
+ }
2773
+
2774
+ /* Custom filtering */
2775
+ _fnFilterCustom( oSettings );
2776
+ }
2777
+ else
2778
+ {
2779
+ fnSaveFilter( oInput );
2780
+ }
2781
+
2782
+ /* Tell the draw function we have been filtering */
2783
+ oSettings.bFiltered = true;
2784
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2785
+ }
2786
+
2787
+
2788
+ /**
2789
+ * Apply custom filtering functions
2790
+ * @param {object} oSettings dataTables settings object
2791
+ * @memberof DataTable#oApi
2792
+ */
2793
+ function _fnFilterCustom( settings )
2794
+ {
2795
+ var filters = DataTable.ext.search;
2796
+ var displayRows = settings.aiDisplay;
2797
+ var row, rowIdx;
2798
+
2799
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2800
+ var rows = [];
2801
+
2802
+ // Loop over each row and see if it should be included
2803
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2804
+ rowIdx = displayRows[ j ];
2805
+ row = settings.aoData[ rowIdx ];
2806
+
2807
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2808
+ rows.push( rowIdx );
2809
+ }
2810
+ }
2811
+
2812
+ // So the array reference doesn't break set the results into the
2813
+ // existing array
2814
+ displayRows.length = 0;
2815
+ displayRows.push.apply( displayRows, rows );
2816
+ }
2817
+ }
2818
+
2819
+
2820
+ /**
2821
+ * Filter the table on a per-column basis
2822
+ * @param {object} oSettings dataTables settings object
2823
+ * @param {string} sInput string to filter on
2824
+ * @param {int} iColumn column to filter
2825
+ * @param {bool} bRegex treat search string as a regular expression or not
2826
+ * @param {bool} bSmart use smart filtering or not
2827
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
2828
+ * @memberof DataTable#oApi
2829
+ */
2830
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2831
+ {
2832
+ if ( searchStr === '' ) {
2833
+ return;
2834
+ }
2835
+
2836
+ var data;
2837
+ var display = settings.aiDisplay;
2838
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2839
+
2840
+ for ( var i=display.length-1 ; i>=0 ; i-- ) {
2841
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2842
+
2843
+ if ( ! rpSearch.test( data ) ) {
2844
+ display.splice( i, 1 );
2845
+ }
2846
+ }
2847
+ }
2848
+
2849
+
2850
+ /**
2851
+ * Filter the data table based on user input and draw the table
2852
+ * @param {object} settings dataTables settings object
2853
+ * @param {string} input string to filter on
2854
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2855
+ * @param {bool} regex treat as a regular expression or not
2856
+ * @param {bool} smart perform smart filtering or not
2857
+ * @param {bool} caseInsensitive Do case insenstive matching or not
2858
+ * @memberof DataTable#oApi
2859
+ */
2860
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2861
+ {
2862
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2863
+ var prevSearch = settings.oPreviousSearch.sSearch;
2864
+ var displayMaster = settings.aiDisplayMaster;
2865
+ var display, invalidated, i;
2866
+
2867
+ // Need to take account of custom filtering functions - always filter
2868
+ if ( DataTable.ext.search.length !== 0 ) {
2869
+ force = true;
2870
+ }
2871
+
2872
+ // Check if any of the rows were invalidated
2873
+ invalidated = _fnFilterData( settings );
2874
+
2875
+ // If the input is blank - we just want the full data set
2876
+ if ( input.length <= 0 ) {
2877
+ settings.aiDisplay = displayMaster.slice();
2878
+ }
2879
+ else {
2880
+ // New search - start from the master array
2881
+ if ( invalidated ||
2882
+ force ||
2883
+ prevSearch.length > input.length ||
2884
+ input.indexOf(prevSearch) !== 0 ||
2885
+ settings.bSorted // On resort, the display master needs to be
2886
+ // re-filtered since indexes will have changed
2887
+ ) {
2888
+ settings.aiDisplay = displayMaster.slice();
2889
+ }
2890
+
2891
+ // Search the display array
2892
+ display = settings.aiDisplay;
2893
+
2894
+ for ( i=display.length-1 ; i>=0 ; i-- ) {
2895
+ if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2896
+ display.splice( i, 1 );
2897
+ }
2898
+ }
2899
+ }
2900
+ }
2901
+
2902
+
2903
+ /**
2904
+ * Build a regular expression object suitable for searching a table
2905
+ * @param {string} sSearch string to search for
2906
+ * @param {bool} bRegex treat as a regular expression or not
2907
+ * @param {bool} bSmart perform smart filtering or not
2908
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
2909
+ * @returns {RegExp} constructed object
2910
+ * @memberof DataTable#oApi
2911
+ */
2912
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
2913
+ {
2914
+ search = regex ?
2915
+ search :
2916
+ _fnEscapeRegex( search );
2917
+
2918
+ if ( smart ) {
2919
+ /* For smart filtering we want to allow the search to work regardless of
2920
+ * word order. We also want double quoted text to be preserved, so word
2921
+ * order is important - a la google. So this is what we want to
2922
+ * generate:
2923
+ *
2924
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2925
+ */
2926
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2927
+ return word.charAt(0) === '"' ?
2928
+ word.match( /^"(.*)"$/ )[1] :
2929
+ word;
2930
+ } );
2931
+
2932
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
2933
+ }
2934
+
2935
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
2936
+ }
2937
+
2938
+
2939
+ /**
2940
+ * scape a string such that it can be used in a regular expression
2941
+ * @param {string} sVal string to escape
2942
+ * @returns {string} escaped string
2943
+ * @memberof DataTable#oApi
2944
+ */
2945
+ function _fnEscapeRegex ( sVal )
2946
+ {
2947
+ return sVal.replace( _re_escape_regex, '\\$1' );
2948
+ }
2949
+
2950
+
2951
+
2952
+ var __filter_div = $('<div>')[0];
2953
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
2954
+
2955
+ // Update the filtering data for each row if needed (by invalidation or first run)
2956
+ function _fnFilterData ( settings )
2957
+ {
2958
+ var columns = settings.aoColumns;
2959
+ var column;
2960
+ var i, j, ien, jen, filterData, cellData, row;
2961
+ var fomatters = DataTable.ext.type.search;
2962
+ var wasInvalidated = false;
2963
+
2964
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
2965
+ row = settings.aoData[i];
2966
+
2967
+ if ( ! row._aFilterData ) {
2968
+ filterData = [];
2969
+
2970
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
2971
+ column = columns[j];
2972
+
2973
+ if ( column.bSearchable ) {
2974
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
2975
+
2976
+ if ( fomatters[ column.sType ] ) {
2977
+ cellData = fomatters[ column.sType ]( cellData );
2978
+ }
2979
+
2980
+ // Search in DataTables 1.10 is string based. In 1.11 this
2981
+ // should be altered to also allow strict type checking.
2982
+ if ( cellData === null ) {
2983
+ cellData = '';
2984
+ }
2985
+
2986
+ if ( typeof cellData !== 'string' && cellData.toString ) {
2987
+ cellData = cellData.toString();
2988
+ }
2989
+ }
2990
+ else {
2991
+ cellData = '';
2992
+ }
2993
+
2994
+ // If it looks like there is an HTML entity in the string,
2995
+ // attempt to decode it so sorting works as expected. Note that
2996
+ // we could use a single line of jQuery to do this, but the DOM
2997
+ // method used here is much faster http://jsperf.com/html-decode
2998
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
2999
+ __filter_div.innerHTML = cellData;
3000
+ cellData = __filter_div_textContent ?
3001
+ __filter_div.textContent :
3002
+ __filter_div.innerText;
3003
+ }
3004
+
3005
+ if ( cellData.replace ) {
3006
+ cellData = cellData.replace(/[\r\n]/g, '');
3007
+ }
3008
+
3009
+ filterData.push( cellData );
3010
+ }
3011
+
3012
+ row._aFilterData = filterData;
3013
+ row._sFilterRow = filterData.join(' ');
3014
+ wasInvalidated = true;
3015
+ }
3016
+ }
3017
+
3018
+ return wasInvalidated;
3019
+ }
3020
+
3021
+
3022
+ /**
3023
+ * Convert from the internal Hungarian notation to camelCase for external
3024
+ * interaction
3025
+ * @param {object} obj Object to convert
3026
+ * @returns {object} Inverted object
3027
+ * @memberof DataTable#oApi
3028
+ */
3029
+ function _fnSearchToCamel ( obj )
3030
+ {
3031
+ return {
3032
+ search: obj.sSearch,
3033
+ smart: obj.bSmart,
3034
+ regex: obj.bRegex,
3035
+ caseInsensitive: obj.bCaseInsensitive
3036
+ };
3037
+ }
3038
+
3039
+
3040
+
3041
+ /**
3042
+ * Convert from camelCase notation to the internal Hungarian. We could use the
3043
+ * Hungarian convert function here, but this is cleaner
3044
+ * @param {object} obj Object to convert
3045
+ * @returns {object} Inverted object
3046
+ * @memberof DataTable#oApi
3047
+ */
3048
+ function _fnSearchToHung ( obj )
3049
+ {
3050
+ return {
3051
+ sSearch: obj.search,
3052
+ bSmart: obj.smart,
3053
+ bRegex: obj.regex,
3054
+ bCaseInsensitive: obj.caseInsensitive
3055
+ };
3056
+ }
3057
+
3058
+ /**
3059
+ * Generate the node required for the info display
3060
+ * @param {object} oSettings dataTables settings object
3061
+ * @returns {node} Information element
3062
+ * @memberof DataTable#oApi
3063
+ */
3064
+ function _fnFeatureHtmlInfo ( settings )
3065
+ {
3066
+ var
3067
+ tid = settings.sTableId,
3068
+ nodes = settings.aanFeatures.i,
3069
+ n = $('<div/>', {
3070
+ 'class': settings.oClasses.sInfo,
3071
+ 'id': ! nodes ? tid+'_info' : null
3072
+ } );
3073
+
3074
+ if ( ! nodes ) {
3075
+ // Update display on each draw
3076
+ settings.aoDrawCallback.push( {
3077
+ "fn": _fnUpdateInfo,
3078
+ "sName": "information"
3079
+ } );
3080
+
3081
+ n
3082
+ .attr( 'role', 'status' )
3083
+ .attr( 'aria-live', 'polite' );
3084
+
3085
+ // Table is described by our info div
3086
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3087
+ }
3088
+
3089
+ return n[0];
3090
+ }
3091
+
3092
+
3093
+ /**
3094
+ * Update the information elements in the display
3095
+ * @param {object} settings dataTables settings object
3096
+ * @memberof DataTable#oApi
3097
+ */
3098
+ function _fnUpdateInfo ( settings )
3099
+ {
3100
+ /* Show information about the table */
3101
+ var nodes = settings.aanFeatures.i;
3102
+ if ( nodes.length === 0 ) {
3103
+ return;
3104
+ }
3105
+
3106
+ var
3107
+ lang = settings.oLanguage,
3108
+ start = settings._iDisplayStart+1,
3109
+ end = settings.fnDisplayEnd(),
3110
+ max = settings.fnRecordsTotal(),
3111
+ total = settings.fnRecordsDisplay(),
3112
+ out = total ?
3113
+ lang.sInfo :
3114
+ lang.sInfoEmpty;
3115
+
3116
+ if ( total !== max ) {
3117
+ /* Record set after filtering */
3118
+ out += ' ' + lang.sInfoFiltered;
3119
+ }
3120
+
3121
+ // Convert the macros
3122
+ out += lang.sInfoPostFix;
3123
+ out = _fnInfoMacros( settings, out );
3124
+
3125
+ var callback = lang.fnInfoCallback;
3126
+ if ( callback !== null ) {
3127
+ out = callback.call( settings.oInstance,
3128
+ settings, start, end, max, total, out
3129
+ );
3130
+ }
3131
+
3132
+ $(nodes).html( out );
3133
+ }
3134
+
3135
+
3136
+ function _fnInfoMacros ( settings, str )
3137
+ {
3138
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3139
+ // internally
3140
+ var
3141
+ formatter = settings.fnFormatNumber,
3142
+ start = settings._iDisplayStart+1,
3143
+ len = settings._iDisplayLength,
3144
+ vis = settings.fnRecordsDisplay(),
3145
+ all = len === -1;
3146
+
3147
+ return str.
3148
+ replace(/_START_/g, formatter.call( settings, start ) ).
3149
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3150
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3151
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3152
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3153
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3154
+ }
3155
+
3156
+
3157
+
3158
+ /**
3159
+ * Draw the table for the first time, adding all required features
3160
+ * @param {object} settings dataTables settings object
3161
+ * @memberof DataTable#oApi
3162
+ */
3163
+ function _fnInitialise ( settings )
3164
+ {
3165
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3166
+ var columns = settings.aoColumns, column;
3167
+ var features = settings.oFeatures;
3168
+
3169
+ /* Ensure that the table data is fully initialised */
3170
+ if ( ! settings.bInitialised ) {
3171
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3172
+ return;
3173
+ }
3174
+
3175
+ /* Show the display HTML options */
3176
+ _fnAddOptionsHtml( settings );
3177
+
3178
+ /* Build and draw the header / footer for the table */
3179
+ _fnBuildHead( settings );
3180
+ _fnDrawHead( settings, settings.aoHeader );
3181
+ _fnDrawHead( settings, settings.aoFooter );
3182
+
3183
+ /* Okay to show that something is going on now */
3184
+ _fnProcessingDisplay( settings, true );
3185
+
3186
+ /* Calculate sizes for columns */
3187
+ if ( features.bAutoWidth ) {
3188
+ _fnCalculateColumnWidths( settings );
3189
+ }
3190
+
3191
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3192
+ column = columns[i];
3193
+
3194
+ if ( column.sWidth ) {
3195
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
3196
+ }
3197
+ }
3198
+
3199
+ // If there is default sorting required - let's do it. The sort function
3200
+ // will do the drawing for us. Otherwise we draw the table regardless of the
3201
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
3202
+ // data (show 'loading' message possibly)
3203
+ _fnReDraw( settings );
3204
+
3205
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
3206
+ var dataSrc = _fnDataSource( settings );
3207
+ if ( dataSrc != 'ssp' ) {
3208
+ // if there is an ajax source load the data
3209
+ if ( dataSrc == 'ajax' ) {
3210
+ _fnBuildAjax( settings, [], function(json) {
3211
+ var aData = _fnAjaxDataSrc( settings, json );
3212
+
3213
+ // Got the data - add it to the table
3214
+ for ( i=0 ; i<aData.length ; i++ ) {
3215
+ _fnAddData( settings, aData[i] );
3216
+ }
3217
+
3218
+ // Reset the init display for cookie saving. We've already done
3219
+ // a filter, and therefore cleared it before. So we need to make
3220
+ // it appear 'fresh'
3221
+ settings.iInitDisplayStart = iAjaxStart;
3222
+
3223
+ _fnReDraw( settings );
3224
+
3225
+ _fnProcessingDisplay( settings, false );
3226
+ _fnInitComplete( settings, json );
3227
+ }, settings );
3228
+ }
3229
+ else {
3230
+ _fnProcessingDisplay( settings, false );
3231
+ _fnInitComplete( settings );
3232
+ }
3233
+ }
3234
+ }
3235
+
3236
+
3237
+ /**
3238
+ * Draw the table for the first time, adding all required features
3239
+ * @param {object} oSettings dataTables settings object
3240
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3241
+ * with client-side processing (optional)
3242
+ * @memberof DataTable#oApi
3243
+ */
3244
+ function _fnInitComplete ( settings, json )
3245
+ {
3246
+ settings._bInitComplete = true;
3247
+
3248
+ // On an Ajax load we now have data and therefore want to apply the column
3249
+ // sizing
3250
+ if ( json ) {
3251
+ _fnAdjustColumnSizing( settings );
3252
+ }
3253
+
3254
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3255
+ }
3256
+
3257
+
3258
+ function _fnLengthChange ( settings, val )
3259
+ {
3260
+ var len = parseInt( val, 10 );
3261
+ settings._iDisplayLength = len;
3262
+
3263
+ _fnLengthOverflow( settings );
3264
+
3265
+ // Fire length change event
3266
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
3267
+ }
3268
+
3269
+
3270
+ /**
3271
+ * Generate the node required for user display length changing
3272
+ * @param {object} settings dataTables settings object
3273
+ * @returns {node} Display length feature node
3274
+ * @memberof DataTable#oApi
3275
+ */
3276
+ function _fnFeatureHtmlLength ( settings )
3277
+ {
3278
+ var
3279
+ classes = settings.oClasses,
3280
+ tableId = settings.sTableId,
3281
+ menu = settings.aLengthMenu,
3282
+ d2 = $.isArray( menu[0] ),
3283
+ lengths = d2 ? menu[0] : menu,
3284
+ language = d2 ? menu[1] : menu;
3285
+
3286
+ var select = $('<select/>', {
3287
+ 'name': tableId+'_length',
3288
+ 'aria-controls': tableId,
3289
+ 'class': classes.sLengthSelect
3290
+ } );
3291
+
3292
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3293
+ select[0][ i ] = new Option( language[i], lengths[i] );
3294
+ }
3295
+
3296
+ var div = $('<div><label/></div>').addClass( classes.sLength );
3297
+ if ( ! settings.aanFeatures.l ) {
3298
+ div[0].id = tableId+'_length';
3299
+ }
3300
+
3301
+ div.children().append(
3302
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3303
+ );
3304
+
3305
+ // Can't use `select` variable as user might provide their own and the
3306
+ // reference is broken by the use of outerHTML
3307
+ $('select', div)
3308
+ .val( settings._iDisplayLength )
3309
+ .bind( 'change.DT', function(e) {
3310
+ _fnLengthChange( settings, $(this).val() );
3311
+ _fnDraw( settings );
3312
+ } );
3313
+
3314
+ // Update node value whenever anything changes the table's length
3315
+ $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3316
+ if ( settings === s ) {
3317
+ $('select', div).val( len );
3318
+ }
3319
+ } );
3320
+
3321
+ return div[0];
3322
+ }
3323
+
3324
+
3325
+
3326
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3327
+ * Note that most of the paging logic is done in
3328
+ * DataTable.ext.pager
3329
+ */
3330
+
3331
+ /**
3332
+ * Generate the node required for default pagination
3333
+ * @param {object} oSettings dataTables settings object
3334
+ * @returns {node} Pagination feature node
3335
+ * @memberof DataTable#oApi
3336
+ */
3337
+ function _fnFeatureHtmlPaginate ( settings )
3338
+ {
3339
+ var
3340
+ type = settings.sPaginationType,
3341
+ plugin = DataTable.ext.pager[ type ],
3342
+ modern = typeof plugin === 'function',
3343
+ redraw = function( settings ) {
3344
+ _fnDraw( settings );
3345
+ },
3346
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3347
+ features = settings.aanFeatures;
3348
+
3349
+ if ( ! modern ) {
3350
+ plugin.fnInit( settings, node, redraw );
3351
+ }
3352
+
3353
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
3354
+ if ( ! features.p )
3355
+ {
3356
+ node.id = settings.sTableId+'_paginate';
3357
+
3358
+ settings.aoDrawCallback.push( {
3359
+ "fn": function( settings ) {
3360
+ if ( modern ) {
3361
+ var
3362
+ start = settings._iDisplayStart,
3363
+ len = settings._iDisplayLength,
3364
+ visRecords = settings.fnRecordsDisplay(),
3365
+ all = len === -1,
3366
+ page = all ? 0 : Math.ceil( start / len ),
3367
+ pages = all ? 1 : Math.ceil( visRecords / len ),
3368
+ buttons = plugin(page, pages),
3369
+ i, ien;
3370
+
3371
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3372
+ _fnRenderer( settings, 'pageButton' )(
3373
+ settings, features.p[i], i, buttons, page, pages
3374
+ );
3375
+ }
3376
+ }
3377
+ else {
3378
+ plugin.fnUpdate( settings, redraw );
3379
+ }
3380
+ },
3381
+ "sName": "pagination"
3382
+ } );
3383
+ }
3384
+
3385
+ return node;
3386
+ }
3387
+
3388
+
3389
+ /**
3390
+ * Alter the display settings to change the page
3391
+ * @param {object} settings DataTables settings object
3392
+ * @param {string|int} action Paging action to take: "first", "previous",
3393
+ * "next" or "last" or page number to jump to (integer)
3394
+ * @param [bool] redraw Automatically draw the update or not
3395
+ * @returns {bool} true page has changed, false - no change
3396
+ * @memberof DataTable#oApi
3397
+ */
3398
+ function _fnPageChange ( settings, action, redraw )
3399
+ {
3400
+ var
3401
+ start = settings._iDisplayStart,
3402
+ len = settings._iDisplayLength,
3403
+ records = settings.fnRecordsDisplay();
3404
+
3405
+ if ( records === 0 || len === -1 )
3406
+ {
3407
+ start = 0;
3408
+ }
3409
+ else if ( typeof action === "number" )
3410
+ {
3411
+ start = action * len;
3412
+
3413
+ if ( start > records )
3414
+ {
3415
+ start = 0;
3416
+ }
3417
+ }
3418
+ else if ( action == "first" )
3419
+ {
3420
+ start = 0;
3421
+ }
3422
+ else if ( action == "previous" )
3423
+ {
3424
+ start = len >= 0 ?
3425
+ start - len :
3426
+ 0;
3427
+
3428
+ if ( start < 0 )
3429
+ {
3430
+ start = 0;
3431
+ }
3432
+ }
3433
+ else if ( action == "next" )
3434
+ {
3435
+ if ( start + len < records )
3436
+ {
3437
+ start += len;
3438
+ }
3439
+ }
3440
+ else if ( action == "last" )
3441
+ {
3442
+ start = Math.floor( (records-1) / len) * len;
3443
+ }
3444
+ else
3445
+ {
3446
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3447
+ }
3448
+
3449
+ var changed = settings._iDisplayStart !== start;
3450
+ settings._iDisplayStart = start;
3451
+
3452
+ if ( changed ) {
3453
+ _fnCallbackFire( settings, null, 'page', [settings] );
3454
+
3455
+ if ( redraw ) {
3456
+ _fnDraw( settings );
3457
+ }
3458
+ }
3459
+
3460
+ return changed;
3461
+ }
3462
+
3463
+
3464
+
3465
+ /**
3466
+ * Generate the node required for the processing node
3467
+ * @param {object} settings dataTables settings object
3468
+ * @returns {node} Processing element
3469
+ * @memberof DataTable#oApi
3470
+ */
3471
+ function _fnFeatureHtmlProcessing ( settings )
3472
+ {
3473
+ return $('<div/>', {
3474
+ 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3475
+ 'class': settings.oClasses.sProcessing
3476
+ } )
3477
+ .html( settings.oLanguage.sProcessing )
3478
+ .insertBefore( settings.nTable )[0];
3479
+ }
3480
+
3481
+
3482
+ /**
3483
+ * Display or hide the processing indicator
3484
+ * @param {object} settings dataTables settings object
3485
+ * @param {bool} show Show the processing indicator (true) or not (false)
3486
+ * @memberof DataTable#oApi
3487
+ */
3488
+ function _fnProcessingDisplay ( settings, show )
3489
+ {
3490
+ if ( settings.oFeatures.bProcessing ) {
3491
+ $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3492
+ }
3493
+
3494
+ _fnCallbackFire( settings, null, 'processing', [settings, show] );
3495
+ }
3496
+
3497
+ /**
3498
+ * Add any control elements for the table - specifically scrolling
3499
+ * @param {object} settings dataTables settings object
3500
+ * @returns {node} Node to add to the DOM
3501
+ * @memberof DataTable#oApi
3502
+ */
3503
+ function _fnFeatureHtmlTable ( settings )
3504
+ {
3505
+ var table = $(settings.nTable);
3506
+
3507
+ // Add the ARIA grid role to the table
3508
+ table.attr( 'role', 'grid' );
3509
+
3510
+ // Scrolling from here on in
3511
+ var scroll = settings.oScroll;
3512
+
3513
+ if ( scroll.sX === '' && scroll.sY === '' ) {
3514
+ return settings.nTable;
3515
+ }
3516
+
3517
+ var scrollX = scroll.sX;
3518
+ var scrollY = scroll.sY;
3519
+ var classes = settings.oClasses;
3520
+ var caption = table.children('caption');
3521
+ var captionSide = caption.length ? caption[0]._captionSide : null;
3522
+ var headerClone = $( table[0].cloneNode(false) );
3523
+ var footerClone = $( table[0].cloneNode(false) );
3524
+ var footer = table.children('tfoot');
3525
+ var _div = '<div/>';
3526
+ var size = function ( s ) {
3527
+ return !s ? null : _fnStringToCss( s );
3528
+ };
3529
+
3530
+ // This is fairly messy, but with x scrolling enabled, if the table has a
3531
+ // width attribute, regardless of any width applied using the column width
3532
+ // options, the browser will shrink or grow the table as needed to fit into
3533
+ // that 100%. That would make the width options useless. So we remove it.
3534
+ // This is okay, under the assumption that width:100% is applied to the
3535
+ // table in CSS (it is in the default stylesheet) which will set the table
3536
+ // width as appropriate (the attribute and css behave differently...)
3537
+ if ( scroll.sX && table.attr('width') === '100%' ) {
3538
+ table.removeAttr('width');
3539
+ }
3540
+
3541
+ if ( ! footer.length ) {
3542
+ footer = null;
3543
+ }
3544
+
3545
+ /*
3546
+ * The HTML structure that we want to generate in this function is:
3547
+ * div - scroller
3548
+ * div - scroll head
3549
+ * div - scroll head inner
3550
+ * table - scroll head table
3551
+ * thead - thead
3552
+ * div - scroll body
3553
+ * table - table (master table)
3554
+ * thead - thead clone for sizing
3555
+ * tbody - tbody
3556
+ * div - scroll foot
3557
+ * div - scroll foot inner
3558
+ * table - scroll foot table
3559
+ * tfoot - tfoot
3560
+ */
3561
+ var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3562
+ .append(
3563
+ $(_div, { 'class': classes.sScrollHead } )
3564
+ .css( {
3565
+ overflow: 'hidden',
3566
+ position: 'relative',
3567
+ border: 0,
3568
+ width: scrollX ? size(scrollX) : '100%'
3569
+ } )
3570
+ .append(
3571
+ $(_div, { 'class': classes.sScrollHeadInner } )
3572
+ .css( {
3573
+ 'box-sizing': 'content-box',
3574
+ width: scroll.sXInner || '100%'
3575
+ } )
3576
+ .append(
3577
+ headerClone
3578
+ .removeAttr('id')
3579
+ .css( 'margin-left', 0 )
3580
+ .append(
3581
+ table.children('thead')
3582
+ )
3583
+ )
3584
+ )
3585
+ .append( captionSide === 'top' ? caption : null )
3586
+ )
3587
+ .append(
3588
+ $(_div, { 'class': classes.sScrollBody } )
3589
+ .css( {
3590
+ overflow: 'auto',
3591
+ height: size( scrollY ),
3592
+ width: size( scrollX )
3593
+ } )
3594
+ .append( table )
3595
+ );
3596
+
3597
+ if ( footer ) {
3598
+ scroller.append(
3599
+ $(_div, { 'class': classes.sScrollFoot } )
3600
+ .css( {
3601
+ overflow: 'hidden',
3602
+ border: 0,
3603
+ width: scrollX ? size(scrollX) : '100%'
3604
+ } )
3605
+ .append(
3606
+ $(_div, { 'class': classes.sScrollFootInner } )
3607
+ .append(
3608
+ footerClone
3609
+ .removeAttr('id')
3610
+ .css( 'margin-left', 0 )
3611
+ .append(
3612
+ table.children('tfoot')
3613
+ )
3614
+ )
3615
+ )
3616
+ .append( captionSide === 'bottom' ? caption : null )
3617
+ );
3618
+ }
3619
+
3620
+ var children = scroller.children();
3621
+ var scrollHead = children[0];
3622
+ var scrollBody = children[1];
3623
+ var scrollFoot = footer ? children[2] : null;
3624
+
3625
+ // When the body is scrolled, then we also want to scroll the headers
3626
+ if ( scrollX ) {
3627
+ $(scrollBody).scroll( function (e) {
3628
+ var scrollLeft = this.scrollLeft;
3629
+
3630
+ scrollHead.scrollLeft = scrollLeft;
3631
+
3632
+ if ( footer ) {
3633
+ scrollFoot.scrollLeft = scrollLeft;
3634
+ }
3635
+ } );
3636
+ }
3637
+
3638
+ settings.nScrollHead = scrollHead;
3639
+ settings.nScrollBody = scrollBody;
3640
+ settings.nScrollFoot = scrollFoot;
3641
+
3642
+ // On redraw - align columns
3643
+ settings.aoDrawCallback.push( {
3644
+ "fn": _fnScrollDraw,
3645
+ "sName": "scrolling"
3646
+ } );
3647
+
3648
+ return scroller[0];
3649
+ }
3650
+
3651
+
3652
+
3653
+ /**
3654
+ * Update the header, footer and body tables for resizing - i.e. column
3655
+ * alignment.
3656
+ *
3657
+ * Welcome to the most horrible function DataTables. The process that this
3658
+ * function follows is basically:
3659
+ * 1. Re-create the table inside the scrolling div
3660
+ * 2. Take live measurements from the DOM
3661
+ * 3. Apply the measurements to align the columns
3662
+ * 4. Clean up
3663
+ *
3664
+ * @param {object} settings dataTables settings object
3665
+ * @memberof DataTable#oApi
3666
+ */
3667
+ function _fnScrollDraw ( settings )
3668
+ {
3669
+ // Given that this is such a monster function, a lot of variables are use
3670
+ // to try and keep the minimised size as small as possible
3671
+ var
3672
+ scroll = settings.oScroll,
3673
+ scrollX = scroll.sX,
3674
+ scrollXInner = scroll.sXInner,
3675
+ scrollY = scroll.sY,
3676
+ barWidth = scroll.iBarWidth,
3677
+ divHeader = $(settings.nScrollHead),
3678
+ divHeaderStyle = divHeader[0].style,
3679
+ divHeaderInner = divHeader.children('div'),
3680
+ divHeaderInnerStyle = divHeaderInner[0].style,
3681
+ divHeaderTable = divHeaderInner.children('table'),
3682
+ divBodyEl = settings.nScrollBody,
3683
+ divBody = $(divBodyEl),
3684
+ divBodyStyle = divBodyEl.style,
3685
+ divFooter = $(settings.nScrollFoot),
3686
+ divFooterInner = divFooter.children('div'),
3687
+ divFooterTable = divFooterInner.children('table'),
3688
+ header = $(settings.nTHead),
3689
+ table = $(settings.nTable),
3690
+ tableEl = table[0],
3691
+ tableStyle = tableEl.style,
3692
+ footer = settings.nTFoot ? $(settings.nTFoot) : null,
3693
+ browser = settings.oBrowser,
3694
+ ie67 = browser.bScrollOversize,
3695
+ headerTrgEls, footerTrgEls,
3696
+ headerSrcEls, footerSrcEls,
3697
+ headerCopy, footerCopy,
3698
+ headerWidths=[], footerWidths=[],
3699
+ headerContent=[],
3700
+ idx, correction, sanityWidth,
3701
+ zeroOut = function(nSizer) {
3702
+ var style = nSizer.style;
3703
+ style.paddingTop = "0";
3704
+ style.paddingBottom = "0";
3705
+ style.borderTopWidth = "0";
3706
+ style.borderBottomWidth = "0";
3707
+ style.height = 0;
3708
+ };
3709
+
3710
+ /*
3711
+ * 1. Re-create the table inside the scrolling div
3712
+ */
3713
+
3714
+ // Remove the old minimised thead and tfoot elements in the inner table
3715
+ table.children('thead, tfoot').remove();
3716
+
3717
+ // Clone the current header and footer elements and then place it into the inner table
3718
+ headerCopy = header.clone().prependTo( table );
3719
+ headerTrgEls = header.find('tr'); // original header is in its own table
3720
+ headerSrcEls = headerCopy.find('tr');
3721
+ headerCopy.find('th, td').removeAttr('tabindex');
3722
+
3723
+ if ( footer ) {
3724
+ footerCopy = footer.clone().prependTo( table );
3725
+ footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3726
+ footerSrcEls = footerCopy.find('tr');
3727
+ }
3728
+
3729
+
3730
+ /*
3731
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
3732
+ */
3733
+
3734
+ // Remove old sizing and apply the calculated column widths
3735
+ // Get the unique column headers in the newly created (cloned) header. We want to apply the
3736
+ // calculated sizes to this header
3737
+ if ( ! scrollX )
3738
+ {
3739
+ divBodyStyle.width = '100%';
3740
+ divHeader[0].style.width = '100%';
3741
+ }
3742
+
3743
+ $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3744
+ idx = _fnVisibleToColumnIndex( settings, i );
3745
+ el.style.width = settings.aoColumns[idx].sWidth;
3746
+ } );
3747
+
3748
+ if ( footer ) {
3749
+ _fnApplyToChildren( function(n) {
3750
+ n.style.width = "";
3751
+ }, footerSrcEls );
3752
+ }
3753
+
3754
+ // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3755
+ // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3756
+ // then hide it (end of this function), so add the header height to the body scroller.
3757
+ if ( scroll.bCollapse && scrollY !== "" ) {
3758
+ divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3759
+ }
3760
+
3761
+ // Size the table as a whole
3762
+ sanityWidth = table.outerWidth();
3763
+ if ( scrollX === "" ) {
3764
+ // No x scrolling
3765
+ tableStyle.width = "100%";
3766
+
3767
+ // IE7 will make the width of the table when 100% include the scrollbar
3768
+ // - which is shouldn't. When there is a scrollbar we need to take this
3769
+ // into account.
3770
+ if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3771
+ divBody.css('overflow-y') == "scroll")
3772
+ ) {
3773
+ tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3774
+ }
3775
+ }
3776
+ else
3777
+ {
3778
+ // x scrolling
3779
+ if ( scrollXInner !== "" ) {
3780
+ // x scroll inner has been given - use it
3781
+ tableStyle.width = _fnStringToCss(scrollXInner);
3782
+ }
3783
+ else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3784
+ // There is y-scrolling - try to take account of the y scroll bar
3785
+ tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3786
+ if ( table.outerWidth() > sanityWidth-barWidth ) {
3787
+ // Not possible to take account of it
3788
+ tableStyle.width = _fnStringToCss( sanityWidth );
3789
+ }
3790
+ }
3791
+ else {
3792
+ // When all else fails
3793
+ tableStyle.width = _fnStringToCss( sanityWidth );
3794
+ }
3795
+ }
3796
+
3797
+ // Recalculate the sanity width - now that we've applied the required width,
3798
+ // before it was a temporary variable. This is required because the column
3799
+ // width calculation is done before this table DOM is created.
3800
+ sanityWidth = table.outerWidth();
3801
+
3802
+ // Hidden header should have zero height, so remove padding and borders. Then
3803
+ // set the width based on the real headers
3804
+
3805
+ // Apply all styles in one pass
3806
+ _fnApplyToChildren( zeroOut, headerSrcEls );
3807
+
3808
+ // Read all widths in next pass
3809
+ _fnApplyToChildren( function(nSizer) {
3810
+ headerContent.push( nSizer.innerHTML );
3811
+ headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3812
+ }, headerSrcEls );
3813
+
3814
+ // Apply all widths in final pass
3815
+ _fnApplyToChildren( function(nToSize, i) {
3816
+ nToSize.style.width = headerWidths[i];
3817
+ }, headerTrgEls );
3818
+
3819
+ $(headerSrcEls).height(0);
3820
+
3821
+ /* Same again with the footer if we have one */
3822
+ if ( footer )
3823
+ {
3824
+ _fnApplyToChildren( zeroOut, footerSrcEls );
3825
+
3826
+ _fnApplyToChildren( function(nSizer) {
3827
+ footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3828
+ }, footerSrcEls );
3829
+
3830
+ _fnApplyToChildren( function(nToSize, i) {
3831
+ nToSize.style.width = footerWidths[i];
3832
+ }, footerTrgEls );
3833
+
3834
+ $(footerSrcEls).height(0);
3835
+ }
3836
+
3837
+
3838
+ /*
3839
+ * 3. Apply the measurements
3840
+ */
3841
+
3842
+ // "Hide" the header and footer that we used for the sizing. We need to keep
3843
+ // the content of the cell so that the width applied to the header and body
3844
+ // both match, but we want to hide it completely. We want to also fix their
3845
+ // width to what they currently are
3846
+ _fnApplyToChildren( function(nSizer, i) {
3847
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3848
+ nSizer.style.width = headerWidths[i];
3849
+ }, headerSrcEls );
3850
+
3851
+ if ( footer )
3852
+ {
3853
+ _fnApplyToChildren( function(nSizer, i) {
3854
+ nSizer.innerHTML = "";
3855
+ nSizer.style.width = footerWidths[i];
3856
+ }, footerSrcEls );
3857
+ }
3858
+
3859
+ // Sanity check that the table is of a sensible width. If not then we are going to get
3860
+ // misalignment - try to prevent this by not allowing the table to shrink below its min width
3861
+ if ( table.outerWidth() < sanityWidth )
3862
+ {
3863
+ // The min width depends upon if we have a vertical scrollbar visible or not */
3864
+ correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3865
+ divBody.css('overflow-y') == "scroll")) ?
3866
+ sanityWidth+barWidth :
3867
+ sanityWidth;
3868
+
3869
+ // IE6/7 are a law unto themselves...
3870
+ if ( ie67 && (divBodyEl.scrollHeight >
3871
+ divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3872
+ ) {
3873
+ tableStyle.width = _fnStringToCss( correction-barWidth );
3874
+ }
3875
+
3876
+ // And give the user a warning that we've stopped the table getting too small
3877
+ if ( scrollX === "" || scrollXInner !== "" ) {
3878
+ _fnLog( settings, 1, 'Possible column misalignment', 6 );
3879
+ }
3880
+ }
3881
+ else
3882
+ {
3883
+ correction = '100%';
3884
+ }
3885
+
3886
+ // Apply to the container elements
3887
+ divBodyStyle.width = _fnStringToCss( correction );
3888
+ divHeaderStyle.width = _fnStringToCss( correction );
3889
+
3890
+ if ( footer ) {
3891
+ settings.nScrollFoot.style.width = _fnStringToCss( correction );
3892
+ }
3893
+
3894
+
3895
+ /*
3896
+ * 4. Clean up
3897
+ */
3898
+ if ( ! scrollY ) {
3899
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3900
+ * the scrollbar height from the visible display, rather than adding it on. We need to
3901
+ * set the height in order to sort this. Don't want to do it in any other browsers.
3902
+ */
3903
+ if ( ie67 ) {
3904
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
3905
+ }
3906
+ }
3907
+
3908
+ if ( scrollY && scroll.bCollapse ) {
3909
+ divBodyStyle.height = _fnStringToCss( scrollY );
3910
+
3911
+ var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3912
+ barWidth :
3913
+ 0;
3914
+
3915
+ if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3916
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3917
+ }
3918
+ }
3919
+
3920
+ /* Finally set the width's of the header and footer tables */
3921
+ var iOuterWidth = table.outerWidth();
3922
+ divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
3923
+ divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
3924
+
3925
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
3926
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
3927
+ var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
3928
+ var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
3929
+ divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
3930
+
3931
+ if ( footer ) {
3932
+ divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
3933
+ divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
3934
+ divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
3935
+ }
3936
+
3937
+ /* Adjust the position of the header in case we loose the y-scrollbar */
3938
+ divBody.scroll();
3939
+
3940
+ // If sorting or filtering has occurred, jump the scrolling back to the top
3941
+ // only if we aren't holding the position
3942
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
3943
+ divBodyEl.scrollTop = 0;
3944
+ }
3945
+ }
3946
+
3947
+
3948
+
3949
+ /**
3950
+ * Apply a given function to the display child nodes of an element array (typically
3951
+ * TD children of TR rows
3952
+ * @param {function} fn Method to apply to the objects
3953
+ * @param array {nodes} an1 List of elements to look through for display children
3954
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
3955
+ * @memberof DataTable#oApi
3956
+ */
3957
+ function _fnApplyToChildren( fn, an1, an2 )
3958
+ {
3959
+ var index=0, i=0, iLen=an1.length;
3960
+ var nNode1, nNode2;
3961
+
3962
+ while ( i < iLen ) {
3963
+ nNode1 = an1[i].firstChild;
3964
+ nNode2 = an2 ? an2[i].firstChild : null;
3965
+
3966
+ while ( nNode1 ) {
3967
+ if ( nNode1.nodeType === 1 ) {
3968
+ if ( an2 ) {
3969
+ fn( nNode1, nNode2, index );
3970
+ }
3971
+ else {
3972
+ fn( nNode1, index );
3973
+ }
3974
+
3975
+ index++;
3976
+ }
3977
+
3978
+ nNode1 = nNode1.nextSibling;
3979
+ nNode2 = an2 ? nNode2.nextSibling : null;
3980
+ }
3981
+
3982
+ i++;
3983
+ }
3984
+ }
3985
+
3986
+
3987
+
3988
+ var __re_html_remove = /<.*?>/g;
3989
+
3990
+
3991
+ /**
3992
+ * Calculate the width of columns for the table
3993
+ * @param {object} oSettings dataTables settings object
3994
+ * @memberof DataTable#oApi
3995
+ */
3996
+ function _fnCalculateColumnWidths ( oSettings )
3997
+ {
3998
+ var
3999
+ table = oSettings.nTable,
4000
+ columns = oSettings.aoColumns,
4001
+ scroll = oSettings.oScroll,
4002
+ scrollY = scroll.sY,
4003
+ scrollX = scroll.sX,
4004
+ scrollXInner = scroll.sXInner,
4005
+ columnCount = columns.length,
4006
+ visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4007
+ headerCells = $('th', oSettings.nTHead),
4008
+ tableWidthAttr = table.getAttribute('width'),
4009
+ tableContainer = table.parentNode,
4010
+ userInputs = false,
4011
+ i, column, columnIdx, width, outerWidth;
4012
+
4013
+ /* Convert any user input sizes into pixel sizes */
4014
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4015
+ column = columns[ visibleColumns[i] ];
4016
+
4017
+ if ( column.sWidth !== null ) {
4018
+ column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4019
+
4020
+ userInputs = true;
4021
+ }
4022
+ }
4023
+
4024
+ /* If the number of columns in the DOM equals the number that we have to
4025
+ * process in DataTables, then we can use the offsets that are created by
4026
+ * the web- browser. No custom sizes can be set in order for this to happen,
4027
+ * nor scrolling used
4028
+ */
4029
+ if ( ! userInputs && ! scrollX && ! scrollY &&
4030
+ columnCount == _fnVisbleColumns( oSettings ) &&
4031
+ columnCount == headerCells.length
4032
+ ) {
4033
+ for ( i=0 ; i<columnCount ; i++ ) {
4034
+ columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4035
+ }
4036
+ }
4037
+ else
4038
+ {
4039
+ // Otherwise construct a single row table with the widest node in the
4040
+ // data, assign any user defined widths, then insert it into the DOM and
4041
+ // allow the browser to do all the hard work of calculating table widths
4042
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4043
+ .empty()
4044
+ .css( 'visibility', 'hidden' )
4045
+ .removeAttr( 'id' )
4046
+ .append( $(oSettings.nTHead).clone( false ) )
4047
+ .append( $(oSettings.nTFoot).clone( false ) )
4048
+ .append( $('<tbody><tr/></tbody>') );
4049
+
4050
+ // Remove any assigned widths from the footer (from scrolling)
4051
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
4052
+
4053
+ var tr = tmpTable.find( 'tbody tr' );
4054
+
4055
+ // Apply custom sizing to the cloned header
4056
+ headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4057
+
4058
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4059
+ column = columns[ visibleColumns[i] ];
4060
+
4061
+ headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4062
+ _fnStringToCss( column.sWidthOrig ) :
4063
+ '';
4064
+ }
4065
+
4066
+ // Find the widest cell for each column and put it into the table
4067
+ if ( oSettings.aoData.length ) {
4068
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4069
+ columnIdx = visibleColumns[i];
4070
+ column = columns[ columnIdx ];
4071
+
4072
+ $( _fnGetWidestNode( oSettings, columnIdx ) )
4073
+ .clone( false )
4074
+ .append( column.sContentPadding )
4075
+ .appendTo( tr );
4076
+ }
4077
+ }
4078
+
4079
+ // Table has been built, attach to the document so we can work with it
4080
+ tmpTable.appendTo( tableContainer );
4081
+
4082
+ // When scrolling (X or Y) we want to set the width of the table as
4083
+ // appropriate. However, when not scrolling leave the table width as it
4084
+ // is. This results in slightly different, but I think correct behaviour
4085
+ if ( scrollX && scrollXInner ) {
4086
+ tmpTable.width( scrollXInner );
4087
+ }
4088
+ else if ( scrollX ) {
4089
+ tmpTable.css( 'width', 'auto' );
4090
+
4091
+ if ( tmpTable.width() < tableContainer.offsetWidth ) {
4092
+ tmpTable.width( tableContainer.offsetWidth );
4093
+ }
4094
+ }
4095
+ else if ( scrollY ) {
4096
+ tmpTable.width( tableContainer.offsetWidth );
4097
+ }
4098
+ else if ( tableWidthAttr ) {
4099
+ tmpTable.width( tableWidthAttr );
4100
+ }
4101
+
4102
+ // Take into account the y scrollbar
4103
+ _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4104
+
4105
+ // Browsers need a bit of a hand when a width is assigned to any columns
4106
+ // when x-scrolling as they tend to collapse the table to the min-width,
4107
+ // even if we sent the column widths. So we need to keep track of what
4108
+ // the table width should be by summing the user given values, and the
4109
+ // automatic values
4110
+ if ( scrollX )
4111
+ {
4112
+ var total = 0;
4113
+
4114
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4115
+ column = columns[ visibleColumns[i] ];
4116
+ outerWidth = $(headerCells[i]).outerWidth();
4117
+
4118
+ total += column.sWidthOrig === null ?
4119
+ outerWidth :
4120
+ parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4121
+ }
4122
+
4123
+ tmpTable.width( _fnStringToCss( total ) );
4124
+ table.style.width = _fnStringToCss( total );
4125
+ }
4126
+
4127
+ // Get the width of each column in the constructed table
4128
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4129
+ column = columns[ visibleColumns[i] ];
4130
+ width = $(headerCells[i]).width();
4131
+
4132
+ if ( width ) {
4133
+ column.sWidth = _fnStringToCss( width );
4134
+ }
4135
+ }
4136
+
4137
+ table.style.width = _fnStringToCss( tmpTable.css('width') );
4138
+
4139
+ // Finished with the table - ditch it
4140
+ tmpTable.remove();
4141
+ }
4142
+
4143
+ // If there is a width attr, we want to attach an event listener which
4144
+ // allows the table sizing to automatically adjust when the window is
4145
+ // resized. Use the width attr rather than CSS, since we can't know if the
4146
+ // CSS is a relative value or absolute - DOM read is always px.
4147
+ if ( tableWidthAttr ) {
4148
+ table.style.width = _fnStringToCss( tableWidthAttr );
4149
+ }
4150
+
4151
+ if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4152
+ $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4153
+ _fnAdjustColumnSizing( oSettings );
4154
+ } ) );
4155
+
4156
+ oSettings._reszEvt = true;
4157
+ }
4158
+ }
4159
+
4160
+
4161
+ /**
4162
+ * Throttle the calls to a function. Arguments and context are maintained for
4163
+ * the throttled function
4164
+ * @param {function} fn Function to be called
4165
+ * @param {int} [freq=200] call frequency in mS
4166
+ * @returns {function} wrapped function
4167
+ * @memberof DataTable#oApi
4168
+ */
4169
+ function _fnThrottle( fn, freq ) {
4170
+ var
4171
+ frequency = freq || 200,
4172
+ last,
4173
+ timer;
4174
+
4175
+ return function () {
4176
+ var
4177
+ that = this,
4178
+ now = +new Date(),
4179
+ args = arguments;
4180
+
4181
+ if ( last && now < last + frequency ) {
4182
+ clearTimeout( timer );
4183
+
4184
+ timer = setTimeout( function () {
4185
+ last = undefined;
4186
+ fn.apply( that, args );
4187
+ }, frequency );
4188
+ }
4189
+ else if ( last ) {
4190
+ last = now;
4191
+ fn.apply( that, args );
4192
+ }
4193
+ else {
4194
+ last = now;
4195
+ }
4196
+ };
4197
+ }
4198
+
4199
+
4200
+ /**
4201
+ * Convert a CSS unit width to pixels (e.g. 2em)
4202
+ * @param {string} width width to be converted
4203
+ * @param {node} parent parent to get the with for (required for relative widths) - optional
4204
+ * @returns {int} width in pixels
4205
+ * @memberof DataTable#oApi
4206
+ */
4207
+ function _fnConvertToWidth ( width, parent )
4208
+ {
4209
+ if ( ! width ) {
4210
+ return 0;
4211
+ }
4212
+
4213
+ var n = $('<div/>')
4214
+ .css( 'width', _fnStringToCss( width ) )
4215
+ .appendTo( parent || document.body );
4216
+
4217
+ var val = n[0].offsetWidth;
4218
+ n.remove();
4219
+
4220
+ return val;
4221
+ }
4222
+
4223
+
4224
+ /**
4225
+ * Adjust a table's width to take account of vertical scroll bar
4226
+ * @param {object} oSettings dataTables settings object
4227
+ * @param {node} n table node
4228
+ * @memberof DataTable#oApi
4229
+ */
4230
+
4231
+ function _fnScrollingWidthAdjust ( settings, n )
4232
+ {
4233
+ var scroll = settings.oScroll;
4234
+
4235
+ if ( scroll.sX || scroll.sY ) {
4236
+ // When y-scrolling only, we want to remove the width of the scroll bar
4237
+ // so the table + scroll bar will fit into the area available, otherwise
4238
+ // we fix the table at its current size with no adjustment
4239
+ var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4240
+ n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4241
+ }
4242
+ }
4243
+
4244
+
4245
+ /**
4246
+ * Get the widest node
4247
+ * @param {object} settings dataTables settings object
4248
+ * @param {int} colIdx column of interest
4249
+ * @returns {node} widest table node
4250
+ * @memberof DataTable#oApi
4251
+ */
4252
+ function _fnGetWidestNode( settings, colIdx )
4253
+ {
4254
+ var idx = _fnGetMaxLenString( settings, colIdx );
4255
+ if ( idx < 0 ) {
4256
+ return null;
4257
+ }
4258
+
4259
+ var data = settings.aoData[ idx ];
4260
+ return ! data.nTr ? // Might not have been created when deferred rendering
4261
+ $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4262
+ data.anCells[ colIdx ];
4263
+ }
4264
+
4265
+
4266
+ /**
4267
+ * Get the maximum strlen for each data column
4268
+ * @param {object} settings dataTables settings object
4269
+ * @param {int} colIdx column of interest
4270
+ * @returns {string} max string length for each column
4271
+ * @memberof DataTable#oApi
4272
+ */
4273
+ function _fnGetMaxLenString( settings, colIdx )
4274
+ {
4275
+ var s, max=-1, maxIdx = -1;
4276
+
4277
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4278
+ s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4279
+ s = s.replace( __re_html_remove, '' );
4280
+
4281
+ if ( s.length > max ) {
4282
+ max = s.length;
4283
+ maxIdx = i;
4284
+ }
4285
+ }
4286
+
4287
+ return maxIdx;
4288
+ }
4289
+
4290
+
4291
+ /**
4292
+ * Append a CSS unit (only if required) to a string
4293
+ * @param {string} value to css-ify
4294
+ * @returns {string} value with css unit
4295
+ * @memberof DataTable#oApi
4296
+ */
4297
+ function _fnStringToCss( s )
4298
+ {
4299
+ if ( s === null ) {
4300
+ return '0px';
4301
+ }
4302
+
4303
+ if ( typeof s == 'number' ) {
4304
+ return s < 0 ?
4305
+ '0px' :
4306
+ s+'px';
4307
+ }
4308
+
4309
+ // Check it has a unit character already
4310
+ return s.match(/\d$/) ?
4311
+ s+'px' :
4312
+ s;
4313
+ }
4314
+
4315
+
4316
+ /**
4317
+ * Get the width of a scroll bar in this browser being used
4318
+ * @returns {int} width in pixels
4319
+ * @memberof DataTable#oApi
4320
+ */
4321
+ function _fnScrollBarWidth ()
4322
+ {
4323
+ // On first run a static variable is set, since this is only needed once.
4324
+ // Subsequent runs will just use the previously calculated value
4325
+ if ( ! DataTable.__scrollbarWidth ) {
4326
+ var inner = $('<p/>').css( {
4327
+ width: '100%',
4328
+ height: 200,
4329
+ padding: 0
4330
+ } )[0];
4331
+
4332
+ var outer = $('<div/>')
4333
+ .css( {
4334
+ position: 'absolute',
4335
+ top: 0,
4336
+ left: 0,
4337
+ width: 200,
4338
+ height: 150,
4339
+ padding: 0,
4340
+ overflow: 'hidden',
4341
+ visibility: 'hidden'
4342
+ } )
4343
+ .append( inner )
4344
+ .appendTo( 'body' );
4345
+
4346
+ var w1 = inner.offsetWidth;
4347
+ outer.css( 'overflow', 'scroll' );
4348
+ var w2 = inner.offsetWidth;
4349
+
4350
+ if ( w1 === w2 ) {
4351
+ w2 = outer[0].clientWidth;
4352
+ }
4353
+
4354
+ outer.remove();
4355
+
4356
+ DataTable.__scrollbarWidth = w1 - w2;
4357
+ }
4358
+
4359
+ return DataTable.__scrollbarWidth;
4360
+ }
4361
+
4362
+
4363
+
4364
+ function _fnSortFlatten ( settings )
4365
+ {
4366
+ var
4367
+ i, iLen, k, kLen,
4368
+ aSort = [],
4369
+ aiOrig = [],
4370
+ aoColumns = settings.aoColumns,
4371
+ aDataSort, iCol, sType, srcCol,
4372
+ fixed = settings.aaSortingFixed,
4373
+ fixedObj = $.isPlainObject( fixed ),
4374
+ nestedSort = [],
4375
+ add = function ( a ) {
4376
+ if ( a.length && ! $.isArray( a[0] ) ) {
4377
+ // 1D array
4378
+ nestedSort.push( a );
4379
+ }
4380
+ else {
4381
+ // 2D array
4382
+ nestedSort.push.apply( nestedSort, a );
4383
+ }
4384
+ };
4385
+
4386
+ // Build the sort array, with pre-fix and post-fix options if they have been
4387
+ // specified
4388
+ if ( $.isArray( fixed ) ) {
4389
+ add( fixed );
4390
+ }
4391
+
4392
+ if ( fixedObj && fixed.pre ) {
4393
+ add( fixed.pre );
4394
+ }
4395
+
4396
+ add( settings.aaSorting );
4397
+
4398
+ if (fixedObj && fixed.post ) {
4399
+ add( fixed.post );
4400
+ }
4401
+
4402
+ for ( i=0 ; i<nestedSort.length ; i++ )
4403
+ {
4404
+ srcCol = nestedSort[i][0];
4405
+ aDataSort = aoColumns[ srcCol ].aDataSort;
4406
+
4407
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4408
+ {
4409
+ iCol = aDataSort[k];
4410
+ sType = aoColumns[ iCol ].sType || 'string';
4411
+
4412
+ aSort.push( {
4413
+ src: srcCol,
4414
+ col: iCol,
4415
+ dir: nestedSort[i][1],
4416
+ index: nestedSort[i][2],
4417
+ type: sType,
4418
+ formatter: DataTable.ext.type.order[ sType+"-pre" ]
4419
+ } );
4420
+ }
4421
+ }
4422
+
4423
+ return aSort;
4424
+ }
4425
+
4426
+ /**
4427
+ * Change the order of the table
4428
+ * @param {object} oSettings dataTables settings object
4429
+ * @memberof DataTable#oApi
4430
+ * @todo This really needs split up!
4431
+ */
4432
+ function _fnSort ( oSettings )
4433
+ {
4434
+ var
4435
+ i, ien, iLen, j, jLen, k, kLen,
4436
+ sDataType, nTh,
4437
+ aiOrig = [],
4438
+ oExtSort = DataTable.ext.type.order,
4439
+ aoData = oSettings.aoData,
4440
+ aoColumns = oSettings.aoColumns,
4441
+ aDataSort, data, iCol, sType, oSort,
4442
+ formatters = 0,
4443
+ sortCol,
4444
+ displayMaster = oSettings.aiDisplayMaster,
4445
+ aSort;
4446
+
4447
+ // Resolve any column types that are unknown due to addition or invalidation
4448
+ // @todo Can this be moved into a 'data-ready' handler which is called when
4449
+ // data is going to be used in the table?
4450
+ _fnColumnTypes( oSettings );
4451
+
4452
+ aSort = _fnSortFlatten( oSettings );
4453
+
4454
+ for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4455
+ sortCol = aSort[i];
4456
+
4457
+ // Track if we can use the fast sort algorithm
4458
+ if ( sortCol.formatter ) {
4459
+ formatters++;
4460
+ }
4461
+
4462
+ // Load the data needed for the sort, for each cell
4463
+ _fnSortData( oSettings, sortCol.col );
4464
+ }
4465
+
4466
+ /* No sorting required if server-side or no sorting array */
4467
+ if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4468
+ {
4469
+ // Create a value - key array of the current row positions such that we can use their
4470
+ // current position during the sort, if values match, in order to perform stable sorting
4471
+ for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4472
+ aiOrig[ displayMaster[i] ] = i;
4473
+ }
4474
+
4475
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
4476
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4477
+ * follow on it's own, but this is what we want (example two column sorting):
4478
+ * fnLocalSorting = function(a,b){
4479
+ * var iTest;
4480
+ * iTest = oSort['string-asc']('data11', 'data12');
4481
+ * if (iTest !== 0)
4482
+ * return iTest;
4483
+ * iTest = oSort['numeric-desc']('data21', 'data22');
4484
+ * if (iTest !== 0)
4485
+ * return iTest;
4486
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4487
+ * }
4488
+ * Basically we have a test for each sorting column, if the data in that column is equal,
4489
+ * test the next column. If all columns match, then we use a numeric sort on the row
4490
+ * positions in the original data array to provide a stable sort.
4491
+ *
4492
+ * Note - I know it seems excessive to have two sorting methods, but the first is around
4493
+ * 15% faster, so the second is only maintained for backwards compatibility with sorting
4494
+ * methods which do not have a pre-sort formatting function.
4495
+ */
4496
+ if ( formatters === aSort.length ) {
4497
+ // All sort types have formatting functions
4498
+ displayMaster.sort( function ( a, b ) {
4499
+ var
4500
+ x, y, k, test, sort,
4501
+ len=aSort.length,
4502
+ dataA = aoData[a]._aSortData,
4503
+ dataB = aoData[b]._aSortData;
4504
+
4505
+ for ( k=0 ; k<len ; k++ ) {
4506
+ sort = aSort[k];
4507
+
4508
+ x = dataA[ sort.col ];
4509
+ y = dataB[ sort.col ];
4510
+
4511
+ test = x<y ? -1 : x>y ? 1 : 0;
4512
+ if ( test !== 0 ) {
4513
+ return sort.dir === 'asc' ? test : -test;
4514
+ }
4515
+ }
4516
+
4517
+ x = aiOrig[a];
4518
+ y = aiOrig[b];
4519
+ return x<y ? -1 : x>y ? 1 : 0;
4520
+ } );
4521
+ }
4522
+ else {
4523
+ // Depreciated - remove in 1.11 (providing a plug-in option)
4524
+ // Not all sort types have formatting methods, so we have to call their sorting
4525
+ // methods.
4526
+ displayMaster.sort( function ( a, b ) {
4527
+ var
4528
+ x, y, k, l, test, sort, fn,
4529
+ len=aSort.length,
4530
+ dataA = aoData[a]._aSortData,
4531
+ dataB = aoData[b]._aSortData;
4532
+
4533
+ for ( k=0 ; k<len ; k++ ) {
4534
+ sort = aSort[k];
4535
+
4536
+ x = dataA[ sort.col ];
4537
+ y = dataB[ sort.col ];
4538
+
4539
+ fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4540
+ test = fn( x, y );
4541
+ if ( test !== 0 ) {
4542
+ return test;
4543
+ }
4544
+ }
4545
+
4546
+ x = aiOrig[a];
4547
+ y = aiOrig[b];
4548
+ return x<y ? -1 : x>y ? 1 : 0;
4549
+ } );
4550
+ }
4551
+ }
4552
+
4553
+ /* Tell the draw function that we have sorted the data */
4554
+ oSettings.bSorted = true;
4555
+ }
4556
+
4557
+
4558
+ function _fnSortAria ( settings )
4559
+ {
4560
+ var label;
4561
+ var nextSort;
4562
+ var columns = settings.aoColumns;
4563
+ var aSort = _fnSortFlatten( settings );
4564
+ var oAria = settings.oLanguage.oAria;
4565
+
4566
+ // ARIA attributes - need to loop all columns, to update all (removing old
4567
+ // attributes as needed)
4568
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4569
+ {
4570
+ var col = columns[i];
4571
+ var asSorting = col.asSorting;
4572
+ var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4573
+ var th = col.nTh;
4574
+
4575
+ // IE7 is throwing an error when setting these properties with jQuery's
4576
+ // attr() and removeAttr() methods...
4577
+ th.removeAttribute('aria-sort');
4578
+
4579
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4580
+ if ( col.bSortable ) {
4581
+ if ( aSort.length > 0 && aSort[0].col == i ) {
4582
+ th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4583
+ nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4584
+ }
4585
+ else {
4586
+ nextSort = asSorting[0];
4587
+ }
4588
+
4589
+ label = sTitle + ( nextSort === "asc" ?
4590
+ oAria.sSortAscending :
4591
+ oAria.sSortDescending
4592
+ );
4593
+ }
4594
+ else {
4595
+ label = sTitle;
4596
+ }
4597
+
4598
+ th.setAttribute('aria-label', label);
4599
+ }
4600
+ }
4601
+
4602
+
4603
+ /**
4604
+ * Function to run on user sort request
4605
+ * @param {object} settings dataTables settings object
4606
+ * @param {node} attachTo node to attach the handler to
4607
+ * @param {int} colIdx column sorting index
4608
+ * @param {boolean} [append=false] Append the requested sort to the existing
4609
+ * sort if true (i.e. multi-column sort)
4610
+ * @param {function} [callback] callback function
4611
+ * @memberof DataTable#oApi
4612
+ */
4613
+ function _fnSortListener ( settings, colIdx, append, callback )
4614
+ {
4615
+ var col = settings.aoColumns[ colIdx ];
4616
+ var sorting = settings.aaSorting;
4617
+ var asSorting = col.asSorting;
4618
+ var nextSortIdx;
4619
+ var next = function ( a ) {
4620
+ var idx = a._idx;
4621
+ if ( idx === undefined ) {
4622
+ idx = $.inArray( a[1], asSorting );
4623
+ }
4624
+
4625
+ return idx+1 >= asSorting.length ? 0 : idx+1;
4626
+ };
4627
+
4628
+ // Convert to 2D array if needed
4629
+ if ( typeof sorting[0] === 'number' ) {
4630
+ sorting = settings.aaSorting = [ sorting ];
4631
+ }
4632
+
4633
+ // If appending the sort then we are multi-column sorting
4634
+ if ( append && settings.oFeatures.bSortMulti ) {
4635
+ // Are we already doing some kind of sort on this column?
4636
+ var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4637
+
4638
+ if ( sortIdx !== -1 ) {
4639
+ // Yes, modify the sort
4640
+ nextSortIdx = next( sorting[sortIdx] );
4641
+
4642
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4643
+ sorting[sortIdx]._idx = nextSortIdx;
4644
+ }
4645
+ else {
4646
+ // No sort on this column yet
4647
+ sorting.push( [ colIdx, asSorting[0], 0 ] );
4648
+ sorting[sorting.length-1]._idx = 0;
4649
+ }
4650
+ }
4651
+ else if ( sorting.length && sorting[0][0] == colIdx ) {
4652
+ // Single column - already sorting on this column, modify the sort
4653
+ nextSortIdx = next( sorting[0] );
4654
+
4655
+ sorting.length = 1;
4656
+ sorting[0][1] = asSorting[ nextSortIdx ];
4657
+ sorting[0]._idx = nextSortIdx;
4658
+ }
4659
+ else {
4660
+ // Single column - sort only on this column
4661
+ sorting.length = 0;
4662
+ sorting.push( [ colIdx, asSorting[0] ] );
4663
+ sorting[0]._idx = 0;
4664
+ }
4665
+
4666
+ // Run the sort by calling a full redraw
4667
+ _fnReDraw( settings );
4668
+
4669
+ // callback used for async user interaction
4670
+ if ( typeof callback == 'function' ) {
4671
+ callback( settings );
4672
+ }
4673
+ }
4674
+
4675
+
4676
+ /**
4677
+ * Attach a sort handler (click) to a node
4678
+ * @param {object} settings dataTables settings object
4679
+ * @param {node} attachTo node to attach the handler to
4680
+ * @param {int} colIdx column sorting index
4681
+ * @param {function} [callback] callback function
4682
+ * @memberof DataTable#oApi
4683
+ */
4684
+ function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4685
+ {
4686
+ var col = settings.aoColumns[ colIdx ];
4687
+
4688
+ _fnBindAction( attachTo, {}, function (e) {
4689
+ /* If the column is not sortable - don't to anything */
4690
+ if ( col.bSortable === false ) {
4691
+ return;
4692
+ }
4693
+
4694
+ // If processing is enabled use a timeout to allow the processing
4695
+ // display to be shown - otherwise to it synchronously
4696
+ if ( settings.oFeatures.bProcessing ) {
4697
+ _fnProcessingDisplay( settings, true );
4698
+
4699
+ setTimeout( function() {
4700
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
4701
+
4702
+ // In server-side processing, the draw callback will remove the
4703
+ // processing display
4704
+ if ( _fnDataSource( settings ) !== 'ssp' ) {
4705
+ _fnProcessingDisplay( settings, false );
4706
+ }
4707
+ }, 0 );
4708
+ }
4709
+ else {
4710
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
4711
+ }
4712
+ } );
4713
+ }
4714
+
4715
+
4716
+ /**
4717
+ * Set the sorting classes on table's body, Note: it is safe to call this function
4718
+ * when bSort and bSortClasses are false
4719
+ * @param {object} oSettings dataTables settings object
4720
+ * @memberof DataTable#oApi
4721
+ */
4722
+ function _fnSortingClasses( settings )
4723
+ {
4724
+ var oldSort = settings.aLastSort;
4725
+ var sortClass = settings.oClasses.sSortColumn;
4726
+ var sort = _fnSortFlatten( settings );
4727
+ var features = settings.oFeatures;
4728
+ var i, ien, colIdx;
4729
+
4730
+ if ( features.bSort && features.bSortClasses ) {
4731
+ // Remove old sorting classes
4732
+ for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4733
+ colIdx = oldSort[i].src;
4734
+
4735
+ // Remove column sorting
4736
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
4737
+ .removeClass( sortClass + (i<2 ? i+1 : 3) );
4738
+ }
4739
+
4740
+ // Add new column sorting
4741
+ for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4742
+ colIdx = sort[i].src;
4743
+
4744
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
4745
+ .addClass( sortClass + (i<2 ? i+1 : 3) );
4746
+ }
4747
+ }
4748
+
4749
+ settings.aLastSort = sort;
4750
+ }
4751
+
4752
+
4753
+ // Get the data to sort a column, be it from cache, fresh (populating the
4754
+ // cache), or from a sort formatter
4755
+ function _fnSortData( settings, idx )
4756
+ {
4757
+ // Custom sorting function - provided by the sort data type
4758
+ var column = settings.aoColumns[ idx ];
4759
+ var customSort = DataTable.ext.order[ column.sSortDataType ];
4760
+ var customData;
4761
+
4762
+ if ( customSort ) {
4763
+ customData = customSort.call( settings.oInstance, settings, idx,
4764
+ _fnColumnIndexToVisible( settings, idx )
4765
+ );
4766
+ }
4767
+
4768
+ // Use / populate cache
4769
+ var row, cellData;
4770
+ var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4771
+
4772
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4773
+ row = settings.aoData[i];
4774
+
4775
+ if ( ! row._aSortData ) {
4776
+ row._aSortData = [];
4777
+ }
4778
+
4779
+ if ( ! row._aSortData[idx] || customSort ) {
4780
+ cellData = customSort ?
4781
+ customData[i] : // If there was a custom sort function, use data from there
4782
+ _fnGetCellData( settings, i, idx, 'sort' );
4783
+
4784
+ row._aSortData[ idx ] = formatter ?
4785
+ formatter( cellData ) :
4786
+ cellData;
4787
+ }
4788
+ }
4789
+ }
4790
+
4791
+
4792
+
4793
+ /**
4794
+ * Save the state of a table
4795
+ * @param {object} oSettings dataTables settings object
4796
+ * @memberof DataTable#oApi
4797
+ */
4798
+ function _fnSaveState ( settings )
4799
+ {
4800
+ if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4801
+ {
4802
+ return;
4803
+ }
4804
+
4805
+ /* Store the interesting variables */
4806
+ var state = {
4807
+ time: +new Date(),
4808
+ start: settings._iDisplayStart,
4809
+ length: settings._iDisplayLength,
4810
+ order: $.extend( true, [], settings.aaSorting ),
4811
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
4812
+ columns: $.map( settings.aoColumns, function ( col, i ) {
4813
+ return {
4814
+ visible: col.bVisible,
4815
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4816
+ };
4817
+ } )
4818
+ };
4819
+
4820
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4821
+
4822
+ settings.oSavedState = state;
4823
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4824
+ }
4825
+
4826
+
4827
+ /**
4828
+ * Attempt to load a saved table state
4829
+ * @param {object} oSettings dataTables settings object
4830
+ * @param {object} oInit DataTables init object so we can override settings
4831
+ * @memberof DataTable#oApi
4832
+ */
4833
+ function _fnLoadState ( settings, oInit )
4834
+ {
4835
+ var i, ien;
4836
+ var columns = settings.aoColumns;
4837
+
4838
+ if ( ! settings.oFeatures.bStateSave ) {
4839
+ return;
4840
+ }
4841
+
4842
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4843
+ if ( ! state || ! state.time ) {
4844
+ return;
4845
+ }
4846
+
4847
+ /* Allow custom and plug-in manipulation functions to alter the saved data set and
4848
+ * cancelling of loading by returning false
4849
+ */
4850
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4851
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
4852
+ return;
4853
+ }
4854
+
4855
+ /* Reject old data */
4856
+ var duration = settings.iStateDuration;
4857
+ if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4858
+ return;
4859
+ }
4860
+
4861
+ // Number of columns have changed - all bets are off, no restore of settings
4862
+ if ( columns.length !== state.columns.length ) {
4863
+ return;
4864
+ }
4865
+
4866
+ // Store the saved state so it might be accessed at any time
4867
+ settings.oLoadedState = $.extend( true, {}, state );
4868
+
4869
+ // Restore key features - todo - for 1.11 this needs to be done by
4870
+ // subscribed events
4871
+ settings._iDisplayStart = state.start;
4872
+ settings.iInitDisplayStart = state.start;
4873
+ settings._iDisplayLength = state.length;
4874
+ settings.aaSorting = [];
4875
+
4876
+ // Order
4877
+ $.each( state.order, function ( i, col ) {
4878
+ settings.aaSorting.push( col[0] >= columns.length ?
4879
+ [ 0, col[1] ] :
4880
+ col
4881
+ );
4882
+ } );
4883
+
4884
+ // Search
4885
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4886
+
4887
+ // Columns
4888
+ for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4889
+ var col = state.columns[i];
4890
+
4891
+ // Visibility
4892
+ columns[i].bVisible = col.visible;
4893
+
4894
+ // Search
4895
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4896
+ }
4897
+
4898
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4899
+ }
4900
+
4901
+
4902
+ /**
4903
+ * Return the settings object for a particular table
4904
+ * @param {node} table table we are using as a dataTable
4905
+ * @returns {object} Settings object - or null if not found
4906
+ * @memberof DataTable#oApi
4907
+ */
4908
+ function _fnSettingsFromNode ( table )
4909
+ {
4910
+ var settings = DataTable.settings;
4911
+ var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
4912
+
4913
+ return idx !== -1 ?
4914
+ settings[ idx ] :
4915
+ null;
4916
+ }
4917
+
4918
+
4919
+ /**
4920
+ * Log an error message
4921
+ * @param {object} settings dataTables settings object
4922
+ * @param {int} level log error messages, or display them to the user
4923
+ * @param {string} msg error message
4924
+ * @param {int} tn Technical note id to get more information about the error.
4925
+ * @memberof DataTable#oApi
4926
+ */
4927
+ function _fnLog( settings, level, msg, tn )
4928
+ {
4929
+ msg = 'DataTables warning: '+
4930
+ (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
4931
+
4932
+ if ( tn ) {
4933
+ msg += '. For more information about this error, please see '+
4934
+ 'http://datatables.net/tn/'+tn;
4935
+ }
4936
+
4937
+ if ( ! level ) {
4938
+ // Backwards compatibility pre 1.10
4939
+ var ext = DataTable.ext;
4940
+ var type = ext.sErrMode || ext.errMode;
4941
+
4942
+ if ( type == 'alert' ) {
4943
+ alert( msg );
4944
+ }
4945
+ else {
4946
+ throw new Error(msg);
4947
+ }
4948
+ }
4949
+ else if ( window.console && console.log ) {
4950
+ console.log( msg );
4951
+ }
4952
+ }
4953
+
4954
+
4955
+ /**
4956
+ * See if a property is defined on one object, if so assign it to the other object
4957
+ * @param {object} ret target object
4958
+ * @param {object} src source object
4959
+ * @param {string} name property
4960
+ * @param {string} [mappedName] name to map too - optional, name used if not given
4961
+ * @memberof DataTable#oApi
4962
+ */
4963
+ function _fnMap( ret, src, name, mappedName )
4964
+ {
4965
+ if ( $.isArray( name ) ) {
4966
+ $.each( name, function (i, val) {
4967
+ if ( $.isArray( val ) ) {
4968
+ _fnMap( ret, src, val[0], val[1] );
4969
+ }
4970
+ else {
4971
+ _fnMap( ret, src, val );
4972
+ }
4973
+ } );
4974
+
4975
+ return;
4976
+ }
4977
+
4978
+ if ( mappedName === undefined ) {
4979
+ mappedName = name;
4980
+ }
4981
+
4982
+ if ( src[name] !== undefined ) {
4983
+ ret[mappedName] = src[name];
4984
+ }
4985
+ }
4986
+
4987
+
4988
+ /**
4989
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and
4990
+ * shallow copy arrays. The reason we need to do this, is that we don't want to
4991
+ * deep copy array init values (such as aaSorting) since the dev wouldn't be
4992
+ * able to override them, but we do want to deep copy arrays.
4993
+ * @param {object} out Object to extend
4994
+ * @param {object} extender Object from which the properties will be applied to
4995
+ * out
4996
+ * @param {boolean} breakRefs If true, then arrays will be sliced to take an
4997
+ * independent copy with the exception of the `data` or `aaData` parameters
4998
+ * if they are present. This is so you can pass in a collection to
4999
+ * DataTables and have that used as your data source without breaking the
5000
+ * references
5001
+ * @returns {object} out Reference, just for convenience - out === the return.
5002
+ * @memberof DataTable#oApi
5003
+ * @todo This doesn't take account of arrays inside the deep copied objects.
5004
+ */
5005
+ function _fnExtend( out, extender, breakRefs )
5006
+ {
5007
+ var val;
5008
+
5009
+ for ( var prop in extender ) {
5010
+ if ( extender.hasOwnProperty(prop) ) {
5011
+ val = extender[prop];
5012
+
5013
+ if ( $.isPlainObject( val ) ) {
5014
+ if ( ! $.isPlainObject( out[prop] ) ) {
5015
+ out[prop] = {};
5016
+ }
5017
+ $.extend( true, out[prop], val );
5018
+ }
5019
+ else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5020
+ out[prop] = val.slice();
5021
+ }
5022
+ else {
5023
+ out[prop] = val;
5024
+ }
5025
+ }
5026
+ }
5027
+
5028
+ return out;
5029
+ }
5030
+
5031
+
5032
+ /**
5033
+ * Bind an event handers to allow a click or return key to activate the callback.
5034
+ * This is good for accessibility since a return on the keyboard will have the
5035
+ * same effect as a click, if the element has focus.
5036
+ * @param {element} n Element to bind the action to
5037
+ * @param {object} oData Data object to pass to the triggered function
5038
+ * @param {function} fn Callback function for when the event is triggered
5039
+ * @memberof DataTable#oApi
5040
+ */
5041
+ function _fnBindAction( n, oData, fn )
5042
+ {
5043
+ $(n)
5044
+ .bind( 'click.DT', oData, function (e) {
5045
+ n.blur(); // Remove focus outline for mouse users
5046
+ fn(e);
5047
+ } )
5048
+ .bind( 'keypress.DT', oData, function (e){
5049
+ if ( e.which === 13 ) {
5050
+ e.preventDefault();
5051
+ fn(e);
5052
+ }
5053
+ } )
5054
+ .bind( 'selectstart.DT', function () {
5055
+ /* Take the brutal approach to cancelling text selection */
5056
+ return false;
5057
+ } );
5058
+ }
5059
+
5060
+
5061
+ /**
5062
+ * Register a callback function. Easily allows a callback function to be added to
5063
+ * an array store of callback functions that can then all be called together.
5064
+ * @param {object} oSettings dataTables settings object
5065
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
5066
+ * @param {function} fn Function to be called back
5067
+ * @param {string} sName Identifying name for the callback (i.e. a label)
5068
+ * @memberof DataTable#oApi
5069
+ */
5070
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
5071
+ {
5072
+ if ( fn )
5073
+ {
5074
+ oSettings[sStore].push( {
5075
+ "fn": fn,
5076
+ "sName": sName
5077
+ } );
5078
+ }
5079
+ }
5080
+
5081
+
5082
+ /**
5083
+ * Fire callback functions and trigger events. Note that the loop over the
5084
+ * callback array store is done backwards! Further note that you do not want to
5085
+ * fire off triggers in time sensitive applications (for example cell creation)
5086
+ * as its slow.
5087
+ * @param {object} settings dataTables settings object
5088
+ * @param {string} callbackArr Name of the array storage for the callbacks in
5089
+ * oSettings
5090
+ * @param {string} event Name of the jQuery custom event to trigger. If null no
5091
+ * trigger is fired
5092
+ * @param {array} args Array of arguments to pass to the callback function /
5093
+ * trigger
5094
+ * @memberof DataTable#oApi
5095
+ */
5096
+ function _fnCallbackFire( settings, callbackArr, e, args )
5097
+ {
5098
+ var ret = [];
5099
+
5100
+ if ( callbackArr ) {
5101
+ ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5102
+ return val.fn.apply( settings.oInstance, args );
5103
+ } );
5104
+ }
5105
+
5106
+ if ( e !== null ) {
5107
+ $(settings.nTable).trigger( e+'.dt', args );
5108
+ }
5109
+
5110
+ return ret;
5111
+ }
5112
+
5113
+
5114
+ function _fnLengthOverflow ( settings )
5115
+ {
5116
+ var
5117
+ start = settings._iDisplayStart,
5118
+ end = settings.fnDisplayEnd(),
5119
+ len = settings._iDisplayLength;
5120
+
5121
+ /* If we have space to show extra rows (backing up from the end point - then do so */
5122
+ if ( end === settings.fnRecordsDisplay() )
5123
+ {
5124
+ start = end - len;
5125
+ }
5126
+
5127
+ if ( len === -1 || start < 0 )
5128
+ {
5129
+ start = 0;
5130
+ }
5131
+
5132
+ settings._iDisplayStart = start;
5133
+ }
5134
+
5135
+
5136
+ function _fnRenderer( settings, type )
5137
+ {
5138
+ var renderer = settings.renderer;
5139
+ var host = DataTable.ext.renderer[type];
5140
+
5141
+ if ( $.isPlainObject( renderer ) && renderer[type] ) {
5142
+ // Specific renderer for this type. If available use it, otherwise use
5143
+ // the default.
5144
+ return host[renderer[type]] || host._;
5145
+ }
5146
+ else if ( typeof renderer === 'string' ) {
5147
+ // Common renderer - if there is one available for this type use it,
5148
+ // otherwise use the default
5149
+ return host[renderer] || host._;
5150
+ }
5151
+
5152
+ // Use the default
5153
+ return host._;
5154
+ }
5155
+
5156
+
5157
+ /**
5158
+ * Detect the data source being used for the table. Used to simplify the code
5159
+ * a little (ajax) and to make it compress a little smaller.
5160
+ *
5161
+ * @param {object} settings dataTables settings object
5162
+ * @returns {string} Data source
5163
+ * @memberof DataTable#oApi
5164
+ */
5165
+ function _fnDataSource ( settings )
5166
+ {
5167
+ if ( settings.oFeatures.bServerSide ) {
5168
+ return 'ssp';
5169
+ }
5170
+ else if ( settings.ajax || settings.sAjaxSource ) {
5171
+ return 'ajax';
5172
+ }
5173
+ return 'dom';
5174
+ }
5175
+
5176
+
5177
+ DataTable = function( options )
5178
+ {
5179
+ /**
5180
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5181
+ * return the resulting jQuery object.
5182
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5183
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5184
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5185
+ * criterion ("applied") or all TR elements (i.e. no filter).
5186
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5187
+ * Can be either 'current', whereby the current sorting of the table is used, or
5188
+ * 'original' whereby the original order the data was read into the table is used.
5189
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5190
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5191
+ * 'current' and filter is 'applied', regardless of what they might be given as.
5192
+ * @returns {object} jQuery object, filtered by the given selector.
5193
+ * @dtopt API
5194
+ * @deprecated Since v1.10
5195
+ *
5196
+ * @example
5197
+ * $(document).ready(function() {
5198
+ * var oTable = $('#example').dataTable();
5199
+ *
5200
+ * // Highlight every second row
5201
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
5202
+ * } );
5203
+ *
5204
+ * @example
5205
+ * $(document).ready(function() {
5206
+ * var oTable = $('#example').dataTable();
5207
+ *
5208
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
5209
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
5210
+ * oTable.fnFilter('Webkit');
5211
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5212
+ * oTable.fnFilter('');
5213
+ * } );
5214
+ */
5215
+ this.$ = function ( sSelector, oOpts )
5216
+ {
5217
+ return this.api(true).$( sSelector, oOpts );
5218
+ };
5219
+
5220
+
5221
+ /**
5222
+ * Almost identical to $ in operation, but in this case returns the data for the matched
5223
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5224
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
5225
+ * rows are found, the data returned is the original data array/object that was used to
5226
+ * create the row (or a generated array if from a DOM source).
5227
+ *
5228
+ * This method is often useful in-combination with $ where both functions are given the
5229
+ * same parameters and the array indexes will match identically.
5230
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5231
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5232
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5233
+ * criterion ("applied") or all elements (i.e. no filter).
5234
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
5235
+ * Can be either 'current', whereby the current sorting of the table is used, or
5236
+ * 'original' whereby the original order the data was read into the table is used.
5237
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5238
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5239
+ * 'current' and filter is 'applied', regardless of what they might be given as.
5240
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
5241
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5242
+ * entry in the array.
5243
+ * @dtopt API
5244
+ * @deprecated Since v1.10
5245
+ *
5246
+ * @example
5247
+ * $(document).ready(function() {
5248
+ * var oTable = $('#example').dataTable();
5249
+ *
5250
+ * // Get the data from the first row in the table
5251
+ * var data = oTable._('tr:first');
5252
+ *
5253
+ * // Do something useful with the data
5254
+ * alert( "First cell is: "+data[0] );
5255
+ * } );
5256
+ *
5257
+ * @example
5258
+ * $(document).ready(function() {
5259
+ * var oTable = $('#example').dataTable();
5260
+ *
5261
+ * // Filter to 'Webkit' and get all data for
5262
+ * oTable.fnFilter('Webkit');
5263
+ * var data = oTable._('tr', {"search": "applied"});
5264
+ *
5265
+ * // Do something with the data
5266
+ * alert( data.length+" rows matched the search" );
5267
+ * } );
5268
+ */
5269
+ this._ = function ( sSelector, oOpts )
5270
+ {
5271
+ return this.api(true).rows( sSelector, oOpts ).data();
5272
+ };
5273
+
5274
+
5275
+ /**
5276
+ * Create a DataTables Api instance, with the currently selected tables for
5277
+ * the Api's context.
5278
+ * @param {boolean} [traditional=false] Set the API instance's context to be
5279
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5280
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5281
+ * or if all tables captured in the jQuery object should be used.
5282
+ * @return {DataTables.Api}
5283
+ */
5284
+ this.api = function ( traditional )
5285
+ {
5286
+ return traditional ?
5287
+ new _Api(
5288
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5289
+ ) :
5290
+ new _Api( this );
5291
+ };
5292
+
5293
+
5294
+ /**
5295
+ * Add a single new row or multiple rows of data to the table. Please note
5296
+ * that this is suitable for client-side processing only - if you are using
5297
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
5298
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
5299
+ * @param {array|object} data The data to be added to the table. This can be:
5300
+ * <ul>
5301
+ * <li>1D array of data - add a single row with the data provided</li>
5302
+ * <li>2D array of arrays - add multiple rows in a single call</li>
5303
+ * <li>object - data object when using <i>mData</i></li>
5304
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
5305
+ * </ul>
5306
+ * @param {bool} [redraw=true] redraw the table or not
5307
+ * @returns {array} An array of integers, representing the list of indexes in
5308
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5309
+ * the table.
5310
+ * @dtopt API
5311
+ * @deprecated Since v1.10
5312
+ *
5313
+ * @example
5314
+ * // Global var for counter
5315
+ * var giCount = 2;
5316
+ *
5317
+ * $(document).ready(function() {
5318
+ * $('#example').dataTable();
5319
+ * } );
5320
+ *
5321
+ * function fnClickAddRow() {
5322
+ * $('#example').dataTable().fnAddData( [
5323
+ * giCount+".1",
5324
+ * giCount+".2",
5325
+ * giCount+".3",
5326
+ * giCount+".4" ]
5327
+ * );
5328
+ *
5329
+ * giCount++;
5330
+ * }
5331
+ */
5332
+ this.fnAddData = function( data, redraw )
5333
+ {
5334
+ var api = this.api( true );
5335
+
5336
+ /* Check if we want to add multiple rows or not */
5337
+ var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5338
+ api.rows.add( data ) :
5339
+ api.row.add( data );
5340
+
5341
+ if ( redraw === undefined || redraw ) {
5342
+ api.draw();
5343
+ }
5344
+
5345
+ return rows.flatten().toArray();
5346
+ };
5347
+
5348
+
5349
+ /**
5350
+ * This function will make DataTables recalculate the column sizes, based on the data
5351
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5352
+ * through the sWidth parameter). This can be useful when the width of the table's
5353
+ * parent element changes (for example a window resize).
5354
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5355
+ * @dtopt API
5356
+ * @deprecated Since v1.10
5357
+ *
5358
+ * @example
5359
+ * $(document).ready(function() {
5360
+ * var oTable = $('#example').dataTable( {
5361
+ * "sScrollY": "200px",
5362
+ * "bPaginate": false
5363
+ * } );
5364
+ *
5365
+ * $(window).bind('resize', function () {
5366
+ * oTable.fnAdjustColumnSizing();
5367
+ * } );
5368
+ * } );
5369
+ */
5370
+ this.fnAdjustColumnSizing = function ( bRedraw )
5371
+ {
5372
+ var api = this.api( true ).columns.adjust();
5373
+ var settings = api.settings()[0];
5374
+ var scroll = settings.oScroll;
5375
+
5376
+ if ( bRedraw === undefined || bRedraw ) {
5377
+ api.draw( false );
5378
+ }
5379
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5380
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5381
+ _fnScrollDraw( settings );
5382
+ }
5383
+ };
5384
+
5385
+
5386
+ /**
5387
+ * Quickly and simply clear a table
5388
+ * @param {bool} [bRedraw=true] redraw the table or not
5389
+ * @dtopt API
5390
+ * @deprecated Since v1.10
5391
+ *
5392
+ * @example
5393
+ * $(document).ready(function() {
5394
+ * var oTable = $('#example').dataTable();
5395
+ *
5396
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5397
+ * oTable.fnClearTable();
5398
+ * } );
5399
+ */
5400
+ this.fnClearTable = function( bRedraw )
5401
+ {
5402
+ var api = this.api( true ).clear();
5403
+
5404
+ if ( bRedraw === undefined || bRedraw ) {
5405
+ api.draw();
5406
+ }
5407
+ };
5408
+
5409
+
5410
+ /**
5411
+ * The exact opposite of 'opening' a row, this function will close any rows which
5412
+ * are currently 'open'.
5413
+ * @param {node} nTr the table row to 'close'
5414
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
5415
+ * @dtopt API
5416
+ * @deprecated Since v1.10
5417
+ *
5418
+ * @example
5419
+ * $(document).ready(function() {
5420
+ * var oTable;
5421
+ *
5422
+ * // 'open' an information row when a row is clicked on
5423
+ * $('#example tbody tr').click( function () {
5424
+ * if ( oTable.fnIsOpen(this) ) {
5425
+ * oTable.fnClose( this );
5426
+ * } else {
5427
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5428
+ * }
5429
+ * } );
5430
+ *
5431
+ * oTable = $('#example').dataTable();
5432
+ * } );
5433
+ */
5434
+ this.fnClose = function( nTr )
5435
+ {
5436
+ this.api( true ).row( nTr ).child.hide();
5437
+ };
5438
+
5439
+
5440
+ /**
5441
+ * Remove a row for the table
5442
+ * @param {mixed} target The index of the row from aoData to be deleted, or
5443
+ * the TR element you want to delete
5444
+ * @param {function|null} [callBack] Callback function
5445
+ * @param {bool} [redraw=true] Redraw the table or not
5446
+ * @returns {array} The row that was deleted
5447
+ * @dtopt API
5448
+ * @deprecated Since v1.10
5449
+ *
5450
+ * @example
5451
+ * $(document).ready(function() {
5452
+ * var oTable = $('#example').dataTable();
5453
+ *
5454
+ * // Immediately remove the first row
5455
+ * oTable.fnDeleteRow( 0 );
5456
+ * } );
5457
+ */
5458
+ this.fnDeleteRow = function( target, callback, redraw )
5459
+ {
5460
+ var api = this.api( true );
5461
+ var rows = api.rows( target );
5462
+ var settings = rows.settings()[0];
5463
+ var data = settings.aoData[ rows[0][0] ];
5464
+
5465
+ rows.remove();
5466
+
5467
+ if ( callback ) {
5468
+ callback.call( this, settings, data );
5469
+ }
5470
+
5471
+ if ( redraw === undefined || redraw ) {
5472
+ api.draw();
5473
+ }
5474
+
5475
+ return data;
5476
+ };
5477
+
5478
+
5479
+ /**
5480
+ * Restore the table to it's original state in the DOM by removing all of DataTables
5481
+ * enhancements, alterations to the DOM structure of the table and event listeners.
5482
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
5483
+ * @dtopt API
5484
+ * @deprecated Since v1.10
5485
+ *
5486
+ * @example
5487
+ * $(document).ready(function() {
5488
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5489
+ * var oTable = $('#example').dataTable();
5490
+ * oTable.fnDestroy();
5491
+ * } );
5492
+ */
5493
+ this.fnDestroy = function ( remove )
5494
+ {
5495
+ this.api( true ).destroy( remove );
5496
+ };
5497
+
5498
+
5499
+ /**
5500
+ * Redraw the table
5501
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5502
+ * @dtopt API
5503
+ * @deprecated Since v1.10
5504
+ *
5505
+ * @example
5506
+ * $(document).ready(function() {
5507
+ * var oTable = $('#example').dataTable();
5508
+ *
5509
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5510
+ * oTable.fnDraw();
5511
+ * } );
5512
+ */
5513
+ this.fnDraw = function( complete )
5514
+ {
5515
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
5516
+ // into account the new data, but can old position.
5517
+ this.api( true ).draw( ! complete );
5518
+ };
5519
+
5520
+
5521
+ /**
5522
+ * Filter the input based on data
5523
+ * @param {string} sInput String to filter the table on
5524
+ * @param {int|null} [iColumn] Column to limit filtering to
5525
+ * @param {bool} [bRegex=false] Treat as regular expression or not
5526
+ * @param {bool} [bSmart=true] Perform smart filtering or not
5527
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5528
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5529
+ * @dtopt API
5530
+ * @deprecated Since v1.10
5531
+ *
5532
+ * @example
5533
+ * $(document).ready(function() {
5534
+ * var oTable = $('#example').dataTable();
5535
+ *
5536
+ * // Sometime later - filter...
5537
+ * oTable.fnFilter( 'test string' );
5538
+ * } );
5539
+ */
5540
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5541
+ {
5542
+ var api = this.api( true );
5543
+
5544
+ if ( iColumn === null || iColumn === undefined ) {
5545
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5546
+ }
5547
+ else {
5548
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5549
+ }
5550
+
5551
+ api.draw();
5552
+ };
5553
+
5554
+
5555
+ /**
5556
+ * Get the data for the whole table, an individual row or an individual cell based on the
5557
+ * provided parameters.
5558
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5559
+ * a TR node then the data source for the whole row will be returned. If given as a
5560
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
5561
+ * cell returned. If given as an integer, then this is treated as the aoData internal
5562
+ * data index for the row (see fnGetPosition) and the data for that row used.
5563
+ * @param {int} [col] Optional column index that you want the data of.
5564
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5565
+ * returned. If mRow is defined, just data for that row, and is iCol is
5566
+ * defined, only data for the designated cell is returned.
5567
+ * @dtopt API
5568
+ * @deprecated Since v1.10
5569
+ *
5570
+ * @example
5571
+ * // Row data
5572
+ * $(document).ready(function() {
5573
+ * oTable = $('#example').dataTable();
5574
+ *
5575
+ * oTable.$('tr').click( function () {
5576
+ * var data = oTable.fnGetData( this );
5577
+ * // ... do something with the array / object of data for the row
5578
+ * } );
5579
+ * } );
5580
+ *
5581
+ * @example
5582
+ * // Individual cell data
5583
+ * $(document).ready(function() {
5584
+ * oTable = $('#example').dataTable();
5585
+ *
5586
+ * oTable.$('td').click( function () {
5587
+ * var sData = oTable.fnGetData( this );
5588
+ * alert( 'The cell clicked on had the value of '+sData );
5589
+ * } );
5590
+ * } );
5591
+ */
5592
+ this.fnGetData = function( src, col )
5593
+ {
5594
+ var api = this.api( true );
5595
+
5596
+ if ( src !== undefined ) {
5597
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5598
+
5599
+ return col !== undefined || type == 'td' || type == 'th' ?
5600
+ api.cell( src, col ).data() :
5601
+ api.row( src ).data() || null;
5602
+ }
5603
+
5604
+ return api.data().toArray();
5605
+ };
5606
+
5607
+
5608
+ /**
5609
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
5610
+ * typically want to use the '$' API method in preference to this as it is more
5611
+ * flexible.
5612
+ * @param {int} [iRow] Optional row index for the TR element you want
5613
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5614
+ * in the table's body, or iRow is defined, just the TR element requested.
5615
+ * @dtopt API
5616
+ * @deprecated Since v1.10
5617
+ *
5618
+ * @example
5619
+ * $(document).ready(function() {
5620
+ * var oTable = $('#example').dataTable();
5621
+ *
5622
+ * // Get the nodes from the table
5623
+ * var nNodes = oTable.fnGetNodes( );
5624
+ * } );
5625
+ */
5626
+ this.fnGetNodes = function( iRow )
5627
+ {
5628
+ var api = this.api( true );
5629
+
5630
+ return iRow !== undefined ?
5631
+ api.row( iRow ).node() :
5632
+ api.rows().nodes().flatten().toArray();
5633
+ };
5634
+
5635
+
5636
+ /**
5637
+ * Get the array indexes of a particular cell from it's DOM element
5638
+ * and column index including hidden columns
5639
+ * @param {node} node this can either be a TR, TD or TH in the table's body
5640
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
5641
+ * if given as a cell, an array of [row index, column index (visible),
5642
+ * column index (all)] is given.
5643
+ * @dtopt API
5644
+ * @deprecated Since v1.10
5645
+ *
5646
+ * @example
5647
+ * $(document).ready(function() {
5648
+ * $('#example tbody td').click( function () {
5649
+ * // Get the position of the current data from the node
5650
+ * var aPos = oTable.fnGetPosition( this );
5651
+ *
5652
+ * // Get the data array for this row
5653
+ * var aData = oTable.fnGetData( aPos[0] );
5654
+ *
5655
+ * // Update the data array and return the value
5656
+ * aData[ aPos[1] ] = 'clicked';
5657
+ * this.innerHTML = 'clicked';
5658
+ * } );
5659
+ *
5660
+ * // Init DataTables
5661
+ * oTable = $('#example').dataTable();
5662
+ * } );
5663
+ */
5664
+ this.fnGetPosition = function( node )
5665
+ {
5666
+ var api = this.api( true );
5667
+ var nodeName = node.nodeName.toUpperCase();
5668
+
5669
+ if ( nodeName == 'TR' ) {
5670
+ return api.row( node ).index();
5671
+ }
5672
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5673
+ var cell = api.cell( node ).index();
5674
+
5675
+ return [
5676
+ cell.row,
5677
+ cell.columnVisible,
5678
+ cell.column
5679
+ ];
5680
+ }
5681
+ return null;
5682
+ };
5683
+
5684
+
5685
+ /**
5686
+ * Check to see if a row is 'open' or not.
5687
+ * @param {node} nTr the table row to check
5688
+ * @returns {boolean} true if the row is currently open, false otherwise
5689
+ * @dtopt API
5690
+ * @deprecated Since v1.10
5691
+ *
5692
+ * @example
5693
+ * $(document).ready(function() {
5694
+ * var oTable;
5695
+ *
5696
+ * // 'open' an information row when a row is clicked on
5697
+ * $('#example tbody tr').click( function () {
5698
+ * if ( oTable.fnIsOpen(this) ) {
5699
+ * oTable.fnClose( this );
5700
+ * } else {
5701
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5702
+ * }
5703
+ * } );
5704
+ *
5705
+ * oTable = $('#example').dataTable();
5706
+ * } );
5707
+ */
5708
+ this.fnIsOpen = function( nTr )
5709
+ {
5710
+ return this.api( true ).row( nTr ).child.isShown();
5711
+ };
5712
+
5713
+
5714
+ /**
5715
+ * This function will place a new row directly after a row which is currently
5716
+ * on display on the page, with the HTML contents that is passed into the
5717
+ * function. This can be used, for example, to ask for confirmation that a
5718
+ * particular record should be deleted.
5719
+ * @param {node} nTr The table row to 'open'
5720
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
5721
+ * @param {string} sClass Class to give the new TD cell
5722
+ * @returns {node} The row opened. Note that if the table row passed in as the
5723
+ * first parameter, is not found in the table, this method will silently
5724
+ * return.
5725
+ * @dtopt API
5726
+ * @deprecated Since v1.10
5727
+ *
5728
+ * @example
5729
+ * $(document).ready(function() {
5730
+ * var oTable;
5731
+ *
5732
+ * // 'open' an information row when a row is clicked on
5733
+ * $('#example tbody tr').click( function () {
5734
+ * if ( oTable.fnIsOpen(this) ) {
5735
+ * oTable.fnClose( this );
5736
+ * } else {
5737
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5738
+ * }
5739
+ * } );
5740
+ *
5741
+ * oTable = $('#example').dataTable();
5742
+ * } );
5743
+ */
5744
+ this.fnOpen = function( nTr, mHtml, sClass )
5745
+ {
5746
+ return this.api( true )
5747
+ .row( nTr )
5748
+ .child( mHtml, sClass )
5749
+ .show()
5750
+ .child()[0];
5751
+ };
5752
+
5753
+
5754
+ /**
5755
+ * Change the pagination - provides the internal logic for pagination in a simple API
5756
+ * function. With this function you can have a DataTables table go to the next,
5757
+ * previous, first or last pages.
5758
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5759
+ * or page number to jump to (integer), note that page 0 is the first page.
5760
+ * @param {bool} [bRedraw=true] Redraw the table or not
5761
+ * @dtopt API
5762
+ * @deprecated Since v1.10
5763
+ *
5764
+ * @example
5765
+ * $(document).ready(function() {
5766
+ * var oTable = $('#example').dataTable();
5767
+ * oTable.fnPageChange( 'next' );
5768
+ * } );
5769
+ */
5770
+ this.fnPageChange = function ( mAction, bRedraw )
5771
+ {
5772
+ var api = this.api( true ).page( mAction );
5773
+
5774
+ if ( bRedraw === undefined || bRedraw ) {
5775
+ api.draw(false);
5776
+ }
5777
+ };
5778
+
5779
+
5780
+ /**
5781
+ * Show a particular column
5782
+ * @param {int} iCol The column whose display should be changed
5783
+ * @param {bool} bShow Show (true) or hide (false) the column
5784
+ * @param {bool} [bRedraw=true] Redraw the table or not
5785
+ * @dtopt API
5786
+ * @deprecated Since v1.10
5787
+ *
5788
+ * @example
5789
+ * $(document).ready(function() {
5790
+ * var oTable = $('#example').dataTable();
5791
+ *
5792
+ * // Hide the second column after initialisation
5793
+ * oTable.fnSetColumnVis( 1, false );
5794
+ * } );
5795
+ */
5796
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5797
+ {
5798
+ var api = this.api( true ).column( iCol ).visible( bShow );
5799
+
5800
+ if ( bRedraw === undefined || bRedraw ) {
5801
+ api.columns.adjust().draw();
5802
+ }
5803
+ };
5804
+
5805
+
5806
+ /**
5807
+ * Get the settings for a particular table for external manipulation
5808
+ * @returns {object} DataTables settings object. See
5809
+ * {@link DataTable.models.oSettings}
5810
+ * @dtopt API
5811
+ * @deprecated Since v1.10
5812
+ *
5813
+ * @example
5814
+ * $(document).ready(function() {
5815
+ * var oTable = $('#example').dataTable();
5816
+ * var oSettings = oTable.fnSettings();
5817
+ *
5818
+ * // Show an example parameter from the settings
5819
+ * alert( oSettings._iDisplayStart );
5820
+ * } );
5821
+ */
5822
+ this.fnSettings = function()
5823
+ {
5824
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
5825
+ };
5826
+
5827
+
5828
+ /**
5829
+ * Sort the table by a particular column
5830
+ * @param {int} iCol the data index to sort on. Note that this will not match the
5831
+ * 'display index' if you have hidden data entries
5832
+ * @dtopt API
5833
+ * @deprecated Since v1.10
5834
+ *
5835
+ * @example
5836
+ * $(document).ready(function() {
5837
+ * var oTable = $('#example').dataTable();
5838
+ *
5839
+ * // Sort immediately with columns 0 and 1
5840
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5841
+ * } );
5842
+ */
5843
+ this.fnSort = function( aaSort )
5844
+ {
5845
+ this.api( true ).order( aaSort ).draw();
5846
+ };
5847
+
5848
+
5849
+ /**
5850
+ * Attach a sort listener to an element for a given column
5851
+ * @param {node} nNode the element to attach the sort listener to
5852
+ * @param {int} iColumn the column that a click on this node will sort on
5853
+ * @param {function} [fnCallback] callback function when sort is run
5854
+ * @dtopt API
5855
+ * @deprecated Since v1.10
5856
+ *
5857
+ * @example
5858
+ * $(document).ready(function() {
5859
+ * var oTable = $('#example').dataTable();
5860
+ *
5861
+ * // Sort on column 1, when 'sorter' is clicked on
5862
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5863
+ * } );
5864
+ */
5865
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
5866
+ {
5867
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
5868
+ };
5869
+
5870
+
5871
+ /**
5872
+ * Update a table cell or row - this method will accept either a single value to
5873
+ * update the cell with, an array of values with one element for each column or
5874
+ * an object in the same format as the original data source. The function is
5875
+ * self-referencing in order to make the multi column updates easier.
5876
+ * @param {object|array|string} mData Data to update the cell/row with
5877
+ * @param {node|int} mRow TR element you want to update or the aoData index
5878
+ * @param {int} [iColumn] The column to update, give as null or undefined to
5879
+ * update a whole row.
5880
+ * @param {bool} [bRedraw=true] Redraw the table or not
5881
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
5882
+ * @returns {int} 0 on success, 1 on error
5883
+ * @dtopt API
5884
+ * @deprecated Since v1.10
5885
+ *
5886
+ * @example
5887
+ * $(document).ready(function() {
5888
+ * var oTable = $('#example').dataTable();
5889
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5890
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5891
+ * } );
5892
+ */
5893
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5894
+ {
5895
+ var api = this.api( true );
5896
+
5897
+ if ( iColumn === undefined || iColumn === null ) {
5898
+ api.row( mRow ).data( mData );
5899
+ }
5900
+ else {
5901
+ api.cell( mRow, iColumn ).data( mData );
5902
+ }
5903
+
5904
+ if ( bAction === undefined || bAction ) {
5905
+ api.columns.adjust();
5906
+ }
5907
+
5908
+ if ( bRedraw === undefined || bRedraw ) {
5909
+ api.draw();
5910
+ }
5911
+ return 0;
5912
+ };
5913
+
5914
+
5915
+ /**
5916
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
5917
+ * to ensure compatibility.
5918
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
5919
+ * formats "X" and "X.Y" are also acceptable.
5920
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
5921
+ * version, or false if this version of DataTales is not suitable
5922
+ * @method
5923
+ * @dtopt API
5924
+ * @deprecated Since v1.10
5925
+ *
5926
+ * @example
5927
+ * $(document).ready(function() {
5928
+ * var oTable = $('#example').dataTable();
5929
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
5930
+ * } );
5931
+ */
5932
+ this.fnVersionCheck = _ext.fnVersionCheck;
5933
+
5934
+
5935
+ var _that = this;
5936
+ var emptyInit = options === undefined;
5937
+ var len = this.length;
5938
+
5939
+ if ( emptyInit ) {
5940
+ options = {};
5941
+ }
5942
+
5943
+ this.oApi = this.internal = _ext.internal;
5944
+
5945
+ // Extend with old style plug-in API methods
5946
+ for ( var fn in DataTable.ext.internal ) {
5947
+ if ( fn ) {
5948
+ this[fn] = _fnExternApiFunc(fn);
5949
+ }
5950
+ }
5951
+
5952
+ this.each(function() {
5953
+ // For each initialisation we want to give it a clean initialisation
5954
+ // object that can be bashed around
5955
+ var o = {};
5956
+ var oInit = len > 1 ? // optimisation for single table case
5957
+ _fnExtend( o, options, true ) :
5958
+ options;
5959
+
5960
+ /*global oInit,_that,emptyInit*/
5961
+ var i=0, iLen, j, jLen, k, kLen;
5962
+ var sId = this.getAttribute( 'id' );
5963
+ var bInitHandedOff = false;
5964
+ var defaults = DataTable.defaults;
5965
+
5966
+
5967
+ /* Sanity check */
5968
+ if ( this.nodeName.toLowerCase() != 'table' )
5969
+ {
5970
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
5971
+ return;
5972
+ }
5973
+
5974
+ /* Backwards compatibility for the defaults */
5975
+ _fnCompatOpts( defaults );
5976
+ _fnCompatCols( defaults.column );
5977
+
5978
+ /* Convert the camel-case defaults to Hungarian */
5979
+ _fnCamelToHungarian( defaults, defaults, true );
5980
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
5981
+
5982
+ /* Setting up the initialisation object */
5983
+ _fnCamelToHungarian( defaults, oInit );
5984
+
5985
+ /* Check to see if we are re-initialising a table */
5986
+ var allSettings = DataTable.settings;
5987
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
5988
+ {
5989
+ /* Base check on table node */
5990
+ if ( allSettings[i].nTable == this )
5991
+ {
5992
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
5993
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
5994
+
5995
+ if ( emptyInit || bRetrieve )
5996
+ {
5997
+ return allSettings[i].oInstance;
5998
+ }
5999
+ else if ( bDestroy )
6000
+ {
6001
+ allSettings[i].oInstance.fnDestroy();
6002
+ break;
6003
+ }
6004
+ else
6005
+ {
6006
+ _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6007
+ return;
6008
+ }
6009
+ }
6010
+
6011
+ /* If the element we are initialising has the same ID as a table which was previously
6012
+ * initialised, but the table nodes don't match (from before) then we destroy the old
6013
+ * instance by simply deleting it. This is under the assumption that the table has been
6014
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6015
+ */
6016
+ if ( allSettings[i].sTableId == this.id )
6017
+ {
6018
+ allSettings.splice( i, 1 );
6019
+ break;
6020
+ }
6021
+ }
6022
+
6023
+ /* Ensure the table has an ID - required for accessibility */
6024
+ if ( sId === null || sId === "" )
6025
+ {
6026
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
6027
+ this.id = sId;
6028
+ }
6029
+
6030
+ /* Create the settings object for this table and set some of the default parameters */
6031
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6032
+ "nTable": this,
6033
+ "oApi": _that.internal,
6034
+ "oInit": oInit,
6035
+ "sDestroyWidth": $(this)[0].style.width,
6036
+ "sInstance": sId,
6037
+ "sTableId": sId
6038
+ } );
6039
+ allSettings.push( oSettings );
6040
+
6041
+ // Need to add the instance after the instance after the settings object has been added
6042
+ // to the settings array, so we can self reference the table instance if more than one
6043
+ oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6044
+
6045
+ // Backwards compatibility, before we apply all the defaults
6046
+ _fnCompatOpts( oInit );
6047
+
6048
+ if ( oInit.oLanguage )
6049
+ {
6050
+ _fnLanguageCompat( oInit.oLanguage );
6051
+ }
6052
+
6053
+ // If the length menu is given, but the init display length is not, use the length menu
6054
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6055
+ {
6056
+ oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6057
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6058
+ }
6059
+
6060
+ // Apply the defaults and init options to make a single init object will all
6061
+ // options defined from defaults and instance options.
6062
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6063
+
6064
+
6065
+ // Map the initialisation options onto the settings object
6066
+ _fnMap( oSettings.oFeatures, oInit, [
6067
+ "bPaginate",
6068
+ "bLengthChange",
6069
+ "bFilter",
6070
+ "bSort",
6071
+ "bSortMulti",
6072
+ "bInfo",
6073
+ "bProcessing",
6074
+ "bAutoWidth",
6075
+ "bSortClasses",
6076
+ "bServerSide",
6077
+ "bDeferRender"
6078
+ ] );
6079
+ _fnMap( oSettings, oInit, [
6080
+ "asStripeClasses",
6081
+ "ajax",
6082
+ "fnServerData",
6083
+ "fnFormatNumber",
6084
+ "sServerMethod",
6085
+ "aaSorting",
6086
+ "aaSortingFixed",
6087
+ "aLengthMenu",
6088
+ "sPaginationType",
6089
+ "sAjaxSource",
6090
+ "sAjaxDataProp",
6091
+ "iStateDuration",
6092
+ "sDom",
6093
+ "bSortCellsTop",
6094
+ "iTabIndex",
6095
+ "fnStateLoadCallback",
6096
+ "fnStateSaveCallback",
6097
+ "renderer",
6098
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
6099
+ [ "oSearch", "oPreviousSearch" ],
6100
+ [ "aoSearchCols", "aoPreSearchCols" ],
6101
+ [ "iDisplayLength", "_iDisplayLength" ],
6102
+ [ "bJQueryUI", "bJUI" ]
6103
+ ] );
6104
+ _fnMap( oSettings.oScroll, oInit, [
6105
+ [ "sScrollX", "sX" ],
6106
+ [ "sScrollXInner", "sXInner" ],
6107
+ [ "sScrollY", "sY" ],
6108
+ [ "bScrollCollapse", "bCollapse" ]
6109
+ ] );
6110
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6111
+
6112
+ /* Callback functions which are array driven */
6113
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6114
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6115
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6116
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6117
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6118
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6119
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6120
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6121
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6122
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6123
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6124
+
6125
+ var oClasses = oSettings.oClasses;
6126
+
6127
+ // @todo Remove in 1.11
6128
+ if ( oInit.bJQueryUI )
6129
+ {
6130
+ /* Use the JUI classes object for display. You could clone the oStdClasses object if
6131
+ * you want to have multiple tables with multiple independent classes
6132
+ */
6133
+ $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6134
+
6135
+ if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6136
+ {
6137
+ /* Set the DOM to use a layout suitable for jQuery UI's theming */
6138
+ oSettings.sDom = '<"H"lfr>t<"F"ip>';
6139
+ }
6140
+
6141
+ if ( ! oSettings.renderer ) {
6142
+ oSettings.renderer = 'jqueryui';
6143
+ }
6144
+ else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6145
+ oSettings.renderer.header = 'jqueryui';
6146
+ }
6147
+ }
6148
+ else
6149
+ {
6150
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6151
+ }
6152
+ $(this).addClass( oClasses.sTable );
6153
+
6154
+ /* Calculate the scroll bar width and cache it for use later on */
6155
+ if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6156
+ {
6157
+ oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6158
+ }
6159
+ if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6160
+ oSettings.oScroll.sX = '100%';
6161
+ }
6162
+
6163
+ if ( oSettings.iInitDisplayStart === undefined )
6164
+ {
6165
+ /* Display start point, taking into account the save saving */
6166
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
6167
+ oSettings._iDisplayStart = oInit.iDisplayStart;
6168
+ }
6169
+
6170
+ if ( oInit.iDeferLoading !== null )
6171
+ {
6172
+ oSettings.bDeferLoading = true;
6173
+ var tmp = $.isArray( oInit.iDeferLoading );
6174
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6175
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6176
+ }
6177
+
6178
+ /* Language definitions */
6179
+ if ( oInit.oLanguage.sUrl !== "" )
6180
+ {
6181
+ /* Get the language definitions from a file - because this Ajax call makes the language
6182
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
6183
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6184
+ */
6185
+ oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6186
+ $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6187
+ _fnLanguageCompat( json );
6188
+ _fnCamelToHungarian( defaults.oLanguage, json );
6189
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6190
+ _fnInitialise( oSettings );
6191
+ } );
6192
+ bInitHandedOff = true;
6193
+ }
6194
+ else
6195
+ {
6196
+ $.extend( true, oSettings.oLanguage, oInit.oLanguage );
6197
+ }
6198
+
6199
+
6200
+ /*
6201
+ * Stripes
6202
+ */
6203
+ if ( oInit.asStripeClasses === null )
6204
+ {
6205
+ oSettings.asStripeClasses =[
6206
+ oClasses.sStripeOdd,
6207
+ oClasses.sStripeEven
6208
+ ];
6209
+ }
6210
+
6211
+ /* Remove row stripe classes if they are already on the table row */
6212
+ var stripeClasses = oSettings.asStripeClasses;
6213
+ var rowOne = $('tbody tr:eq(0)', this);
6214
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6215
+ return rowOne.hasClass(el);
6216
+ } ) ) !== -1 ) {
6217
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6218
+ oSettings.asDestroyStripes = stripeClasses.slice();
6219
+ }
6220
+
6221
+ /*
6222
+ * Columns
6223
+ * See if we should load columns automatically or use defined ones
6224
+ */
6225
+ var anThs = [];
6226
+ var aoColumnsInit;
6227
+ var nThead = this.getElementsByTagName('thead');
6228
+ if ( nThead.length !== 0 )
6229
+ {
6230
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6231
+ anThs = _fnGetUniqueThs( oSettings );
6232
+ }
6233
+
6234
+ /* If not given a column array, generate one with nulls */
6235
+ if ( oInit.aoColumns === null )
6236
+ {
6237
+ aoColumnsInit = [];
6238
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6239
+ {
6240
+ aoColumnsInit.push( null );
6241
+ }
6242
+ }
6243
+ else
6244
+ {
6245
+ aoColumnsInit = oInit.aoColumns;
6246
+ }
6247
+
6248
+ /* Add the columns */
6249
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6250
+ {
6251
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6252
+ }
6253
+
6254
+ /* Apply the column definitions */
6255
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6256
+ _fnColumnOptions( oSettings, iCol, oDef );
6257
+ } );
6258
+
6259
+ /* HTML5 attribute detection - build an mData object automatically if the
6260
+ * attributes are found
6261
+ */
6262
+ if ( rowOne.length ) {
6263
+ var a = function ( cell, name ) {
6264
+ return cell.getAttribute( 'data-'+name ) ? name : null;
6265
+ };
6266
+
6267
+ $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6268
+ var col = oSettings.aoColumns[i];
6269
+
6270
+ if ( col.mData === i ) {
6271
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
6272
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
6273
+
6274
+ if ( sort !== null || filter !== null ) {
6275
+ col.mData = {
6276
+ _: i+'.display',
6277
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
6278
+ type: sort !== null ? i+'.@data-'+sort : undefined,
6279
+ filter: filter !== null ? i+'.@data-'+filter : undefined
6280
+ };
6281
+
6282
+ _fnColumnOptions( oSettings, i );
6283
+ }
6284
+ }
6285
+ } );
6286
+ }
6287
+
6288
+ var features = oSettings.oFeatures;
6289
+
6290
+ /* Must be done after everything which can be overridden by the state saving! */
6291
+ if ( oInit.bStateSave )
6292
+ {
6293
+ features.bStateSave = true;
6294
+ _fnLoadState( oSettings, oInit );
6295
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6296
+ }
6297
+
6298
+
6299
+ /*
6300
+ * Sorting
6301
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
6302
+ */
6303
+
6304
+ // If aaSorting is not defined, then we use the first indicator in asSorting
6305
+ // in case that has been altered, so the default sort reflects that option
6306
+ if ( oInit.aaSorting === undefined )
6307
+ {
6308
+ var sorting = oSettings.aaSorting;
6309
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6310
+ {
6311
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6312
+ }
6313
+ }
6314
+
6315
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
6316
+ * account, and also will apply sorting disabled classes if disabled
6317
+ */
6318
+ _fnSortingClasses( oSettings );
6319
+
6320
+ if ( features.bSort )
6321
+ {
6322
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6323
+ if ( oSettings.bSorted ) {
6324
+ var aSort = _fnSortFlatten( oSettings );
6325
+ var sortedColumns = {};
6326
+
6327
+ $.each( aSort, function (i, val) {
6328
+ sortedColumns[ val.src ] = val.dir;
6329
+ } );
6330
+
6331
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6332
+ _fnSortAria( oSettings );
6333
+ }
6334
+ } );
6335
+ }
6336
+
6337
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6338
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6339
+ _fnSortingClasses( oSettings );
6340
+ }
6341
+ }, 'sc' );
6342
+
6343
+
6344
+ /*
6345
+ * Final init
6346
+ * Cache the header, body and footer as required, creating them if needed
6347
+ */
6348
+
6349
+ /* Browser support detection */
6350
+ _fnBrowserDetect( oSettings );
6351
+
6352
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6353
+ var captions = $(this).children('caption').each( function () {
6354
+ this._captionSide = $(this).css('caption-side');
6355
+ } );
6356
+
6357
+ var thead = $(this).children('thead');
6358
+ if ( thead.length === 0 )
6359
+ {
6360
+ thead = $('<thead/>').appendTo(this);
6361
+ }
6362
+ oSettings.nTHead = thead[0];
6363
+
6364
+ var tbody = $(this).children('tbody');
6365
+ if ( tbody.length === 0 )
6366
+ {
6367
+ tbody = $('<tbody/>').appendTo(this);
6368
+ }
6369
+ oSettings.nTBody = tbody[0];
6370
+
6371
+ var tfoot = $(this).children('tfoot');
6372
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6373
+ {
6374
+ // If we are a scrolling table, and no footer has been given, then we need to create
6375
+ // a tfoot element for the caption element to be appended to
6376
+ tfoot = $('<tfoot/>').appendTo(this);
6377
+ }
6378
+
6379
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6380
+ $(this).addClass( oClasses.sNoFooter );
6381
+ }
6382
+ else if ( tfoot.length > 0 ) {
6383
+ oSettings.nTFoot = tfoot[0];
6384
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6385
+ }
6386
+
6387
+ /* Check if there is data passing into the constructor */
6388
+ if ( oInit.aaData )
6389
+ {
6390
+ for ( i=0 ; i<oInit.aaData.length ; i++ )
6391
+ {
6392
+ _fnAddData( oSettings, oInit.aaData[ i ] );
6393
+ }
6394
+ }
6395
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6396
+ {
6397
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
6398
+ * source since there is no point in reading the DOM data if we are then going
6399
+ * to replace it with Ajax data
6400
+ */
6401
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6402
+ }
6403
+
6404
+ /* Copy the data index array */
6405
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6406
+
6407
+ /* Initialisation complete - table can be drawn */
6408
+ oSettings.bInitialised = true;
6409
+
6410
+ /* Check if we need to initialise the table (it might not have been handed off to the
6411
+ * language processor)
6412
+ */
6413
+ if ( bInitHandedOff === false )
6414
+ {
6415
+ _fnInitialise( oSettings );
6416
+ }
6417
+ } );
6418
+ _that = null;
6419
+ return this;
6420
+ };
6421
+
6422
+
6423
+
6424
+ /**
6425
+ * Computed structure of the DataTables API, defined by the options passed to
6426
+ * `DataTable.Api.register()` when building the API.
6427
+ *
6428
+ * The structure is built in order to speed creation and extension of the Api
6429
+ * objects since the extensions are effectively pre-parsed.
6430
+ *
6431
+ * The array is an array of objects with the following structure, where this
6432
+ * base array represents the Api prototype base:
6433
+ *
6434
+ * [
6435
+ * {
6436
+ * name: 'data' -- string - Property name
6437
+ * val: function () {}, -- function - Api method (or undefined if just an object
6438
+ * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6439
+ * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6440
+ * },
6441
+ * {
6442
+ * name: 'row'
6443
+ * val: {},
6444
+ * methodExt: [ ... ],
6445
+ * propExt: [
6446
+ * {
6447
+ * name: 'data'
6448
+ * val: function () {},
6449
+ * methodExt: [ ... ],
6450
+ * propExt: [ ... ]
6451
+ * },
6452
+ * ...
6453
+ * ]
6454
+ * }
6455
+ * ]
6456
+ *
6457
+ * @type {Array}
6458
+ * @ignore
6459
+ */
6460
+ var __apiStruct = [];
6461
+
6462
+
6463
+ /**
6464
+ * `Array.prototype` reference.
6465
+ *
6466
+ * @type object
6467
+ * @ignore
6468
+ */
6469
+ var __arrayProto = Array.prototype;
6470
+
6471
+
6472
+ /**
6473
+ * Abstraction for `context` parameter of the `Api` constructor to allow it to
6474
+ * take several different forms for ease of use.
6475
+ *
6476
+ * Each of the input parameter types will be converted to a DataTables settings
6477
+ * object where possible.
6478
+ *
6479
+ * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6480
+ * of:
6481
+ *
6482
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6483
+ * with be found and used.
6484
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6485
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6486
+ * * `object` - DataTables settings object
6487
+ * * `DataTables.Api` - API instance
6488
+ * @return {array|null} Matching DataTables settings objects. `null` or
6489
+ * `undefined` is returned if no matching DataTable is found.
6490
+ * @ignore
6491
+ */
6492
+ var _toSettings = function ( mixed )
6493
+ {
6494
+ var idx, jq;
6495
+ var settings = DataTable.settings;
6496
+ var tables = $.map( settings, function (el, i) {
6497
+ return el.nTable;
6498
+ } );
6499
+
6500
+ if ( ! mixed ) {
6501
+ return [];
6502
+ }
6503
+ else if ( mixed.nTable && mixed.oApi ) {
6504
+ // DataTables settings object
6505
+ return [ mixed ];
6506
+ }
6507
+ else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6508
+ // Table node
6509
+ idx = $.inArray( mixed, tables );
6510
+ return idx !== -1 ? [ settings[idx] ] : null;
6511
+ }
6512
+ else if ( mixed && typeof mixed.settings === 'function' ) {
6513
+ return mixed.settings().toArray();
6514
+ }
6515
+ else if ( typeof mixed === 'string' ) {
6516
+ // jQuery selector
6517
+ jq = $(mixed);
6518
+ }
6519
+ else if ( mixed instanceof $ ) {
6520
+ // jQuery object (also DataTables instance)
6521
+ jq = mixed;
6522
+ }
6523
+
6524
+ if ( jq ) {
6525
+ return jq.map( function(i) {
6526
+ idx = $.inArray( this, tables );
6527
+ return idx !== -1 ? settings[idx] : null;
6528
+ } ).toArray();
6529
+ }
6530
+ };
6531
+
6532
+
6533
+ /**
6534
+ * DataTables API class - used to control and interface with one or more
6535
+ * DataTables enhanced tables.
6536
+ *
6537
+ * The API class is heavily based on jQuery, presenting a chainable interface
6538
+ * that you can use to interact with tables. Each instance of the API class has
6539
+ * a "context" - i.e. the tables that it will operate on. This could be a single
6540
+ * table, all tables on a page or a sub-set thereof.
6541
+ *
6542
+ * Additionally the API is designed to allow you to easily work with the data in
6543
+ * the tables, retrieving and manipulating it as required. This is done by
6544
+ * presenting the API class as an array like interface. The contents of the
6545
+ * array depend upon the actions requested by each method (for example
6546
+ * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6547
+ * return an array of objects or arrays depending upon your table's
6548
+ * configuration). The API object has a number of array like methods (`push`,
6549
+ * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6550
+ * `unique` etc) to assist your working with the data held in a table.
6551
+ *
6552
+ * Most methods (those which return an Api instance) are chainable, which means
6553
+ * the return from a method call also has all of the methods available that the
6554
+ * top level object had. For example, these two calls are equivalent:
6555
+ *
6556
+ * // Not chained
6557
+ * api.row.add( {...} );
6558
+ * api.draw();
6559
+ *
6560
+ * // Chained
6561
+ * api.row.add( {...} ).draw();
6562
+ *
6563
+ * @class DataTable.Api
6564
+ * @param {array|object|string|jQuery} context DataTable identifier. This is
6565
+ * used to define which DataTables enhanced tables this API will operate on.
6566
+ * Can be one of:
6567
+ *
6568
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6569
+ * with be found and used.
6570
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6571
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6572
+ * * `object` - DataTables settings object
6573
+ * @param {array} [data] Data to initialise the Api instance with.
6574
+ *
6575
+ * @example
6576
+ * // Direct initialisation during DataTables construction
6577
+ * var api = $('#example').DataTable();
6578
+ *
6579
+ * @example
6580
+ * // Initialisation using a DataTables jQuery object
6581
+ * var api = $('#example').dataTable().api();
6582
+ *
6583
+ * @example
6584
+ * // Initialisation as a constructor
6585
+ * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6586
+ */
6587
+ _Api = function ( context, data )
6588
+ {
6589
+ if ( ! this instanceof _Api ) {
6590
+ throw 'DT API must be constructed as a new object';
6591
+ // or should it do the 'new' for the caller?
6592
+ // return new _Api.apply( this, arguments );
6593
+ }
6594
+
6595
+ var settings = [];
6596
+ var ctxSettings = function ( o ) {
6597
+ var a = _toSettings( o );
6598
+ if ( a ) {
6599
+ settings.push.apply( settings, a );
6600
+ }
6601
+ };
6602
+
6603
+ if ( $.isArray( context ) ) {
6604
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6605
+ ctxSettings( context[i] );
6606
+ }
6607
+ }
6608
+ else {
6609
+ ctxSettings( context );
6610
+ }
6611
+
6612
+ // Remove duplicates
6613
+ this.context = _unique( settings );
6614
+
6615
+ // Initial data
6616
+ if ( data ) {
6617
+ this.push.apply( this, data.toArray ? data.toArray() : data );
6618
+ }
6619
+
6620
+ // selector
6621
+ this.selector = {
6622
+ rows: null,
6623
+ cols: null,
6624
+ opts: null
6625
+ };
6626
+
6627
+ _Api.extend( this, this, __apiStruct );
6628
+ };
6629
+
6630
+ DataTable.Api = _Api;
6631
+
6632
+ _Api.prototype = /** @lends DataTables.Api */{
6633
+ /**
6634
+ * Return a new Api instance, comprised of the data held in the current
6635
+ * instance, join with the other array(s) and/or value(s).
6636
+ *
6637
+ * An alias for `Array.prototype.concat`.
6638
+ *
6639
+ * @type method
6640
+ * @param {*} value1 Arrays and/or values to concatenate.
6641
+ * @param {*} [...] Additional arrays and/or values to concatenate.
6642
+ * @returns {DataTables.Api} New API instance, comprising of the combined
6643
+ * array.
6644
+ */
6645
+ concat: __arrayProto.concat,
6646
+
6647
+
6648
+ context: [], // array of table settings objects
6649
+
6650
+
6651
+ each: function ( fn )
6652
+ {
6653
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
6654
+ fn.call( this, this[i], i, this );
6655
+ }
6656
+
6657
+ return this;
6658
+ },
6659
+
6660
+
6661
+ eq: function ( idx )
6662
+ {
6663
+ var ctx = this.context;
6664
+
6665
+ return ctx.length > idx ?
6666
+ new _Api( ctx[idx], this[idx] ) :
6667
+ null;
6668
+ },
6669
+
6670
+
6671
+ filter: function ( fn )
6672
+ {
6673
+ var a = [];
6674
+
6675
+ if ( __arrayProto.filter ) {
6676
+ a = __arrayProto.filter.call( this, fn, this );
6677
+ }
6678
+ else {
6679
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6680
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6681
+ if ( fn.call( this, this[i], i, this ) ) {
6682
+ a.push( this[i] );
6683
+ }
6684
+ }
6685
+ }
6686
+
6687
+ return new _Api( this.context, a );
6688
+ },
6689
+
6690
+
6691
+ flatten: function ()
6692
+ {
6693
+ var a = [];
6694
+ return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6695
+ },
6696
+
6697
+
6698
+ join: __arrayProto.join,
6699
+
6700
+
6701
+ indexOf: __arrayProto.indexOf || function (obj, start)
6702
+ {
6703
+ for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6704
+ if ( this[i] === obj ) {
6705
+ return i;
6706
+ }
6707
+ }
6708
+ return -1;
6709
+ },
6710
+
6711
+ // Internal only at the moment - relax?
6712
+ iterator: function ( flatten, type, fn ) {
6713
+ var
6714
+ a = [], ret,
6715
+ i, ien, j, jen,
6716
+ context = this.context,
6717
+ rows, items, item,
6718
+ selector = this.selector;
6719
+
6720
+ // Argument shifting
6721
+ if ( typeof flatten === 'string' ) {
6722
+ fn = type;
6723
+ type = flatten;
6724
+ flatten = false;
6725
+ }
6726
+
6727
+ for ( i=0, ien=context.length ; i<ien ; i++ ) {
6728
+ if ( type === 'table' ) {
6729
+ ret = fn( context[i], i );
6730
+
6731
+ if ( ret !== undefined ) {
6732
+ a.push( ret );
6733
+ }
6734
+ }
6735
+ else if ( type === 'columns' || type === 'rows' ) {
6736
+ // this has same length as context - one entry for each table
6737
+ ret = fn( context[i], this[i], i );
6738
+
6739
+ if ( ret !== undefined ) {
6740
+ a.push( ret );
6741
+ }
6742
+ }
6743
+ else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6744
+ // columns and rows share the same structure.
6745
+ // 'this' is an array of column indexes for each context
6746
+ items = this[i];
6747
+
6748
+ if ( type === 'column-rows' ) {
6749
+ rows = _selector_row_indexes( context[i], selector.opts );
6750
+ }
6751
+
6752
+ for ( j=0, jen=items.length ; j<jen ; j++ ) {
6753
+ item = items[j];
6754
+
6755
+ if ( type === 'cell' ) {
6756
+ ret = fn( context[i], item.row, item.column, i, j );
6757
+ }
6758
+ else {
6759
+ ret = fn( context[i], item, i, j, rows );
6760
+ }
6761
+
6762
+ if ( ret !== undefined ) {
6763
+ a.push( ret );
6764
+ }
6765
+ }
6766
+ }
6767
+ }
6768
+
6769
+ if ( a.length ) {
6770
+ var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6771
+ var apiSelector = api.selector;
6772
+ apiSelector.rows = selector.rows;
6773
+ apiSelector.cols = selector.cols;
6774
+ apiSelector.opts = selector.opts;
6775
+ return api;
6776
+ }
6777
+ return this;
6778
+ },
6779
+
6780
+
6781
+ lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6782
+ {
6783
+ // Bit cheeky...
6784
+ return this.indexOf.apply( this.toArray.reverse(), arguments );
6785
+ },
6786
+
6787
+
6788
+ length: 0,
6789
+
6790
+
6791
+ map: function ( fn )
6792
+ {
6793
+ var a = [];
6794
+
6795
+ if ( __arrayProto.map ) {
6796
+ a = __arrayProto.map.call( this, fn, this );
6797
+ }
6798
+ else {
6799
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6800
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6801
+ a.push( fn.call( this, this[i], i ) );
6802
+ }
6803
+ }
6804
+
6805
+ return new _Api( this.context, a );
6806
+ },
6807
+
6808
+
6809
+ pluck: function ( prop )
6810
+ {
6811
+ return this.map( function ( el ) {
6812
+ return el[ prop ];
6813
+ } );
6814
+ },
6815
+
6816
+ pop: __arrayProto.pop,
6817
+
6818
+
6819
+ push: __arrayProto.push,
6820
+
6821
+
6822
+ // Does not return an API instance
6823
+ reduce: __arrayProto.reduce || function ( fn, init )
6824
+ {
6825
+ return _fnReduce( this, fn, init, 0, this.length, 1 );
6826
+ },
6827
+
6828
+
6829
+ reduceRight: __arrayProto.reduceRight || function ( fn, init )
6830
+ {
6831
+ return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6832
+ },
6833
+
6834
+
6835
+ reverse: __arrayProto.reverse,
6836
+
6837
+
6838
+ // Object with rows, columns and opts
6839
+ selector: null,
6840
+
6841
+
6842
+ shift: __arrayProto.shift,
6843
+
6844
+
6845
+ sort: __arrayProto.sort, // ? name - order?
6846
+
6847
+
6848
+ splice: __arrayProto.splice,
6849
+
6850
+
6851
+ toArray: function ()
6852
+ {
6853
+ return __arrayProto.slice.call( this );
6854
+ },
6855
+
6856
+
6857
+ to$: function ()
6858
+ {
6859
+ return $( this );
6860
+ },
6861
+
6862
+
6863
+ toJQuery: function ()
6864
+ {
6865
+ return $( this );
6866
+ },
6867
+
6868
+
6869
+ unique: function ()
6870
+ {
6871
+ return new _Api( this.context, _unique(this) );
6872
+ },
6873
+
6874
+
6875
+ unshift: __arrayProto.unshift
6876
+ };
6877
+
6878
+
6879
+ _Api.extend = function ( scope, obj, ext )
6880
+ {
6881
+ // Only extend API instances and static properties of the API
6882
+ if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6883
+ return;
6884
+ }
6885
+
6886
+ var
6887
+ i, ien,
6888
+ j, jen,
6889
+ struct, inner,
6890
+ methodScoping = function ( scope, fn, struc ) {
6891
+ return function () {
6892
+ var ret = fn.apply( scope, arguments );
6893
+
6894
+ // Method extension
6895
+ _Api.extend( ret, ret, struc.methodExt );
6896
+ return ret;
6897
+ };
6898
+ };
6899
+
6900
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6901
+ struct = ext[i];
6902
+
6903
+ // Value
6904
+ obj[ struct.name ] = typeof struct.val === 'function' ?
6905
+ methodScoping( scope, struct.val, struct ) :
6906
+ $.isPlainObject( struct.val ) ?
6907
+ {} :
6908
+ struct.val;
6909
+
6910
+ obj[ struct.name ].__dt_wrapper = true;
6911
+
6912
+ // Property extension
6913
+ _Api.extend( scope, obj[ struct.name ], struct.propExt );
6914
+ }
6915
+ };
6916
+
6917
+
6918
+ // @todo - Is there need for an augment function?
6919
+ // _Api.augment = function ( inst, name )
6920
+ // {
6921
+ // // Find src object in the structure from the name
6922
+ // var parts = name.split('.');
6923
+
6924
+ // _Api.extend( inst, obj );
6925
+ // };
6926
+
6927
+
6928
+ // [
6929
+ // {
6930
+ // name: 'data' -- string - Property name
6931
+ // val: function () {}, -- function - Api method (or undefined if just an object
6932
+ // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6933
+ // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6934
+ // },
6935
+ // {
6936
+ // name: 'row'
6937
+ // val: {},
6938
+ // methodExt: [ ... ],
6939
+ // propExt: [
6940
+ // {
6941
+ // name: 'data'
6942
+ // val: function () {},
6943
+ // methodExt: [ ... ],
6944
+ // propExt: [ ... ]
6945
+ // },
6946
+ // ...
6947
+ // ]
6948
+ // }
6949
+ // ]
6950
+
6951
+ _Api.register = _api_register = function ( name, val )
6952
+ {
6953
+ if ( $.isArray( name ) ) {
6954
+ for ( var j=0, jen=name.length ; j<jen ; j++ ) {
6955
+ _Api.register( name[j], val );
6956
+ }
6957
+ return;
6958
+ }
6959
+
6960
+ var
6961
+ i, ien,
6962
+ heir = name.split('.'),
6963
+ struct = __apiStruct,
6964
+ key, method;
6965
+
6966
+ var find = function ( src, name ) {
6967
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
6968
+ if ( src[i].name === name ) {
6969
+ return src[i];
6970
+ }
6971
+ }
6972
+ return null;
6973
+ };
6974
+
6975
+ for ( i=0, ien=heir.length ; i<ien ; i++ ) {
6976
+ method = heir[i].indexOf('()') !== -1;
6977
+ key = method ?
6978
+ heir[i].replace('()', '') :
6979
+ heir[i];
6980
+
6981
+ var src = find( struct, key );
6982
+ if ( ! src ) {
6983
+ src = {
6984
+ name: key,
6985
+ val: {},
6986
+ methodExt: [],
6987
+ propExt: []
6988
+ };
6989
+ struct.push( src );
6990
+ }
6991
+
6992
+ if ( i === ien-1 ) {
6993
+ src.val = val;
6994
+ }
6995
+ else {
6996
+ struct = method ?
6997
+ src.methodExt :
6998
+ src.propExt;
6999
+ }
7000
+ }
7001
+ };
7002
+
7003
+
7004
+ _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7005
+ _Api.register( pluralName, val );
7006
+
7007
+ _Api.register( singularName, function () {
7008
+ var ret = val.apply( this, arguments );
7009
+
7010
+ if ( ret === this ) {
7011
+ // Returned item is the API instance that was passed in, return it
7012
+ return this;
7013
+ }
7014
+ else if ( ret instanceof _Api ) {
7015
+ // New API instance returned, want the value from the first item
7016
+ // in the returned array for the singular result.
7017
+ return ret.length ?
7018
+ $.isArray( ret[0] ) ?
7019
+ new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7020
+ ret[0] :
7021
+ undefined;
7022
+ }
7023
+
7024
+ // Non-API return - just fire it back
7025
+ return ret;
7026
+ } );
7027
+ };
7028
+
7029
+
7030
+ /**
7031
+ * Selector for HTML tables. Apply the given selector to the give array of
7032
+ * DataTables settings objects.
7033
+ *
7034
+ * @param {string|integer} [selector] jQuery selector string or integer
7035
+ * @param {array} Array of DataTables settings objects to be filtered
7036
+ * @return {array}
7037
+ * @ignore
7038
+ */
7039
+ var __table_selector = function ( selector, a )
7040
+ {
7041
+ // Integer is used to pick out a table by index
7042
+ if ( typeof selector === 'number' ) {
7043
+ return [ a[ selector ] ];
7044
+ }
7045
+
7046
+ // Perform a jQuery selector on the table nodes
7047
+ var nodes = $.map( a, function (el, i) {
7048
+ return el.nTable;
7049
+ } );
7050
+
7051
+ return $(nodes)
7052
+ .filter( selector )
7053
+ .map( function (i) {
7054
+ // Need to translate back from the table node to the settings
7055
+ var idx = $.inArray( this, nodes );
7056
+ return a[ idx ];
7057
+ } )
7058
+ .toArray();
7059
+ };
7060
+
7061
+
7062
+
7063
+ /**
7064
+ * Context selector for the API's context (i.e. the tables the API instance
7065
+ * refers to.
7066
+ *
7067
+ * @name DataTable.Api#tables
7068
+ * @param {string|integer} [selector] Selector to pick which tables the iterator
7069
+ * should operate on. If not given, all tables in the current context are
7070
+ * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7071
+ * select multiple tables or as an integer to select a single table.
7072
+ * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7073
+ */
7074
+ _api_register( 'tables()', function ( selector ) {
7075
+ // A new instance is created if there was a selector specified
7076
+ return selector ?
7077
+ new _Api( __table_selector( selector, this.context ) ) :
7078
+ this;
7079
+ } );
7080
+
7081
+
7082
+ _api_register( 'table()', function ( selector ) {
7083
+ var tables = this.tables( selector );
7084
+ var ctx = tables.context;
7085
+
7086
+ // Truncate to the first matched table
7087
+ return ctx.length ?
7088
+ new _Api( ctx[0] ) :
7089
+ tables;
7090
+ } );
7091
+
7092
+
7093
+ _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7094
+ return this.iterator( 'table', function ( ctx ) {
7095
+ return ctx.nTable;
7096
+ } );
7097
+ } );
7098
+
7099
+
7100
+ _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7101
+ return this.iterator( 'table', function ( ctx ) {
7102
+ return ctx.nTBody;
7103
+ } );
7104
+ } );
7105
+
7106
+
7107
+ _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7108
+ return this.iterator( 'table', function ( ctx ) {
7109
+ return ctx.nTHead;
7110
+ } );
7111
+ } );
7112
+
7113
+
7114
+ _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7115
+ return this.iterator( 'table', function ( ctx ) {
7116
+ return ctx.nTFoot;
7117
+ } );
7118
+ } );
7119
+
7120
+
7121
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7122
+ return this.iterator( 'table', function ( ctx ) {
7123
+ return ctx.nTableWrapper;
7124
+ } );
7125
+ } );
7126
+
7127
+
7128
+
7129
+ /**
7130
+ * Redraw the tables in the current context.
7131
+ *
7132
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7133
+ * position. A full re-sort and re-filter is performed when this method is
7134
+ * called, which is why the pagination reset is the default action.
7135
+ * @returns {DataTables.Api} this
7136
+ */
7137
+ _api_register( 'draw()', function ( resetPaging ) {
7138
+ return this.iterator( 'table', function ( settings ) {
7139
+ _fnReDraw( settings, resetPaging===false );
7140
+ } );
7141
+ } );
7142
+
7143
+
7144
+
7145
+ /**
7146
+ * Get the current page index.
7147
+ *
7148
+ * @return {integer} Current page index (zero based)
7149
+ *//**
7150
+ * Set the current page.
7151
+ *
7152
+ * Note that if you attempt to show a page which does not exist, DataTables will
7153
+ * not throw an error, but rather reset the paging.
7154
+ *
7155
+ * @param {integer|string} action The paging action to take. This can be one of:
7156
+ * * `integer` - The page index to jump to
7157
+ * * `string` - An action to take:
7158
+ * * `first` - Jump to first page.
7159
+ * * `next` - Jump to the next page
7160
+ * * `previous` - Jump to previous page
7161
+ * * `last` - Jump to the last page.
7162
+ * @returns {DataTables.Api} this
7163
+ */
7164
+ _api_register( 'page()', function ( action ) {
7165
+ if ( action === undefined ) {
7166
+ return this.page.info().page; // not an expensive call
7167
+ }
7168
+
7169
+ // else, have an action to take on all tables
7170
+ return this.iterator( 'table', function ( settings ) {
7171
+ _fnPageChange( settings, action );
7172
+ } );
7173
+ } );
7174
+
7175
+
7176
+ /**
7177
+ * Paging information for the first table in the current context.
7178
+ *
7179
+ * If you require paging information for another table, use the `table()` method
7180
+ * with a suitable selector.
7181
+ *
7182
+ * @return {object} Object with the following properties set:
7183
+ * * `page` - Current page index (zero based - i.e. the first page is `0`)
7184
+ * * `pages` - Total number of pages
7185
+ * * `start` - Display index for the first record shown on the current page
7186
+ * * `end` - Display index for the last record shown on the current page
7187
+ * * `length` - Display length (number of records). Note that generally `start
7188
+ * + length = end`, but this is not always true, for example if there are
7189
+ * only 2 records to show on the final page, with a length of 10.
7190
+ * * `recordsTotal` - Full data set length
7191
+ * * `recordsDisplay` - Data set length once the current filtering criterion
7192
+ * are applied.
7193
+ */
7194
+ _api_register( 'page.info()', function ( action ) {
7195
+ if ( this.context.length === 0 ) {
7196
+ return undefined;
7197
+ }
7198
+
7199
+ var
7200
+ settings = this.context[0],
7201
+ start = settings._iDisplayStart,
7202
+ len = settings._iDisplayLength,
7203
+ visRecords = settings.fnRecordsDisplay(),
7204
+ all = len === -1;
7205
+
7206
+ return {
7207
+ "page": all ? 0 : Math.floor( start / len ),
7208
+ "pages": all ? 1 : Math.ceil( visRecords / len ),
7209
+ "start": start,
7210
+ "end": settings.fnDisplayEnd(),
7211
+ "length": len,
7212
+ "recordsTotal": settings.fnRecordsTotal(),
7213
+ "recordsDisplay": visRecords
7214
+ };
7215
+ } );
7216
+
7217
+
7218
+ /**
7219
+ * Get the current page length.
7220
+ *
7221
+ * @return {integer} Current page length. Note `-1` indicates that all records
7222
+ * are to be shown.
7223
+ *//**
7224
+ * Set the current page length.
7225
+ *
7226
+ * @param {integer} Page length to set. Use `-1` to show all records.
7227
+ * @returns {DataTables.Api} this
7228
+ */
7229
+ _api_register( 'page.len()', function ( len ) {
7230
+ // Note that we can't call this function 'length()' because `length`
7231
+ // is a Javascript property of functions which defines how many arguments
7232
+ // the function expects.
7233
+ if ( len === undefined ) {
7234
+ return this.context.length !== 0 ?
7235
+ this.context[0]._iDisplayLength :
7236
+ undefined;
7237
+ }
7238
+
7239
+ // else, set the page length
7240
+ return this.iterator( 'table', function ( settings ) {
7241
+ _fnLengthChange( settings, len );
7242
+ } );
7243
+ } );
7244
+
7245
+
7246
+
7247
+ var __reload = function ( settings, holdPosition, callback ) {
7248
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7249
+ _fnReDraw( settings, holdPosition );
7250
+ }
7251
+ else {
7252
+ // Trigger xhr
7253
+ _fnProcessingDisplay( settings, true );
7254
+
7255
+ _fnBuildAjax( settings, [], function( json ) {
7256
+ _fnClearTable( settings );
7257
+
7258
+ var data = _fnAjaxDataSrc( settings, json );
7259
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7260
+ _fnAddData( settings, data[i] );
7261
+ }
7262
+
7263
+ _fnReDraw( settings, holdPosition );
7264
+ _fnProcessingDisplay( settings, false );
7265
+ } );
7266
+ }
7267
+
7268
+ // Use the draw event to trigger a callback, regardless of if it is an async
7269
+ // or sync draw
7270
+ if ( callback ) {
7271
+ var api = new _Api( settings );
7272
+
7273
+ api.one( 'draw', function () {
7274
+ callback( api.ajax.json() );
7275
+ } );
7276
+ }
7277
+ };
7278
+
7279
+
7280
+ /**
7281
+ * Get the JSON response from the last Ajax request that DataTables made to the
7282
+ * server. Note that this returns the JSON from the first table in the current
7283
+ * context.
7284
+ *
7285
+ * @return {object} JSON received from the server.
7286
+ */
7287
+ _api_register( 'ajax.json()', function () {
7288
+ var ctx = this.context;
7289
+
7290
+ if ( ctx.length > 0 ) {
7291
+ return ctx[0].json;
7292
+ }
7293
+
7294
+ // else return undefined;
7295
+ } );
7296
+
7297
+
7298
+ /**
7299
+ * Get the data submitted in the last Ajax request
7300
+ */
7301
+ _api_register( 'ajax.params()', function () {
7302
+ var ctx = this.context;
7303
+
7304
+ if ( ctx.length > 0 ) {
7305
+ return ctx[0].oAjaxData;
7306
+ }
7307
+
7308
+ // else return undefined;
7309
+ } );
7310
+
7311
+
7312
+ /**
7313
+ * Reload tables from the Ajax data source. Note that this function will
7314
+ * automatically re-draw the table when the remote data has been loaded.
7315
+ *
7316
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7317
+ * position. A full re-sort and re-filter is performed when this method is
7318
+ * called, which is why the pagination reset is the default action.
7319
+ * @returns {DataTables.Api} this
7320
+ */
7321
+ _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7322
+ return this.iterator( 'table', function (settings) {
7323
+ __reload( settings, resetPaging===false, callback );
7324
+ } );
7325
+ } );
7326
+
7327
+
7328
+ /**
7329
+ * Get the current Ajax URL. Note that this returns the URL from the first
7330
+ * table in the current context.
7331
+ *
7332
+ * @return {string} Current Ajax source URL
7333
+ *//**
7334
+ * Set the Ajax URL. Note that this will set the URL for all tables in the
7335
+ * current context.
7336
+ *
7337
+ * @param {string} url URL to set.
7338
+ * @returns {DataTables.Api} this
7339
+ */
7340
+ _api_register( 'ajax.url()', function ( url ) {
7341
+ var ctx = this.context;
7342
+
7343
+ if ( url === undefined ) {
7344
+ // get
7345
+ if ( ctx.length === 0 ) {
7346
+ return undefined;
7347
+ }
7348
+ ctx = ctx[0];
7349
+
7350
+ return ctx.ajax ?
7351
+ $.isPlainObject( ctx.ajax ) ?
7352
+ ctx.ajax.url :
7353
+ ctx.ajax :
7354
+ ctx.sAjaxSource;
7355
+ }
7356
+
7357
+ // set
7358
+ return this.iterator( 'table', function ( settings ) {
7359
+ if ( $.isPlainObject( settings.ajax ) ) {
7360
+ settings.ajax.url = url;
7361
+ }
7362
+ else {
7363
+ settings.ajax = url;
7364
+ }
7365
+ // No need to consider sAjaxSource here since DataTables gives priority
7366
+ // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7367
+ // value of `sAjaxSource` redundant.
7368
+ } );
7369
+ } );
7370
+
7371
+
7372
+ /**
7373
+ * Load data from the newly set Ajax URL. Note that this method is only
7374
+ * available when `ajax.url()` is used to set a URL. Additionally, this method
7375
+ * has the same effect as calling `ajax.reload()` but is provided for
7376
+ * convenience when setting a new URL. Like `ajax.reload()` it will
7377
+ * automatically redraw the table once the remote data has been loaded.
7378
+ *
7379
+ * @returns {DataTables.Api} this
7380
+ */
7381
+ _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7382
+ // Same as a reload, but makes sense to present it for easy access after a
7383
+ // url change
7384
+ return this.iterator( 'table', function ( ctx ) {
7385
+ __reload( ctx, resetPaging===false, callback );
7386
+ } );
7387
+ } );
7388
+
7389
+
7390
+
7391
+
7392
+ var _selector_run = function ( selector, select )
7393
+ {
7394
+ var
7395
+ out = [], res,
7396
+ a, i, ien, j, jen;
7397
+
7398
+ // Can't just check for isArray here, as an API or jQuery instance might be
7399
+ // given with their array like look
7400
+ if ( ! selector || typeof selector === 'string' || selector.length === undefined ) {
7401
+ selector = [ selector ];
7402
+ }
7403
+
7404
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7405
+ a = selector[i] && selector[i].split ?
7406
+ selector[i].split(',') :
7407
+ [ selector[i] ];
7408
+
7409
+ for ( j=0, jen=a.length ; j<jen ; j++ ) {
7410
+ res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7411
+
7412
+ if ( res && res.length ) {
7413
+ out.push.apply( out, res );
7414
+ }
7415
+ }
7416
+ }
7417
+
7418
+ return out;
7419
+ };
7420
+
7421
+
7422
+ var _selector_opts = function ( opts )
7423
+ {
7424
+ if ( ! opts ) {
7425
+ opts = {};
7426
+ }
7427
+
7428
+ // Backwards compatibility for 1.9- which used the terminology filter rather
7429
+ // than search
7430
+ if ( opts.filter && ! opts.search ) {
7431
+ opts.search = opts.filter;
7432
+ }
7433
+
7434
+ return {
7435
+ search: opts.search || 'none',
7436
+ order: opts.order || 'current',
7437
+ page: opts.page || 'all'
7438
+ };
7439
+ };
7440
+
7441
+
7442
+ var _selector_first = function ( inst )
7443
+ {
7444
+ // Reduce the API instance to the first item found
7445
+ for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7446
+ if ( inst[i].length > 0 ) {
7447
+ // Assign the first element to the first item in the instance
7448
+ // and truncate the instance and context
7449
+ inst[0] = inst[i];
7450
+ inst.length = 1;
7451
+ inst.context = [ inst.context[i] ];
7452
+
7453
+ return inst;
7454
+ }
7455
+ }
7456
+
7457
+ // Not found - return an empty instance
7458
+ inst.length = 0;
7459
+ return inst;
7460
+ };
7461
+
7462
+
7463
+ var _selector_row_indexes = function ( settings, opts )
7464
+ {
7465
+ var
7466
+ i, ien, tmp, a=[],
7467
+ displayFiltered = settings.aiDisplay,
7468
+ displayMaster = settings.aiDisplayMaster;
7469
+
7470
+ var
7471
+ search = opts.search, // none, applied, removed
7472
+ order = opts.order, // applied, current, index (original - compatibility with 1.9)
7473
+ page = opts.page; // all, current
7474
+
7475
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7476
+ // In server-side processing mode, most options are irrelevant since
7477
+ // rows not shown don't exist and the index order is the applied order
7478
+ // Removed is a special case - for consistency just return an empty
7479
+ // array
7480
+ return search === 'removed' ?
7481
+ [] :
7482
+ _range( 0, displayMaster.length );
7483
+ }
7484
+ else if ( page == 'current' ) {
7485
+ // Current page implies that order=current and fitler=applied, since it is
7486
+ // fairly senseless otherwise, regardless of what order and search actually
7487
+ // are
7488
+ for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7489
+ a.push( displayFiltered[i] );
7490
+ }
7491
+ }
7492
+ else if ( order == 'current' || order == 'applied' ) {
7493
+ a = search == 'none' ?
7494
+ displayMaster.slice() : // no search
7495
+ search == 'applied' ?
7496
+ displayFiltered.slice() : // applied search
7497
+ $.map( displayMaster, function (el, i) { // removed search
7498
+ return $.inArray( el, displayFiltered ) === -1 ? el : null;
7499
+ } );
7500
+ }
7501
+ else if ( order == 'index' || order == 'original' ) {
7502
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7503
+ if ( search == 'none' ) {
7504
+ a.push( i );
7505
+ }
7506
+ else { // applied | removed
7507
+ tmp = $.inArray( i, displayFiltered );
7508
+
7509
+ if ((tmp === -1 && search == 'removed') ||
7510
+ (tmp >= 0 && search == 'applied') )
7511
+ {
7512
+ a.push( i );
7513
+ }
7514
+ }
7515
+ }
7516
+ }
7517
+
7518
+ return a;
7519
+ };
7520
+
7521
+
7522
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7523
+ * Rows
7524
+ *
7525
+ * {} - no selector - use all available rows
7526
+ * {integer} - row aoData index
7527
+ * {node} - TR node
7528
+ * {string} - jQuery selector to apply to the TR elements
7529
+ * {array} - jQuery array of nodes, or simply an array of TR nodes
7530
+ *
7531
+ */
7532
+
7533
+
7534
+ var __row_selector = function ( settings, selector, opts )
7535
+ {
7536
+ return _selector_run( selector, function ( sel ) {
7537
+ var selInt = _intVal( sel );
7538
+
7539
+ // Short cut - selector is a number and no options provided (default is
7540
+ // all records, so no need to check if the index is in there, since it
7541
+ // must be - dev error if the index doesn't exist).
7542
+ if ( selInt !== null && ! opts ) {
7543
+ return [ selInt ];
7544
+ }
7545
+
7546
+ var rows = _selector_row_indexes( settings, opts );
7547
+
7548
+ if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7549
+ // Selector - integer
7550
+ return [ selInt ];
7551
+ }
7552
+ else if ( ! sel ) {
7553
+ // Selector - none
7554
+ return rows;
7555
+ }
7556
+
7557
+ // Get nodes in the order from the `rows` array (can't use `pluck`) @todo - use pluck_order
7558
+ var nodes = [];
7559
+ for ( var i=0, ien=rows.length ; i<ien ; i++ ) {
7560
+ nodes.push( settings.aoData[ rows[i] ].nTr );
7561
+ }
7562
+
7563
+ if ( sel.nodeName ) {
7564
+ // Selector - node
7565
+ if ( $.inArray( sel, nodes ) !== -1 ) {
7566
+ return [ sel._DT_RowIndex ];// sel is a TR node that is in the table
7567
+ // and DataTables adds a prop for fast lookup
7568
+ }
7569
+ }
7570
+
7571
+ // Selector - jQuery selector string, array of nodes or jQuery object/
7572
+ // As jQuery's .filter() allows jQuery objects to be passed in filter,
7573
+ // it also allows arrays, so this will cope with all three options
7574
+ return $(nodes)
7575
+ .filter( sel )
7576
+ .map( function () {
7577
+ return this._DT_RowIndex;
7578
+ } )
7579
+ .toArray();
7580
+ } );
7581
+ };
7582
+
7583
+
7584
+ /**
7585
+ *
7586
+ */
7587
+ _api_register( 'rows()', function ( selector, opts ) {
7588
+ // argument shifting
7589
+ if ( selector === undefined ) {
7590
+ selector = '';
7591
+ }
7592
+ else if ( $.isPlainObject( selector ) ) {
7593
+ opts = selector;
7594
+ selector = '';
7595
+ }
7596
+
7597
+ opts = _selector_opts( opts );
7598
+
7599
+ var inst = this.iterator( 'table', function ( settings ) {
7600
+ return __row_selector( settings, selector, opts );
7601
+ } );
7602
+
7603
+ // Want argument shifting here and in __row_selector?
7604
+ inst.selector.rows = selector;
7605
+ inst.selector.opts = opts;
7606
+
7607
+ return inst;
7608
+ } );
7609
+
7610
+
7611
+ _api_register( 'rows().nodes()', function () {
7612
+ return this.iterator( 'row', function ( settings, row ) {
7613
+ return settings.aoData[ row ].nTr || undefined;
7614
+ } );
7615
+ } );
7616
+
7617
+ _api_register( 'rows().data()', function () {
7618
+ return this.iterator( true, 'rows', function ( settings, rows ) {
7619
+ return _pluck_order( settings.aoData, rows, '_aData' );
7620
+ } );
7621
+ } );
7622
+
7623
+ _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7624
+ return this.iterator( 'row', function ( settings, row ) {
7625
+ var r = settings.aoData[ row ];
7626
+ return type === 'search' ? r._aFilterData : r._aSortData;
7627
+ } );
7628
+ } );
7629
+
7630
+ _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7631
+ return this.iterator( 'row', function ( settings, row ) {
7632
+ _fnInvalidateRow( settings, row, src );
7633
+ } );
7634
+ } );
7635
+
7636
+ _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7637
+ return this.iterator( 'row', function ( settings, row ) {
7638
+ return row;
7639
+ } );
7640
+ } );
7641
+
7642
+ _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7643
+ var that = this;
7644
+
7645
+ return this.iterator( 'row', function ( settings, row, thatIdx ) {
7646
+ var data = settings.aoData;
7647
+
7648
+ data.splice( row, 1 );
7649
+
7650
+ // Update the _DT_RowIndex parameter on all rows in the table
7651
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7652
+ if ( data[i].nTr !== null ) {
7653
+ data[i].nTr._DT_RowIndex = i;
7654
+ }
7655
+ }
7656
+
7657
+ // Remove the target row from the search array
7658
+ var displayIndex = $.inArray( row, settings.aiDisplay );
7659
+
7660
+ // Delete from the display arrays
7661
+ _fnDeleteIndex( settings.aiDisplayMaster, row );
7662
+ _fnDeleteIndex( settings.aiDisplay, row );
7663
+ _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7664
+
7665
+ // Check for an 'overflow' they case for displaying the table
7666
+ _fnLengthOverflow( settings );
7667
+ } );
7668
+ } );
7669
+
7670
+
7671
+ _api_register( 'rows.add()', function ( rows ) {
7672
+ var newRows = this.iterator( 'table', function ( settings ) {
7673
+ var row, i, ien;
7674
+ var out = [];
7675
+
7676
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7677
+ row = rows[i];
7678
+
7679
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7680
+ out.push( _fnAddTr( settings, row )[0] );
7681
+ }
7682
+ else {
7683
+ out.push( _fnAddData( settings, row ) );
7684
+ }
7685
+ }
7686
+
7687
+ return out;
7688
+ } );
7689
+
7690
+ // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7691
+ var modRows = this.rows( -1 );
7692
+ modRows.pop();
7693
+ modRows.push.apply( modRows, newRows.toArray() );
7694
+
7695
+ return modRows;
7696
+ } );
7697
+
7698
+
7699
+
7700
+
7701
+
7702
+ /**
7703
+ *
7704
+ */
7705
+ _api_register( 'row()', function ( selector, opts ) {
7706
+ return _selector_first( this.rows( selector, opts ) );
7707
+ } );
7708
+
7709
+
7710
+ _api_register( 'row().data()', function ( data ) {
7711
+ var ctx = this.context;
7712
+
7713
+ if ( data === undefined ) {
7714
+ // Get
7715
+ return ctx.length && this.length ?
7716
+ ctx[0].aoData[ this[0] ]._aData :
7717
+ undefined;
7718
+ }
7719
+
7720
+ // Set
7721
+ ctx[0].aoData[ this[0] ]._aData = data;
7722
+
7723
+ // Automatically invalidate
7724
+ _fnInvalidateRow( ctx[0], this[0], 'data' );
7725
+
7726
+ return this;
7727
+ } );
7728
+
7729
+
7730
+ _api_register( 'row().node()', function () {
7731
+ var ctx = this.context;
7732
+
7733
+ return ctx.length && this.length ?
7734
+ ctx[0].aoData[ this[0] ].nTr || null :
7735
+ null;
7736
+ } );
7737
+
7738
+
7739
+ _api_register( 'row.add()', function ( row ) {
7740
+ // Allow a jQuery object to be passed in - only a single row is added from
7741
+ // it though - the first element in the set
7742
+ if ( row instanceof $ && row.length ) {
7743
+ row = row[0];
7744
+ }
7745
+
7746
+ var rows = this.iterator( 'table', function ( settings ) {
7747
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7748
+ return _fnAddTr( settings, row )[0];
7749
+ }
7750
+ return _fnAddData( settings, row );
7751
+ } );
7752
+
7753
+ // Return an Api.rows() extended instance, with the newly added row selected
7754
+ return this.row( rows[0] );
7755
+ } );
7756
+
7757
+
7758
+
7759
+ var __details_add = function ( ctx, row, data, klass )
7760
+ {
7761
+ // Convert to array of TR elements
7762
+ var rows = [];
7763
+ var addRow = function ( r, k ) {
7764
+ // If we get a TR element, then just add it directly - up to the dev
7765
+ // to add the correct number of columns etc
7766
+ if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7767
+ rows.push( r );
7768
+ }
7769
+ else {
7770
+ // Otherwise create a row with a wrapper
7771
+ var created = $('<tr><td/></tr>').addClass( k );
7772
+ $('td', created)
7773
+ .addClass( k )
7774
+ .html( r )
7775
+ [0].colSpan = _fnVisbleColumns( ctx );
7776
+
7777
+ rows.push( created[0] );
7778
+ }
7779
+ };
7780
+
7781
+ if ( $.isArray( data ) || data instanceof $ ) {
7782
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7783
+ addRow( data[i], klass );
7784
+ }
7785
+ }
7786
+ else {
7787
+ addRow( data, klass );
7788
+ }
7789
+
7790
+ if ( row._details ) {
7791
+ row._details.remove();
7792
+ }
7793
+
7794
+ row._details = $(rows);
7795
+
7796
+ // If the children were already shown, that state should be retained
7797
+ if ( row._detailsShow ) {
7798
+ row._details.insertAfter( row.nTr );
7799
+ }
7800
+ };
7801
+
7802
+
7803
+ var __details_remove = function ( api )
7804
+ {
7805
+ var ctx = api.context;
7806
+
7807
+ if ( ctx.length && api.length ) {
7808
+ var row = ctx[0].aoData[ api[0] ];
7809
+
7810
+ if ( row._details ) {
7811
+ row._details.remove();
7812
+
7813
+ row._detailsShow = undefined;
7814
+ row._details = undefined;
7815
+ }
7816
+ }
7817
+ };
7818
+
7819
+
7820
+ var __details_display = function ( api, show ) {
7821
+ var ctx = api.context;
7822
+
7823
+ if ( ctx.length && api.length ) {
7824
+ var row = ctx[0].aoData[ api[0] ];
7825
+
7826
+ if ( row._details ) {
7827
+ row._detailsShow = show;
7828
+
7829
+ if ( show ) {
7830
+ row._details.insertAfter( row.nTr );
7831
+ }
7832
+ else {
7833
+ row._details.detach();
7834
+ }
7835
+
7836
+ __details_events( ctx[0] );
7837
+ }
7838
+ }
7839
+ };
7840
+
7841
+
7842
+ var __details_events = function ( settings )
7843
+ {
7844
+ var api = new _Api( settings );
7845
+ var namespace = '.dt.DT_details';
7846
+ var drawEvent = 'draw'+namespace;
7847
+ var colvisEvent = 'column-visibility'+namespace;
7848
+ var destroyEvent = 'destroy'+namespace;
7849
+ var data = settings.aoData;
7850
+
7851
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7852
+
7853
+ if ( _pluck( data, '_details' ).length > 0 ) {
7854
+ // On each draw, insert the required elements into the document
7855
+ api.on( drawEvent, function ( e, ctx ) {
7856
+ if ( settings !== ctx ) {
7857
+ return;
7858
+ }
7859
+
7860
+ api.rows( {page:'current'} ).eq(0).each( function (idx) {
7861
+ // Internal data grab
7862
+ var row = data[ idx ];
7863
+
7864
+ if ( row._detailsShow ) {
7865
+ row._details.insertAfter( row.nTr );
7866
+ }
7867
+ } );
7868
+ } );
7869
+
7870
+ // Column visibility change - update the colspan
7871
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7872
+ if ( settings !== ctx ) {
7873
+ return;
7874
+ }
7875
+
7876
+ // Update the colspan for the details rows (note, only if it already has
7877
+ // a colspan)
7878
+ var row, visible = _fnVisbleColumns( ctx );
7879
+
7880
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7881
+ row = data[i];
7882
+
7883
+ if ( row._details ) {
7884
+ row._details.children('td[colspan]').attr('colspan', visible );
7885
+ }
7886
+ }
7887
+ } );
7888
+
7889
+ // Table destroyed - nuke any child rows
7890
+ api.on( destroyEvent, function ( e, ctx ) {
7891
+ if ( settings !== ctx ) {
7892
+ return;
7893
+ }
7894
+
7895
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7896
+ if ( data[i]._details ) {
7897
+ __details_remove( data[i] );
7898
+ }
7899
+ }
7900
+ } );
7901
+ }
7902
+ };
7903
+
7904
+ // Strings for the method names to help minification
7905
+ var _emp = '';
7906
+ var _child_obj = _emp+'row().child';
7907
+ var _child_mth = _child_obj+'()';
7908
+
7909
+ // data can be:
7910
+ // tr
7911
+ // string
7912
+ // jQuery or array of any of the above
7913
+ _api_register( _child_mth, function ( data, klass ) {
7914
+ var ctx = this.context;
7915
+
7916
+ if ( data === undefined ) {
7917
+ // get
7918
+ return ctx.length && this.length ?
7919
+ ctx[0].aoData[ this[0] ]._details :
7920
+ undefined;
7921
+ }
7922
+ else if ( data === true ) {
7923
+ // show
7924
+ this.child.show();
7925
+ }
7926
+ else if ( data === false ) {
7927
+ // remove
7928
+ __details_remove( this );
7929
+ }
7930
+ else if ( ctx.length && this.length ) {
7931
+ // set
7932
+ __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
7933
+ }
7934
+
7935
+ return this;
7936
+ } );
7937
+
7938
+
7939
+ _api_register( [
7940
+ _child_obj+'.show()',
7941
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
7942
+ ], function ( show ) { // it returns an object and this method is not executed)
7943
+ __details_display( this, true );
7944
+ return this;
7945
+ } );
7946
+
7947
+
7948
+ _api_register( [
7949
+ _child_obj+'.hide()',
7950
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
7951
+ ], function () { // it returns an object and this method is not executed)
7952
+ __details_display( this, false );
7953
+ return this;
7954
+ } );
7955
+
7956
+
7957
+ _api_register( [
7958
+ _child_obj+'.remove()',
7959
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
7960
+ ], function () { // it returns an object and this method is not executed)
7961
+ __details_remove( this );
7962
+ return this;
7963
+ } );
7964
+
7965
+
7966
+ _api_register( _child_obj+'.isShown()', function () {
7967
+ var ctx = this.context;
7968
+
7969
+ if ( ctx.length && this.length ) {
7970
+ // _detailsShown as false or undefined will fall through to return false
7971
+ return ctx[0].aoData[ this[0] ]._detailsShow || false;
7972
+ }
7973
+ return false;
7974
+ } );
7975
+
7976
+
7977
+
7978
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7979
+ * Columns
7980
+ *
7981
+ * {integer} - column index (>=0 count from left, <0 count from right)
7982
+ * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
7983
+ * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
7984
+ * "{string}:name" - column name
7985
+ * "{string}" - jQuery selector on column header nodes
7986
+ *
7987
+ */
7988
+
7989
+ // can be an array of these items, comma separated list, or an array of comma
7990
+ // separated lists
7991
+
7992
+ var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
7993
+
7994
+ var __column_selector = function ( settings, selector, opts )
7995
+ {
7996
+ var
7997
+ columns = settings.aoColumns,
7998
+ names = _pluck( columns, 'sName' ),
7999
+ nodes = _pluck( columns, 'nTh' );
8000
+
8001
+ return _selector_run( selector, function ( s ) {
8002
+ var selInt = _intVal( s );
8003
+
8004
+ if ( s === '' ) {
8005
+ // All columns
8006
+ return _range( columns.length );
8007
+ }
8008
+ else if ( selInt !== null ) {
8009
+ // Integer selector
8010
+ return [ selInt >= 0 ?
8011
+ selInt : // Count from left
8012
+ columns.length + selInt // Count from right (+ because its a negative value)
8013
+ ];
8014
+ }
8015
+ else {
8016
+ var match = typeof s === 'string' ?
8017
+ s.match( __re_column_selector ) :
8018
+ '';
8019
+
8020
+ if ( match ) {
8021
+ switch( match[2] ) {
8022
+ case 'visIdx':
8023
+ case 'visible':
8024
+ var idx = parseInt( match[1], 10 );
8025
+ // Visible index given, convert to column index
8026
+ if ( idx < 0 ) {
8027
+ // Counting from the right
8028
+ var visColumns = $.map( columns, function (col,i) {
8029
+ return col.bVisible ? i : null;
8030
+ } );
8031
+ return [ visColumns[ visColumns.length + idx ] ];
8032
+ }
8033
+ // Counting from the left
8034
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
8035
+
8036
+ case 'name':
8037
+ // match by name. `names` is column index complete and in order
8038
+ return $.map( names, function (name, i) {
8039
+ return name === match[1] ? i : null;
8040
+ } );
8041
+ }
8042
+ }
8043
+ else {
8044
+ // jQuery selector on the TH elements for the columns
8045
+ return $( nodes )
8046
+ .filter( s )
8047
+ .map( function () {
8048
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8049
+ } )
8050
+ .toArray();
8051
+ }
8052
+ }
8053
+ } );
8054
+ };
8055
+
8056
+
8057
+
8058
+
8059
+
8060
+ var __setColumnVis = function ( settings, column, vis, recalc ) {
8061
+ var
8062
+ cols = settings.aoColumns,
8063
+ col = cols[ column ],
8064
+ data = settings.aoData,
8065
+ row, cells, i, ien, tr;
8066
+
8067
+ // Get
8068
+ if ( vis === undefined ) {
8069
+ return col.bVisible;
8070
+ }
8071
+
8072
+ // Set
8073
+ // No change
8074
+ if ( col.bVisible === vis ) {
8075
+ return;
8076
+ }
8077
+
8078
+ if ( vis ) {
8079
+ // Insert column
8080
+ // Need to decide if we should use appendChild or insertBefore
8081
+ var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8082
+
8083
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8084
+ tr = data[i].nTr;
8085
+ cells = data[i].anCells;
8086
+
8087
+ if ( tr ) {
8088
+ // insertBefore can act like appendChild if 2nd arg is null
8089
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8090
+ }
8091
+ }
8092
+ }
8093
+ else {
8094
+ // Remove column
8095
+ $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8096
+ }
8097
+
8098
+ // Common actions
8099
+ col.bVisible = vis;
8100
+ _fnDrawHead( settings, settings.aoHeader );
8101
+ _fnDrawHead( settings, settings.aoFooter );
8102
+
8103
+ if ( recalc === undefined || recalc ) {
8104
+ // Automatically adjust column sizing
8105
+ _fnAdjustColumnSizing( settings );
8106
+
8107
+ // Realign columns for scrolling
8108
+ if ( settings.oScroll.sX || settings.oScroll.sY ) {
8109
+ _fnScrollDraw( settings );
8110
+ }
8111
+ }
8112
+
8113
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8114
+
8115
+ _fnSaveState( settings );
8116
+ };
8117
+
8118
+
8119
+ /**
8120
+ *
8121
+ */
8122
+ _api_register( 'columns()', function ( selector, opts ) {
8123
+ // argument shifting
8124
+ if ( selector === undefined ) {
8125
+ selector = '';
8126
+ }
8127
+ else if ( $.isPlainObject( selector ) ) {
8128
+ opts = selector;
8129
+ selector = '';
8130
+ }
8131
+
8132
+ opts = _selector_opts( opts );
8133
+
8134
+ var inst = this.iterator( 'table', function ( settings ) {
8135
+ return __column_selector( settings, selector, opts );
8136
+ } );
8137
+
8138
+ // Want argument shifting here and in _row_selector?
8139
+ inst.selector.cols = selector;
8140
+ inst.selector.opts = opts;
8141
+
8142
+ return inst;
8143
+ } );
8144
+
8145
+
8146
+ /**
8147
+ *
8148
+ */
8149
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8150
+ return this.iterator( 'column', function ( settings, column ) {
8151
+ return settings.aoColumns[column].nTh;
8152
+ } );
8153
+ } );
8154
+
8155
+
8156
+ /**
8157
+ *
8158
+ */
8159
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8160
+ return this.iterator( 'column', function ( settings, column ) {
8161
+ return settings.aoColumns[column].nTf;
8162
+ } );
8163
+ } );
8164
+
8165
+
8166
+ /**
8167
+ *
8168
+ */
8169
+ _api_registerPlural( 'columns().data()', 'column().data()', function () {
8170
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8171
+ var a = [];
8172
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8173
+ a.push( _fnGetCellData( settings, rows[row], column, '' ) );
8174
+ }
8175
+ return a;
8176
+ } );
8177
+ } );
8178
+
8179
+
8180
+ _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8181
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8182
+ return _pluck_order( settings.aoData, rows,
8183
+ type === 'search' ? '_aFilterData' : '_aSortData', column
8184
+ );
8185
+ } );
8186
+ } );
8187
+
8188
+
8189
+ _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8190
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8191
+ return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8192
+ } );
8193
+ } );
8194
+
8195
+
8196
+
8197
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8198
+ return this.iterator( 'column', function ( settings, column ) {
8199
+ return vis === undefined ?
8200
+ settings.aoColumns[ column ].bVisible :
8201
+ __setColumnVis( settings, column, vis, calc );
8202
+ } );
8203
+ } );
8204
+
8205
+
8206
+
8207
+ _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8208
+ return this.iterator( 'column', function ( settings, column ) {
8209
+ return type === 'visible' ?
8210
+ _fnColumnIndexToVisible( settings, column ) :
8211
+ column;
8212
+ } );
8213
+ } );
8214
+
8215
+
8216
+ // _api_register( 'columns().show()', function () {
8217
+ // var selector = this.selector;
8218
+ // return this.columns( selector.cols, selector.opts ).visible( true );
8219
+ // } );
8220
+
8221
+
8222
+ // _api_register( 'columns().hide()', function () {
8223
+ // var selector = this.selector;
8224
+ // return this.columns( selector.cols, selector.opts ).visible( false );
8225
+ // } );
8226
+
8227
+
8228
+
8229
+ _api_register( 'columns.adjust()', function () {
8230
+ return this.iterator( 'table', function ( settings ) {
8231
+ _fnAdjustColumnSizing( settings );
8232
+ } );
8233
+ } );
8234
+
8235
+
8236
+ // Convert from one column index type, to another type
8237
+ _api_register( 'column.index()', function ( type, idx ) {
8238
+ if ( this.context.length !== 0 ) {
8239
+ var ctx = this.context[0];
8240
+
8241
+ if ( type === 'fromVisible' || type === 'toData' ) {
8242
+ return _fnVisibleToColumnIndex( ctx, idx );
8243
+ }
8244
+ else if ( type === 'fromData' || type === 'toVisible' ) {
8245
+ return _fnColumnIndexToVisible( ctx, idx );
8246
+ }
8247
+ }
8248
+ } );
8249
+
8250
+
8251
+ _api_register( 'column()', function ( selector, opts ) {
8252
+ return _selector_first( this.columns( selector, opts ) );
8253
+ } );
8254
+
8255
+
8256
+
8257
+
8258
+ var __cell_selector = function ( settings, selector, opts )
8259
+ {
8260
+ var data = settings.aoData;
8261
+ var rows = _selector_row_indexes( settings, opts );
8262
+ var cells = _pluck_order( data, rows, 'anCells' );
8263
+ var allCells = $( [].concat.apply([], cells) );
8264
+ var row;
8265
+ var columns = settings.aoColumns.length;
8266
+ var a, i, ien, j;
8267
+
8268
+ return _selector_run( selector, function ( s ) {
8269
+ if ( s === null || s === undefined ) {
8270
+ // All cells
8271
+ a = [];
8272
+
8273
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8274
+ row = rows[i];
8275
+
8276
+ for ( j=0 ; j<columns ; j++ ) {
8277
+ a.push( {
8278
+ row: row,
8279
+ column: j
8280
+ } );
8281
+ }
8282
+ }
8283
+
8284
+ return a;
8285
+ }
8286
+ else if ( $.isPlainObject( s ) ) {
8287
+ return [s];
8288
+ }
8289
+
8290
+ // jQuery filtered cells
8291
+ return allCells
8292
+ .filter( s )
8293
+ .map( function (i, el) {
8294
+ row = el.parentNode._DT_RowIndex;
8295
+
8296
+ return {
8297
+ row: row,
8298
+ column: $.inArray( el, data[ row ].anCells )
8299
+ };
8300
+ } )
8301
+ .toArray();
8302
+ } );
8303
+ };
8304
+
8305
+
8306
+
8307
+
8308
+ _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8309
+ // Argument shifting
8310
+ if ( $.isPlainObject( rowSelector ) ) {
8311
+ // Indexes
8312
+ if ( typeof rowSelector.row !== undefined ) {
8313
+ opts = columnSelector;
8314
+ columnSelector = null;
8315
+ }
8316
+ else {
8317
+ opts = rowSelector;
8318
+ rowSelector = null;
8319
+ }
8320
+ }
8321
+ if ( $.isPlainObject( columnSelector ) ) {
8322
+ opts = columnSelector;
8323
+ columnSelector = null;
8324
+ }
8325
+
8326
+ // Cell selector
8327
+ if ( columnSelector === null || columnSelector === undefined ) {
8328
+ return this.iterator( 'table', function ( settings ) {
8329
+ return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8330
+ } );
8331
+ }
8332
+
8333
+ // Row + column selector
8334
+ var columns = this.columns( columnSelector, opts );
8335
+ var rows = this.rows( rowSelector, opts );
8336
+ var a, i, ien, j, jen;
8337
+
8338
+ var cells = this.iterator( 'table', function ( settings, idx ) {
8339
+ a = [];
8340
+
8341
+ for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8342
+ for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8343
+ a.push( {
8344
+ row: rows[idx][i],
8345
+ column: columns[idx][j]
8346
+ } );
8347
+ }
8348
+ }
8349
+
8350
+ return a;
8351
+ } );
8352
+
8353
+ $.extend( cells.selector, {
8354
+ cols: columnSelector,
8355
+ rows: rowSelector,
8356
+ opts: opts
8357
+ } );
8358
+
8359
+ return cells;
8360
+ } );
8361
+
8362
+
8363
+ _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8364
+ return this.iterator( 'cell', function ( settings, row, column ) {
8365
+ return settings.aoData[ row ].anCells[ column ];
8366
+ } );
8367
+ } );
8368
+
8369
+
8370
+ _api_register( 'cells().data()', function () {
8371
+ return this.iterator( 'cell', function ( settings, row, column ) {
8372
+ return _fnGetCellData( settings, row, column );
8373
+ } );
8374
+ } );
8375
+
8376
+
8377
+ _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8378
+ type = type === 'search' ? '_aFilterData' : '_aSortData';
8379
+
8380
+ return this.iterator( 'cell', function ( settings, row, column ) {
8381
+ return settings.aoData[ row ][ type ][ column ];
8382
+ } );
8383
+ } );
8384
+
8385
+
8386
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8387
+ return this.iterator( 'cell', function ( settings, row, column ) {
8388
+ return {
8389
+ row: row,
8390
+ column: column,
8391
+ columnVisible: _fnColumnIndexToVisible( settings, column )
8392
+ };
8393
+ } );
8394
+ } );
8395
+
8396
+
8397
+ _api_register( [
8398
+ 'cells().invalidate()',
8399
+ 'cell().invalidate()'
8400
+ ], function ( src ) {
8401
+ var selector = this.selector;
8402
+
8403
+ // Use the rows method of the instance to perform the invalidation, rather
8404
+ // than doing it here. This avoids needing to handle duplicate rows from
8405
+ // the cells.
8406
+ this.rows( selector.rows, selector.opts ).invalidate( src );
8407
+
8408
+ return this;
8409
+ } );
8410
+
8411
+
8412
+
8413
+
8414
+ _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8415
+ return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8416
+ } );
8417
+
8418
+
8419
+
8420
+ _api_register( 'cell().data()', function ( data ) {
8421
+ var ctx = this.context;
8422
+ var cell = this[0];
8423
+
8424
+ if ( data === undefined ) {
8425
+ // Get
8426
+ return ctx.length && cell.length ?
8427
+ _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8428
+ undefined;
8429
+ }
8430
+
8431
+ // Set
8432
+ _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8433
+ _fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );
8434
+
8435
+ return this;
8436
+ } );
8437
+
8438
+
8439
+
8440
+ /**
8441
+ * Get current ordering (sorting) that has been applied to the table.
8442
+ *
8443
+ * @returns {array} 2D array containing the sorting information for the first
8444
+ * table in the current context. Each element in the parent array represents
8445
+ * a column being sorted upon (i.e. multi-sorting with two columns would have
8446
+ * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8447
+ * the column index that the sorting condition applies to, the second is the
8448
+ * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8449
+ * index of the sorting order from the `column.sorting` initialisation array.
8450
+ *//**
8451
+ * Set the ordering for the table.
8452
+ *
8453
+ * @param {integer} order Column index to sort upon.
8454
+ * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8455
+ * @returns {DataTables.Api} this
8456
+ *//**
8457
+ * Set the ordering for the table.
8458
+ *
8459
+ * @param {array} order 1D array of sorting information to be applied.
8460
+ * @param {array} [...] Optional additional sorting conditions
8461
+ * @returns {DataTables.Api} this
8462
+ *//**
8463
+ * Set the ordering for the table.
8464
+ *
8465
+ * @param {array} order 2D array of sorting information to be applied.
8466
+ * @returns {DataTables.Api} this
8467
+ */
8468
+ _api_register( 'order()', function ( order, dir ) {
8469
+ var ctx = this.context;
8470
+
8471
+ if ( order === undefined ) {
8472
+ // get
8473
+ return ctx.length !== 0 ?
8474
+ ctx[0].aaSorting :
8475
+ undefined;
8476
+ }
8477
+
8478
+ // set
8479
+ if ( typeof order === 'number' ) {
8480
+ // Simple column / direction passed in
8481
+ order = [ [ order, dir ] ];
8482
+ }
8483
+ else if ( ! $.isArray( order[0] ) ) {
8484
+ // Arguments passed in (list of 1D arrays)
8485
+ order = Array.prototype.slice.call( arguments );
8486
+ }
8487
+ // otherwise a 2D array was passed in
8488
+
8489
+ return this.iterator( 'table', function ( settings ) {
8490
+ settings.aaSorting = order.slice();
8491
+ } );
8492
+ } );
8493
+
8494
+
8495
+ /**
8496
+ * Attach a sort listener to an element for a given column
8497
+ *
8498
+ * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8499
+ * listener to. This can take the form of a single DOM node, a jQuery
8500
+ * collection of nodes or a jQuery selector which will identify the node(s).
8501
+ * @param {integer} column the column that a click on this node will sort on
8502
+ * @param {function} [callback] callback function when sort is run
8503
+ * @returns {DataTables.Api} this
8504
+ */
8505
+ _api_register( 'order.listener()', function ( node, column, callback ) {
8506
+ return this.iterator( 'table', function ( settings ) {
8507
+ _fnSortAttachListener( settings, node, column, callback );
8508
+ } );
8509
+ } );
8510
+
8511
+
8512
+ // Order by the selected column(s)
8513
+ _api_register( [
8514
+ 'columns().order()',
8515
+ 'column().order()'
8516
+ ], function ( dir ) {
8517
+ var that = this;
8518
+
8519
+ return this.iterator( 'table', function ( settings, i ) {
8520
+ var sort = [];
8521
+
8522
+ $.each( that[i], function (j, col) {
8523
+ sort.push( [ col, dir ] );
8524
+ } );
8525
+
8526
+ settings.aaSorting = sort;
8527
+ } );
8528
+ } );
8529
+
8530
+
8531
+
8532
+ _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8533
+ var ctx = this.context;
8534
+
8535
+ if ( input === undefined ) {
8536
+ // get
8537
+ return ctx.length !== 0 ?
8538
+ ctx[0].oPreviousSearch.sSearch :
8539
+ undefined;
8540
+ }
8541
+
8542
+ // set
8543
+ return this.iterator( 'table', function ( settings ) {
8544
+ if ( ! settings.oFeatures.bFilter ) {
8545
+ return;
8546
+ }
8547
+
8548
+ _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8549
+ "sSearch": input+"",
8550
+ "bRegex": regex === null ? false : regex,
8551
+ "bSmart": smart === null ? true : smart,
8552
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
8553
+ } ), 1 );
8554
+ } );
8555
+ } );
8556
+
8557
+
8558
+ _api_registerPlural(
8559
+ 'columns().search()',
8560
+ 'column().search()',
8561
+ function ( input, regex, smart, caseInsen ) {
8562
+ return this.iterator( 'column', function ( settings, column ) {
8563
+ var preSearch = settings.aoPreSearchCols;
8564
+
8565
+ if ( input === undefined ) {
8566
+ // get
8567
+ return preSearch[ column ].sSearch;
8568
+ }
8569
+
8570
+ // set
8571
+ if ( ! settings.oFeatures.bFilter ) {
8572
+ return;
8573
+ }
8574
+
8575
+ $.extend( preSearch[ column ], {
8576
+ "sSearch": input+"",
8577
+ "bRegex": regex === null ? false : regex,
8578
+ "bSmart": smart === null ? true : smart,
8579
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
8580
+ } );
8581
+
8582
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8583
+ } );
8584
+ }
8585
+ );
8586
+
8587
+ /*
8588
+ * State API methods
8589
+ */
8590
+
8591
+ _api_register( 'state()', function () {
8592
+ return this.context.length ?
8593
+ this.context[0].oSavedState :
8594
+ null;
8595
+ } );
8596
+
8597
+
8598
+ _api_register( 'state.clear()', function () {
8599
+ return this.iterator( 'table', function ( settings ) {
8600
+ // Save an empty object
8601
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8602
+ } );
8603
+ } );
8604
+
8605
+
8606
+ _api_register( 'state.loaded()', function () {
8607
+ return this.context.length ?
8608
+ this.context[0].oLoadedState :
8609
+ null;
8610
+ } );
8611
+
8612
+
8613
+ _api_register( 'state.save()', function () {
8614
+ return this.iterator( 'table', function ( settings ) {
8615
+ _fnSaveState( settings );
8616
+ } );
8617
+ } );
8618
+
8619
+
8620
+
8621
+ /**
8622
+ * Provide a common method for plug-ins to check the version of DataTables being
8623
+ * used, in order to ensure compatibility.
8624
+ *
8625
+ * @param {string} version Version string to check for, in the format "X.Y.Z".
8626
+ * Note that the formats "X" and "X.Y" are also acceptable.
8627
+ * @returns {boolean} true if this version of DataTables is greater or equal to
8628
+ * the required version, or false if this version of DataTales is not
8629
+ * suitable
8630
+ * @static
8631
+ * @dtopt API-Static
8632
+ *
8633
+ * @example
8634
+ * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8635
+ */
8636
+ DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8637
+ {
8638
+ var aThis = DataTable.version.split('.');
8639
+ var aThat = version.split('.');
8640
+ var iThis, iThat;
8641
+
8642
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8643
+ iThis = parseInt( aThis[i], 10 ) || 0;
8644
+ iThat = parseInt( aThat[i], 10 ) || 0;
8645
+
8646
+ // Parts are the same, keep comparing
8647
+ if (iThis === iThat) {
8648
+ continue;
8649
+ }
8650
+
8651
+ // Parts are different, return immediately
8652
+ return iThis > iThat;
8653
+ }
8654
+
8655
+ return true;
8656
+ };
8657
+
8658
+
8659
+ /**
8660
+ * Check if a `<table>` node is a DataTable table already or not.
8661
+ *
8662
+ * @param {node|jquery|string} table Table node, jQuery object or jQuery
8663
+ * selector for the table to test. Note that if more than more than one
8664
+ * table is passed on, only the first will be checked
8665
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
8666
+ * @static
8667
+ * @dtopt API-Static
8668
+ *
8669
+ * @example
8670
+ * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8671
+ * $('#example').dataTable();
8672
+ * }
8673
+ */
8674
+ DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8675
+ {
8676
+ var t = $(table).get(0);
8677
+ var is = false;
8678
+
8679
+ $.each( DataTable.settings, function (i, o) {
8680
+ if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8681
+ is = true;
8682
+ }
8683
+ } );
8684
+
8685
+ return is;
8686
+ };
8687
+
8688
+
8689
+ /**
8690
+ * Get all DataTable tables that have been initialised - optionally you can
8691
+ * select to get only currently visible tables.
8692
+ *
8693
+ * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8694
+ * or visible tables only.
8695
+ * @returns {array} Array of `table` nodes (not DataTable instances) which are
8696
+ * DataTables
8697
+ * @static
8698
+ * @dtopt API-Static
8699
+ *
8700
+ * @example
8701
+ * $.each( $.fn.dataTable.tables(true), function () {
8702
+ * $(table).DataTable().columns.adjust();
8703
+ * } );
8704
+ */
8705
+ DataTable.tables = DataTable.fnTables = function ( visible )
8706
+ {
8707
+ return jQuery.map( DataTable.settings, function (o) {
8708
+ if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8709
+ return o.nTable;
8710
+ }
8711
+ } );
8712
+ };
8713
+
8714
+
8715
+ /**
8716
+ * Convert from camel case parameters to Hungarian notation. This is made public
8717
+ * for the extensions to provide the same ability as DataTables core to accept
8718
+ * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8719
+ * parameters.
8720
+ *
8721
+ * @param {object} src The model object which holds all parameters that can be
8722
+ * mapped.
8723
+ * @param {object} user The object to convert from camel case to Hungarian.
8724
+ * @param {boolean} force When set to `true`, properties which already have a
8725
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
8726
+ * won't be.
8727
+ */
8728
+ DataTable.camelToHungarian = _fnCamelToHungarian;
8729
+
8730
+
8731
+
8732
+ /**
8733
+ *
8734
+ */
8735
+ _api_register( '$()', function ( selector, opts ) {
8736
+ var
8737
+ rows = this.rows( opts ).nodes(), // Get all rows
8738
+ jqRows = $(rows);
8739
+
8740
+ return $( [].concat(
8741
+ jqRows.filter( selector ).toArray(),
8742
+ jqRows.find( selector ).toArray()
8743
+ ) );
8744
+ } );
8745
+
8746
+
8747
+ // jQuery functions to operate on the tables
8748
+ $.each( [ 'on', 'one', 'off' ], function (i, key) {
8749
+ _api_register( key+'()', function ( /* event, handler */ ) {
8750
+ var args = Array.prototype.slice.call(arguments);
8751
+
8752
+ // Add the `dt` namespace automatically if it isn't already present
8753
+ if ( ! args[0].match(/\.dt\b/) ) {
8754
+ args[0] += '.dt';
8755
+ }
8756
+
8757
+ var inst = $( this.tables().nodes() );
8758
+ inst[key].apply( inst, args );
8759
+ return this;
8760
+ } );
8761
+ } );
8762
+
8763
+
8764
+ _api_register( 'clear()', function () {
8765
+ return this.iterator( 'table', function ( settings ) {
8766
+ _fnClearTable( settings );
8767
+ } );
8768
+ } );
8769
+
8770
+
8771
+ _api_register( 'settings()', function () {
8772
+ return new _Api( this.context, this.context );
8773
+ } );
8774
+
8775
+
8776
+ _api_register( 'data()', function () {
8777
+ return this.iterator( 'table', function ( settings ) {
8778
+ return _pluck( settings.aoData, '_aData' );
8779
+ } ).flatten();
8780
+ } );
8781
+
8782
+
8783
+ _api_register( 'destroy()', function ( remove ) {
8784
+ remove = remove || false;
8785
+
8786
+ return this.iterator( 'table', function ( settings ) {
8787
+ var orig = settings.nTableWrapper.parentNode;
8788
+ var classes = settings.oClasses;
8789
+ var table = settings.nTable;
8790
+ var tbody = settings.nTBody;
8791
+ var thead = settings.nTHead;
8792
+ var tfoot = settings.nTFoot;
8793
+ var jqTable = $(table);
8794
+ var jqTbody = $(tbody);
8795
+ var jqWrapper = $(settings.nTableWrapper);
8796
+ var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
8797
+ var i, ien;
8798
+
8799
+ // Flag to note that the table is currently being destroyed - no action
8800
+ // should be taken
8801
+ settings.bDestroying = true;
8802
+
8803
+ // Fire off the destroy callbacks for plug-ins etc
8804
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
8805
+
8806
+ // If not being removed from the document, make all columns visible
8807
+ if ( ! remove ) {
8808
+ new _Api( settings ).columns().visible( true );
8809
+ }
8810
+
8811
+ // Blitz all `DT` namespaced events (these are internal events, the
8812
+ // lowercase, `dt` events are user subscribed and they are responsible
8813
+ // for removing them
8814
+ jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
8815
+ $(window).unbind('.DT-'+settings.sInstance);
8816
+
8817
+ // When scrolling we had to break the table up - restore it
8818
+ if ( table != thead.parentNode ) {
8819
+ jqTable.children('thead').detach();
8820
+ jqTable.append( thead );
8821
+ }
8822
+
8823
+ if ( tfoot && table != tfoot.parentNode ) {
8824
+ jqTable.children('tfoot').detach();
8825
+ jqTable.append( tfoot );
8826
+ }
8827
+
8828
+ // Remove the DataTables generated nodes, events and classes
8829
+ jqTable.detach();
8830
+ jqWrapper.detach();
8831
+
8832
+ settings.aaSorting = [];
8833
+ settings.aaSortingFixed = [];
8834
+ _fnSortingClasses( settings );
8835
+
8836
+ $( rows ).removeClass( settings.asStripeClasses.join(' ') );
8837
+
8838
+ $('th, td', thead).removeClass( classes.sSortable+' '+
8839
+ classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
8840
+ );
8841
+
8842
+ if ( settings.bJUI ) {
8843
+ $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
8844
+ $('th, td', thead).each( function () {
8845
+ var wrapper = $('div.'+classes.sSortJUIWrapper, this);
8846
+ $(this).append( wrapper.contents() );
8847
+ wrapper.detach();
8848
+ } );
8849
+ }
8850
+
8851
+ if ( ! remove && orig ) {
8852
+ // insertBefore acts like appendChild if !arg[1]
8853
+ orig.insertBefore( table, settings.nTableReinsertBefore );
8854
+ }
8855
+
8856
+ // Add the TR elements back into the table in their original order
8857
+ jqTbody.children().detach();
8858
+ jqTbody.append( rows );
8859
+
8860
+ // Restore the width of the original table - was read from the style property,
8861
+ // so we can restore directly to that
8862
+ jqTable
8863
+ .css( 'width', settings.sDestroyWidth )
8864
+ .removeClass( classes.sTable );
8865
+
8866
+ // If the were originally stripe classes - then we add them back here.
8867
+ // Note this is not fool proof (for example if not all rows had stripe
8868
+ // classes - but it's a good effort without getting carried away
8869
+ ien = settings.asDestroyStripes.length;
8870
+
8871
+ if ( ien ) {
8872
+ jqTbody.children().each( function (i) {
8873
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
8874
+ } );
8875
+ }
8876
+
8877
+ /* Remove the settings object from the settings array */
8878
+ var idx = $.inArray( settings, DataTable.settings );
8879
+ if ( idx !== -1 ) {
8880
+ DataTable.settings.splice( idx, 1 );
8881
+ }
8882
+ } );
8883
+ } );
8884
+
8885
+
8886
+ /**
8887
+ * Version string for plug-ins to check compatibility. Allowed format is
8888
+ * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
8889
+ * only for non-release builds. See http://semver.org/ for more information.
8890
+ * @member
8891
+ * @type string
8892
+ * @default Version number
8893
+ */
8894
+ DataTable.version = "1.10.2";
8895
+
8896
+ /**
8897
+ * Private data store, containing all of the settings objects that are
8898
+ * created for the tables on a given page.
8899
+ *
8900
+ * Note that the `DataTable.settings` object is aliased to
8901
+ * `jQuery.fn.dataTableExt` through which it may be accessed and
8902
+ * manipulated, or `jQuery.fn.dataTable.settings`.
8903
+ * @member
8904
+ * @type array
8905
+ * @default []
8906
+ * @private
8907
+ */
8908
+ DataTable.settings = [];
8909
+
8910
+ /**
8911
+ * Object models container, for the various models that DataTables has
8912
+ * available to it. These models define the objects that are used to hold
8913
+ * the active state and configuration of the table.
8914
+ * @namespace
8915
+ */
8916
+ DataTable.models = {};
8917
+
8918
+
8919
+
8920
+ /**
8921
+ * Template object for the way in which DataTables holds information about
8922
+ * search information for the global filter and individual column filters.
8923
+ * @namespace
8924
+ */
8925
+ DataTable.models.oSearch = {
8926
+ /**
8927
+ * Flag to indicate if the filtering should be case insensitive or not
8928
+ * @type boolean
8929
+ * @default true
8930
+ */
8931
+ "bCaseInsensitive": true,
8932
+
8933
+ /**
8934
+ * Applied search term
8935
+ * @type string
8936
+ * @default <i>Empty string</i>
8937
+ */
8938
+ "sSearch": "",
8939
+
8940
+ /**
8941
+ * Flag to indicate if the search term should be interpreted as a
8942
+ * regular expression (true) or not (false) and therefore and special
8943
+ * regex characters escaped.
8944
+ * @type boolean
8945
+ * @default false
8946
+ */
8947
+ "bRegex": false,
8948
+
8949
+ /**
8950
+ * Flag to indicate if DataTables is to use its smart filtering or not.
8951
+ * @type boolean
8952
+ * @default true
8953
+ */
8954
+ "bSmart": true
8955
+ };
8956
+
8957
+
8958
+
8959
+
8960
+ /**
8961
+ * Template object for the way in which DataTables holds information about
8962
+ * each individual row. This is the object format used for the settings
8963
+ * aoData array.
8964
+ * @namespace
8965
+ */
8966
+ DataTable.models.oRow = {
8967
+ /**
8968
+ * TR element for the row
8969
+ * @type node
8970
+ * @default null
8971
+ */
8972
+ "nTr": null,
8973
+
8974
+ /**
8975
+ * Array of TD elements for each row. This is null until the row has been
8976
+ * created.
8977
+ * @type array nodes
8978
+ * @default []
8979
+ */
8980
+ "anCells": null,
8981
+
8982
+ /**
8983
+ * Data object from the original data source for the row. This is either
8984
+ * an array if using the traditional form of DataTables, or an object if
8985
+ * using mData options. The exact type will depend on the passed in
8986
+ * data from the data source, or will be an array if using DOM a data
8987
+ * source.
8988
+ * @type array|object
8989
+ * @default []
8990
+ */
8991
+ "_aData": [],
8992
+
8993
+ /**
8994
+ * Sorting data cache - this array is ostensibly the same length as the
8995
+ * number of columns (although each index is generated only as it is
8996
+ * needed), and holds the data that is used for sorting each column in the
8997
+ * row. We do this cache generation at the start of the sort in order that
8998
+ * the formatting of the sort data need be done only once for each cell
8999
+ * per sort. This array should not be read from or written to by anything
9000
+ * other than the master sorting methods.
9001
+ * @type array
9002
+ * @default null
9003
+ * @private
9004
+ */
9005
+ "_aSortData": null,
9006
+
9007
+ /**
9008
+ * Per cell filtering data cache. As per the sort data cache, used to
9009
+ * increase the performance of the filtering in DataTables
9010
+ * @type array
9011
+ * @default null
9012
+ * @private
9013
+ */
9014
+ "_aFilterData": null,
9015
+
9016
+ /**
9017
+ * Filtering data cache. This is the same as the cell filtering cache, but
9018
+ * in this case a string rather than an array. This is easily computed with
9019
+ * a join on `_aFilterData`, but is provided as a cache so the join isn't
9020
+ * needed on every search (memory traded for performance)
9021
+ * @type array
9022
+ * @default null
9023
+ * @private
9024
+ */
9025
+ "_sFilterRow": null,
9026
+
9027
+ /**
9028
+ * Cache of the class name that DataTables has applied to the row, so we
9029
+ * can quickly look at this variable rather than needing to do a DOM check
9030
+ * on className for the nTr property.
9031
+ * @type string
9032
+ * @default <i>Empty string</i>
9033
+ * @private
9034
+ */
9035
+ "_sRowStripe": "",
9036
+
9037
+ /**
9038
+ * Denote if the original data source was from the DOM, or the data source
9039
+ * object. This is used for invalidating data, so DataTables can
9040
+ * automatically read data from the original source, unless uninstructed
9041
+ * otherwise.
9042
+ * @type string
9043
+ * @default null
9044
+ * @private
9045
+ */
9046
+ "src": null
9047
+ };
9048
+
9049
+
9050
+ /**
9051
+ * Template object for the column information object in DataTables. This object
9052
+ * is held in the settings aoColumns array and contains all the information that
9053
+ * DataTables needs about each individual column.
9054
+ *
9055
+ * Note that this object is related to {@link DataTable.defaults.column}
9056
+ * but this one is the internal data store for DataTables's cache of columns.
9057
+ * It should NOT be manipulated outside of DataTables. Any configuration should
9058
+ * be done through the initialisation options.
9059
+ * @namespace
9060
+ */
9061
+ DataTable.models.oColumn = {
9062
+ /**
9063
+ * Column index. This could be worked out on-the-fly with $.inArray, but it
9064
+ * is faster to just hold it as a variable
9065
+ * @type integer
9066
+ * @default null
9067
+ */
9068
+ "idx": null,
9069
+
9070
+ /**
9071
+ * A list of the columns that sorting should occur on when this column
9072
+ * is sorted. That this property is an array allows multi-column sorting
9073
+ * to be defined for a column (for example first name / last name columns
9074
+ * would benefit from this). The values are integers pointing to the
9075
+ * columns to be sorted on (typically it will be a single integer pointing
9076
+ * at itself, but that doesn't need to be the case).
9077
+ * @type array
9078
+ */
9079
+ "aDataSort": null,
9080
+
9081
+ /**
9082
+ * Define the sorting directions that are applied to the column, in sequence
9083
+ * as the column is repeatedly sorted upon - i.e. the first value is used
9084
+ * as the sorting direction when the column if first sorted (clicked on).
9085
+ * Sort it again (click again) and it will move on to the next index.
9086
+ * Repeat until loop.
9087
+ * @type array
9088
+ */
9089
+ "asSorting": null,
9090
+
9091
+ /**
9092
+ * Flag to indicate if the column is searchable, and thus should be included
9093
+ * in the filtering or not.
9094
+ * @type boolean
9095
+ */
9096
+ "bSearchable": null,
9097
+
9098
+ /**
9099
+ * Flag to indicate if the column is sortable or not.
9100
+ * @type boolean
9101
+ */
9102
+ "bSortable": null,
9103
+
9104
+ /**
9105
+ * Flag to indicate if the column is currently visible in the table or not
9106
+ * @type boolean
9107
+ */
9108
+ "bVisible": null,
9109
+
9110
+ /**
9111
+ * Store for manual type assignment using the `column.type` option. This
9112
+ * is held in store so we can manipulate the column's `sType` property.
9113
+ * @type string
9114
+ * @default null
9115
+ * @private
9116
+ */
9117
+ "_sManualType": null,
9118
+
9119
+ /**
9120
+ * Flag to indicate if HTML5 data attributes should be used as the data
9121
+ * source for filtering or sorting. True is either are.
9122
+ * @type boolean
9123
+ * @default false
9124
+ * @private
9125
+ */
9126
+ "_bAttrSrc": false,
9127
+
9128
+ /**
9129
+ * Developer definable function that is called whenever a cell is created (Ajax source,
9130
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9131
+ * allowing you to modify the DOM element (add background colour for example) when the
9132
+ * element is available.
9133
+ * @type function
9134
+ * @param {element} nTd The TD node that has been created
9135
+ * @param {*} sData The Data for the cell
9136
+ * @param {array|object} oData The data for the whole row
9137
+ * @param {int} iRow The row index for the aoData data store
9138
+ * @default null
9139
+ */
9140
+ "fnCreatedCell": null,
9141
+
9142
+ /**
9143
+ * Function to get data from a cell in a column. You should <b>never</b>
9144
+ * access data directly through _aData internally in DataTables - always use
9145
+ * the method attached to this property. It allows mData to function as
9146
+ * required. This function is automatically assigned by the column
9147
+ * initialisation method
9148
+ * @type function
9149
+ * @param {array|object} oData The data array/object for the array
9150
+ * (i.e. aoData[]._aData)
9151
+ * @param {string} sSpecific The specific data type you want to get -
9152
+ * 'display', 'type' 'filter' 'sort'
9153
+ * @returns {*} The data for the cell from the given row's data
9154
+ * @default null
9155
+ */
9156
+ "fnGetData": null,
9157
+
9158
+ /**
9159
+ * Function to set data for a cell in the column. You should <b>never</b>
9160
+ * set the data directly to _aData internally in DataTables - always use
9161
+ * this method. It allows mData to function as required. This function
9162
+ * is automatically assigned by the column initialisation method
9163
+ * @type function
9164
+ * @param {array|object} oData The data array/object for the array
9165
+ * (i.e. aoData[]._aData)
9166
+ * @param {*} sValue Value to set
9167
+ * @default null
9168
+ */
9169
+ "fnSetData": null,
9170
+
9171
+ /**
9172
+ * Property to read the value for the cells in the column from the data
9173
+ * source array / object. If null, then the default content is used, if a
9174
+ * function is given then the return from the function is used.
9175
+ * @type function|int|string|null
9176
+ * @default null
9177
+ */
9178
+ "mData": null,
9179
+
9180
+ /**
9181
+ * Partner property to mData which is used (only when defined) to get
9182
+ * the data - i.e. it is basically the same as mData, but without the
9183
+ * 'set' option, and also the data fed to it is the result from mData.
9184
+ * This is the rendering method to match the data method of mData.
9185
+ * @type function|int|string|null
9186
+ * @default null
9187
+ */
9188
+ "mRender": null,
9189
+
9190
+ /**
9191
+ * Unique header TH/TD element for this column - this is what the sorting
9192
+ * listener is attached to (if sorting is enabled.)
9193
+ * @type node
9194
+ * @default null
9195
+ */
9196
+ "nTh": null,
9197
+
9198
+ /**
9199
+ * Unique footer TH/TD element for this column (if there is one). Not used
9200
+ * in DataTables as such, but can be used for plug-ins to reference the
9201
+ * footer for each column.
9202
+ * @type node
9203
+ * @default null
9204
+ */
9205
+ "nTf": null,
9206
+
9207
+ /**
9208
+ * The class to apply to all TD elements in the table's TBODY for the column
9209
+ * @type string
9210
+ * @default null
9211
+ */
9212
+ "sClass": null,
9213
+
9214
+ /**
9215
+ * When DataTables calculates the column widths to assign to each column,
9216
+ * it finds the longest string in each column and then constructs a
9217
+ * temporary table and reads the widths from that. The problem with this
9218
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
9219
+ * string - thus the calculation can go wrong (doing it properly and putting
9220
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
9221
+ * a "work around" we provide this option. It will append its value to the
9222
+ * text that is found to be the longest string for the column - i.e. padding.
9223
+ * @type string
9224
+ */
9225
+ "sContentPadding": null,
9226
+
9227
+ /**
9228
+ * Allows a default value to be given for a column's data, and will be used
9229
+ * whenever a null data source is encountered (this can be because mData
9230
+ * is set to null, or because the data source itself is null).
9231
+ * @type string
9232
+ * @default null
9233
+ */
9234
+ "sDefaultContent": null,
9235
+
9236
+ /**
9237
+ * Name for the column, allowing reference to the column by name as well as
9238
+ * by index (needs a lookup to work by name).
9239
+ * @type string
9240
+ */
9241
+ "sName": null,
9242
+
9243
+ /**
9244
+ * Custom sorting data type - defines which of the available plug-ins in
9245
+ * afnSortData the custom sorting will use - if any is defined.
9246
+ * @type string
9247
+ * @default std
9248
+ */
9249
+ "sSortDataType": 'std',
9250
+
9251
+ /**
9252
+ * Class to be applied to the header element when sorting on this column
9253
+ * @type string
9254
+ * @default null
9255
+ */
9256
+ "sSortingClass": null,
9257
+
9258
+ /**
9259
+ * Class to be applied to the header element when sorting on this column -
9260
+ * when jQuery UI theming is used.
9261
+ * @type string
9262
+ * @default null
9263
+ */
9264
+ "sSortingClassJUI": null,
9265
+
9266
+ /**
9267
+ * Title of the column - what is seen in the TH element (nTh).
9268
+ * @type string
9269
+ */
9270
+ "sTitle": null,
9271
+
9272
+ /**
9273
+ * Column sorting and filtering type
9274
+ * @type string
9275
+ * @default null
9276
+ */
9277
+ "sType": null,
9278
+
9279
+ /**
9280
+ * Width of the column
9281
+ * @type string
9282
+ * @default null
9283
+ */
9284
+ "sWidth": null,
9285
+
9286
+ /**
9287
+ * Width of the column when it was first "encountered"
9288
+ * @type string
9289
+ * @default null
9290
+ */
9291
+ "sWidthOrig": null
9292
+ };
9293
+
9294
+
9295
+ /*
9296
+ * Developer note: The properties of the object below are given in Hungarian
9297
+ * notation, that was used as the interface for DataTables prior to v1.10, however
9298
+ * from v1.10 onwards the primary interface is camel case. In order to avoid
9299
+ * breaking backwards compatibility utterly with this change, the Hungarian
9300
+ * version is still, internally the primary interface, but is is not documented
9301
+ * - hence the @name tags in each doc comment. This allows a Javascript function
9302
+ * to create a map from Hungarian notation to camel case (going the other direction
9303
+ * would require each property to be listed, which would at around 3K to the size
9304
+ * of DataTables, while this method is about a 0.5K hit.
9305
+ *
9306
+ * Ultimately this does pave the way for Hungarian notation to be dropped
9307
+ * completely, but that is a massive amount of work and will break current
9308
+ * installs (therefore is on-hold until v2).
9309
+ */
9310
+
9311
+ /**
9312
+ * Initialisation options that can be given to DataTables at initialisation
9313
+ * time.
9314
+ * @namespace
9315
+ */
9316
+ DataTable.defaults = {
9317
+ /**
9318
+ * An array of data to use for the table, passed in at initialisation which
9319
+ * will be used in preference to any data which is already in the DOM. This is
9320
+ * particularly useful for constructing tables purely in Javascript, for
9321
+ * example with a custom Ajax call.
9322
+ * @type array
9323
+ * @default null
9324
+ *
9325
+ * @dtopt Option
9326
+ * @name DataTable.defaults.data
9327
+ *
9328
+ * @example
9329
+ * // Using a 2D array data source
9330
+ * $(document).ready( function () {
9331
+ * $('#example').dataTable( {
9332
+ * "data": [
9333
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9334
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9335
+ * ],
9336
+ * "columns": [
9337
+ * { "title": "Engine" },
9338
+ * { "title": "Browser" },
9339
+ * { "title": "Platform" },
9340
+ * { "title": "Version" },
9341
+ * { "title": "Grade" }
9342
+ * ]
9343
+ * } );
9344
+ * } );
9345
+ *
9346
+ * @example
9347
+ * // Using an array of objects as a data source (`data`)
9348
+ * $(document).ready( function () {
9349
+ * $('#example').dataTable( {
9350
+ * "data": [
9351
+ * {
9352
+ * "engine": "Trident",
9353
+ * "browser": "Internet Explorer 4.0",
9354
+ * "platform": "Win 95+",
9355
+ * "version": 4,
9356
+ * "grade": "X"
9357
+ * },
9358
+ * {
9359
+ * "engine": "Trident",
9360
+ * "browser": "Internet Explorer 5.0",
9361
+ * "platform": "Win 95+",
9362
+ * "version": 5,
9363
+ * "grade": "C"
9364
+ * }
9365
+ * ],
9366
+ * "columns": [
9367
+ * { "title": "Engine", "data": "engine" },
9368
+ * { "title": "Browser", "data": "browser" },
9369
+ * { "title": "Platform", "data": "platform" },
9370
+ * { "title": "Version", "data": "version" },
9371
+ * { "title": "Grade", "data": "grade" }
9372
+ * ]
9373
+ * } );
9374
+ * } );
9375
+ */
9376
+ "aaData": null,
9377
+
9378
+
9379
+ /**
9380
+ * If ordering is enabled, then DataTables will perform a first pass sort on
9381
+ * initialisation. You can define which column(s) the sort is performed
9382
+ * upon, and the sorting direction, with this variable. The `sorting` array
9383
+ * should contain an array for each column to be sorted initially containing
9384
+ * the column's index and a direction string ('asc' or 'desc').
9385
+ * @type array
9386
+ * @default [[0,'asc']]
9387
+ *
9388
+ * @dtopt Option
9389
+ * @name DataTable.defaults.order
9390
+ *
9391
+ * @example
9392
+ * // Sort by 3rd column first, and then 4th column
9393
+ * $(document).ready( function() {
9394
+ * $('#example').dataTable( {
9395
+ * "order": [[2,'asc'], [3,'desc']]
9396
+ * } );
9397
+ * } );
9398
+ *
9399
+ * // No initial sorting
9400
+ * $(document).ready( function() {
9401
+ * $('#example').dataTable( {
9402
+ * "order": []
9403
+ * } );
9404
+ * } );
9405
+ */
9406
+ "aaSorting": [[0,'asc']],
9407
+
9408
+
9409
+ /**
9410
+ * This parameter is basically identical to the `sorting` parameter, but
9411
+ * cannot be overridden by user interaction with the table. What this means
9412
+ * is that you could have a column (visible or hidden) which the sorting
9413
+ * will always be forced on first - any sorting after that (from the user)
9414
+ * will then be performed as required. This can be useful for grouping rows
9415
+ * together.
9416
+ * @type array
9417
+ * @default null
9418
+ *
9419
+ * @dtopt Option
9420
+ * @name DataTable.defaults.orderFixed
9421
+ *
9422
+ * @example
9423
+ * $(document).ready( function() {
9424
+ * $('#example').dataTable( {
9425
+ * "orderFixed": [[0,'asc']]
9426
+ * } );
9427
+ * } )
9428
+ */
9429
+ "aaSortingFixed": [],
9430
+
9431
+
9432
+ /**
9433
+ * DataTables can be instructed to load data to display in the table from a
9434
+ * Ajax source. This option defines how that Ajax call is made and where to.
9435
+ *
9436
+ * The `ajax` property has three different modes of operation, depending on
9437
+ * how it is defined. These are:
9438
+ *
9439
+ * * `string` - Set the URL from where the data should be loaded from.
9440
+ * * `object` - Define properties for `jQuery.ajax`.
9441
+ * * `function` - Custom data get function
9442
+ *
9443
+ * `string`
9444
+ * --------
9445
+ *
9446
+ * As a string, the `ajax` property simply defines the URL from which
9447
+ * DataTables will load data.
9448
+ *
9449
+ * `object`
9450
+ * --------
9451
+ *
9452
+ * As an object, the parameters in the object are passed to
9453
+ * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9454
+ * of the Ajax request. DataTables has a number of default parameters which
9455
+ * you can override using this option. Please refer to the jQuery
9456
+ * documentation for a full description of the options available, although
9457
+ * the following parameters provide additional options in DataTables or
9458
+ * require special consideration:
9459
+ *
9460
+ * * `data` - As with jQuery, `data` can be provided as an object, but it
9461
+ * can also be used as a function to manipulate the data DataTables sends
9462
+ * to the server. The function takes a single parameter, an object of
9463
+ * parameters with the values that DataTables has readied for sending. An
9464
+ * object may be returned which will be merged into the DataTables
9465
+ * defaults, or you can add the items to the object that was passed in and
9466
+ * not return anything from the function. This supersedes `fnServerParams`
9467
+ * from DataTables 1.9-.
9468
+ *
9469
+ * * `dataSrc` - By default DataTables will look for the property `data` (or
9470
+ * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9471
+ * from an Ajax source or for server-side processing - this parameter
9472
+ * allows that property to be changed. You can use Javascript dotted
9473
+ * object notation to get a data source for multiple levels of nesting, or
9474
+ * it my be used as a function. As a function it takes a single parameter,
9475
+ * the JSON returned from the server, which can be manipulated as
9476
+ * required, with the returned value being that used by DataTables as the
9477
+ * data source for the table. This supersedes `sAjaxDataProp` from
9478
+ * DataTables 1.9-.
9479
+ *
9480
+ * * `success` - Should not be overridden it is used internally in
9481
+ * DataTables. To manipulate / transform the data returned by the server
9482
+ * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9483
+ *
9484
+ * `function`
9485
+ * ----------
9486
+ *
9487
+ * As a function, making the Ajax call is left up to yourself allowing
9488
+ * complete control of the Ajax request. Indeed, if desired, a method other
9489
+ * than Ajax could be used to obtain the required data, such as Web storage
9490
+ * or an AIR database.
9491
+ *
9492
+ * The function is given four parameters and no return is required. The
9493
+ * parameters are:
9494
+ *
9495
+ * 1. _object_ - Data to send to the server
9496
+ * 2. _function_ - Callback function that must be executed when the required
9497
+ * data has been obtained. That data should be passed into the callback
9498
+ * as the only parameter
9499
+ * 3. _object_ - DataTables settings object for the table
9500
+ *
9501
+ * Note that this supersedes `fnServerData` from DataTables 1.9-.
9502
+ *
9503
+ * @type string|object|function
9504
+ * @default null
9505
+ *
9506
+ * @dtopt Option
9507
+ * @name DataTable.defaults.ajax
9508
+ * @since 1.10.0
9509
+ *
9510
+ * @example
9511
+ * // Get JSON data from a file via Ajax.
9512
+ * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9513
+ * $('#example').dataTable( {
9514
+ * "ajax": "data.json"
9515
+ * } );
9516
+ *
9517
+ * @example
9518
+ * // Get JSON data from a file via Ajax, using `dataSrc` to change
9519
+ * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9520
+ * $('#example').dataTable( {
9521
+ * "ajax": {
9522
+ * "url": "data.json",
9523
+ * "dataSrc": "tableData"
9524
+ * }
9525
+ * } );
9526
+ *
9527
+ * @example
9528
+ * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9529
+ * // from a plain array rather than an array in an object
9530
+ * $('#example').dataTable( {
9531
+ * "ajax": {
9532
+ * "url": "data.json",
9533
+ * "dataSrc": ""
9534
+ * }
9535
+ * } );
9536
+ *
9537
+ * @example
9538
+ * // Manipulate the data returned from the server - add a link to data
9539
+ * // (note this can, should, be done using `render` for the column - this
9540
+ * // is just a simple example of how the data can be manipulated).
9541
+ * $('#example').dataTable( {
9542
+ * "ajax": {
9543
+ * "url": "data.json",
9544
+ * "dataSrc": function ( json ) {
9545
+ * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9546
+ * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9547
+ * }
9548
+ * return json;
9549
+ * }
9550
+ * }
9551
+ * } );
9552
+ *
9553
+ * @example
9554
+ * // Add data to the request
9555
+ * $('#example').dataTable( {
9556
+ * "ajax": {
9557
+ * "url": "data.json",
9558
+ * "data": function ( d ) {
9559
+ * return {
9560
+ * "extra_search": $('#extra').val()
9561
+ * };
9562
+ * }
9563
+ * }
9564
+ * } );
9565
+ *
9566
+ * @example
9567
+ * // Send request as POST
9568
+ * $('#example').dataTable( {
9569
+ * "ajax": {
9570
+ * "url": "data.json",
9571
+ * "type": "POST"
9572
+ * }
9573
+ * } );
9574
+ *
9575
+ * @example
9576
+ * // Get the data from localStorage (could interface with a form for
9577
+ * // adding, editing and removing rows).
9578
+ * $('#example').dataTable( {
9579
+ * "ajax": function (data, callback, settings) {
9580
+ * callback(
9581
+ * JSON.parse( localStorage.getItem('dataTablesData') )
9582
+ * );
9583
+ * }
9584
+ * } );
9585
+ */
9586
+ "ajax": null,
9587
+
9588
+
9589
+ /**
9590
+ * This parameter allows you to readily specify the entries in the length drop
9591
+ * down menu that DataTables shows when pagination is enabled. It can be
9592
+ * either a 1D array of options which will be used for both the displayed
9593
+ * option and the value, or a 2D array which will use the array in the first
9594
+ * position as the value, and the array in the second position as the
9595
+ * displayed options (useful for language strings such as 'All').
9596
+ *
9597
+ * Note that the `pageLength` property will be automatically set to the
9598
+ * first value given in this array, unless `pageLength` is also provided.
9599
+ * @type array
9600
+ * @default [ 10, 25, 50, 100 ]
9601
+ *
9602
+ * @dtopt Option
9603
+ * @name DataTable.defaults.lengthMenu
9604
+ *
9605
+ * @example
9606
+ * $(document).ready( function() {
9607
+ * $('#example').dataTable( {
9608
+ * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9609
+ * } );
9610
+ * } );
9611
+ */
9612
+ "aLengthMenu": [ 10, 25, 50, 100 ],
9613
+
9614
+
9615
+ /**
9616
+ * The `columns` option in the initialisation parameter allows you to define
9617
+ * details about the way individual columns behave. For a full list of
9618
+ * column options that can be set, please see
9619
+ * {@link DataTable.defaults.column}. Note that if you use `columns` to
9620
+ * define your columns, you must have an entry in the array for every single
9621
+ * column that you have in your table (these can be null if you don't which
9622
+ * to specify any options).
9623
+ * @member
9624
+ *
9625
+ * @name DataTable.defaults.column
9626
+ */
9627
+ "aoColumns": null,
9628
+
9629
+ /**
9630
+ * Very similar to `columns`, `columnDefs` allows you to target a specific
9631
+ * column, multiple columns, or all columns, using the `targets` property of
9632
+ * each object in the array. This allows great flexibility when creating
9633
+ * tables, as the `columnDefs` arrays can be of any length, targeting the
9634
+ * columns you specifically want. `columnDefs` may use any of the column
9635
+ * options available: {@link DataTable.defaults.column}, but it _must_
9636
+ * have `targets` defined in each object in the array. Values in the `targets`
9637
+ * array may be:
9638
+ * <ul>
9639
+ * <li>a string - class name will be matched on the TH for the column</li>
9640
+ * <li>0 or a positive integer - column index counting from the left</li>
9641
+ * <li>a negative integer - column index counting from the right</li>
9642
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
9643
+ * </ul>
9644
+ * @member
9645
+ *
9646
+ * @name DataTable.defaults.columnDefs
9647
+ */
9648
+ "aoColumnDefs": null,
9649
+
9650
+
9651
+ /**
9652
+ * Basically the same as `search`, this parameter defines the individual column
9653
+ * filtering state at initialisation time. The array must be of the same size
9654
+ * as the number of columns, and each element be an object with the parameters
9655
+ * `search` and `escapeRegex` (the latter is optional). 'null' is also
9656
+ * accepted and the default will be used.
9657
+ * @type array
9658
+ * @default []
9659
+ *
9660
+ * @dtopt Option
9661
+ * @name DataTable.defaults.searchCols
9662
+ *
9663
+ * @example
9664
+ * $(document).ready( function() {
9665
+ * $('#example').dataTable( {
9666
+ * "searchCols": [
9667
+ * null,
9668
+ * { "search": "My filter" },
9669
+ * null,
9670
+ * { "search": "^[0-9]", "escapeRegex": false }
9671
+ * ]
9672
+ * } );
9673
+ * } )
9674
+ */
9675
+ "aoSearchCols": [],
9676
+
9677
+
9678
+ /**
9679
+ * An array of CSS classes that should be applied to displayed rows. This
9680
+ * array may be of any length, and DataTables will apply each class
9681
+ * sequentially, looping when required.
9682
+ * @type array
9683
+ * @default null <i>Will take the values determined by the `oClasses.stripe*`
9684
+ * options</i>
9685
+ *
9686
+ * @dtopt Option
9687
+ * @name DataTable.defaults.stripeClasses
9688
+ *
9689
+ * @example
9690
+ * $(document).ready( function() {
9691
+ * $('#example').dataTable( {
9692
+ * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9693
+ * } );
9694
+ * } )
9695
+ */
9696
+ "asStripeClasses": null,
9697
+
9698
+
9699
+ /**
9700
+ * Enable or disable automatic column width calculation. This can be disabled
9701
+ * as an optimisation (it takes some time to calculate the widths) if the
9702
+ * tables widths are passed in using `columns`.
9703
+ * @type boolean
9704
+ * @default true
9705
+ *
9706
+ * @dtopt Features
9707
+ * @name DataTable.defaults.autoWidth
9708
+ *
9709
+ * @example
9710
+ * $(document).ready( function () {
9711
+ * $('#example').dataTable( {
9712
+ * "autoWidth": false
9713
+ * } );
9714
+ * } );
9715
+ */
9716
+ "bAutoWidth": true,
9717
+
9718
+
9719
+ /**
9720
+ * Deferred rendering can provide DataTables with a huge speed boost when you
9721
+ * are using an Ajax or JS data source for the table. This option, when set to
9722
+ * true, will cause DataTables to defer the creation of the table elements for
9723
+ * each row until they are needed for a draw - saving a significant amount of
9724
+ * time.
9725
+ * @type boolean
9726
+ * @default false
9727
+ *
9728
+ * @dtopt Features
9729
+ * @name DataTable.defaults.deferRender
9730
+ *
9731
+ * @example
9732
+ * $(document).ready( function() {
9733
+ * $('#example').dataTable( {
9734
+ * "ajax": "sources/arrays.txt",
9735
+ * "deferRender": true
9736
+ * } );
9737
+ * } );
9738
+ */
9739
+ "bDeferRender": false,
9740
+
9741
+
9742
+ /**
9743
+ * Replace a DataTable which matches the given selector and replace it with
9744
+ * one which has the properties of the new initialisation object passed. If no
9745
+ * table matches the selector, then the new DataTable will be constructed as
9746
+ * per normal.
9747
+ * @type boolean
9748
+ * @default false
9749
+ *
9750
+ * @dtopt Options
9751
+ * @name DataTable.defaults.destroy
9752
+ *
9753
+ * @example
9754
+ * $(document).ready( function() {
9755
+ * $('#example').dataTable( {
9756
+ * "srollY": "200px",
9757
+ * "paginate": false
9758
+ * } );
9759
+ *
9760
+ * // Some time later....
9761
+ * $('#example').dataTable( {
9762
+ * "filter": false,
9763
+ * "destroy": true
9764
+ * } );
9765
+ * } );
9766
+ */
9767
+ "bDestroy": false,
9768
+
9769
+
9770
+ /**
9771
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
9772
+ * that it allows the end user to input multiple words (space separated) and
9773
+ * will match a row containing those words, even if not in the order that was
9774
+ * specified (this allow matching across multiple columns). Note that if you
9775
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
9776
+ * default filtering input box and retain filtering abilities, please use
9777
+ * {@link DataTable.defaults.dom}.
9778
+ * @type boolean
9779
+ * @default true
9780
+ *
9781
+ * @dtopt Features
9782
+ * @name DataTable.defaults.searching
9783
+ *
9784
+ * @example
9785
+ * $(document).ready( function () {
9786
+ * $('#example').dataTable( {
9787
+ * "searching": false
9788
+ * } );
9789
+ * } );
9790
+ */
9791
+ "bFilter": true,
9792
+
9793
+
9794
+ /**
9795
+ * Enable or disable the table information display. This shows information
9796
+ * about the data that is currently visible on the page, including information
9797
+ * about filtered data if that action is being performed.
9798
+ * @type boolean
9799
+ * @default true
9800
+ *
9801
+ * @dtopt Features
9802
+ * @name DataTable.defaults.info
9803
+ *
9804
+ * @example
9805
+ * $(document).ready( function () {
9806
+ * $('#example').dataTable( {
9807
+ * "info": false
9808
+ * } );
9809
+ * } );
9810
+ */
9811
+ "bInfo": true,
9812
+
9813
+
9814
+ /**
9815
+ * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
9816
+ * slightly different and additional mark-up from what DataTables has
9817
+ * traditionally used).
9818
+ * @type boolean
9819
+ * @default false
9820
+ *
9821
+ * @dtopt Features
9822
+ * @name DataTable.defaults.jQueryUI
9823
+ *
9824
+ * @example
9825
+ * $(document).ready( function() {
9826
+ * $('#example').dataTable( {
9827
+ * "jQueryUI": true
9828
+ * } );
9829
+ * } );
9830
+ */
9831
+ "bJQueryUI": false,
9832
+
9833
+
9834
+ /**
9835
+ * Allows the end user to select the size of a formatted page from a select
9836
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
9837
+ * @type boolean
9838
+ * @default true
9839
+ *
9840
+ * @dtopt Features
9841
+ * @name DataTable.defaults.lengthChange
9842
+ *
9843
+ * @example
9844
+ * $(document).ready( function () {
9845
+ * $('#example').dataTable( {
9846
+ * "lengthChange": false
9847
+ * } );
9848
+ * } );
9849
+ */
9850
+ "bLengthChange": true,
9851
+
9852
+
9853
+ /**
9854
+ * Enable or disable pagination.
9855
+ * @type boolean
9856
+ * @default true
9857
+ *
9858
+ * @dtopt Features
9859
+ * @name DataTable.defaults.paging
9860
+ *
9861
+ * @example
9862
+ * $(document).ready( function () {
9863
+ * $('#example').dataTable( {
9864
+ * "paging": false
9865
+ * } );
9866
+ * } );
9867
+ */
9868
+ "bPaginate": true,
9869
+
9870
+
9871
+ /**
9872
+ * Enable or disable the display of a 'processing' indicator when the table is
9873
+ * being processed (e.g. a sort). This is particularly useful for tables with
9874
+ * large amounts of data where it can take a noticeable amount of time to sort
9875
+ * the entries.
9876
+ * @type boolean
9877
+ * @default false
9878
+ *
9879
+ * @dtopt Features
9880
+ * @name DataTable.defaults.processing
9881
+ *
9882
+ * @example
9883
+ * $(document).ready( function () {
9884
+ * $('#example').dataTable( {
9885
+ * "processing": true
9886
+ * } );
9887
+ * } );
9888
+ */
9889
+ "bProcessing": false,
9890
+
9891
+
9892
+ /**
9893
+ * Retrieve the DataTables object for the given selector. Note that if the
9894
+ * table has already been initialised, this parameter will cause DataTables
9895
+ * to simply return the object that has already been set up - it will not take
9896
+ * account of any changes you might have made to the initialisation object
9897
+ * passed to DataTables (setting this parameter to true is an acknowledgement
9898
+ * that you understand this). `destroy` can be used to reinitialise a table if
9899
+ * you need.
9900
+ * @type boolean
9901
+ * @default false
9902
+ *
9903
+ * @dtopt Options
9904
+ * @name DataTable.defaults.retrieve
9905
+ *
9906
+ * @example
9907
+ * $(document).ready( function() {
9908
+ * initTable();
9909
+ * tableActions();
9910
+ * } );
9911
+ *
9912
+ * function initTable ()
9913
+ * {
9914
+ * return $('#example').dataTable( {
9915
+ * "scrollY": "200px",
9916
+ * "paginate": false,
9917
+ * "retrieve": true
9918
+ * } );
9919
+ * }
9920
+ *
9921
+ * function tableActions ()
9922
+ * {
9923
+ * var table = initTable();
9924
+ * // perform API operations with oTable
9925
+ * }
9926
+ */
9927
+ "bRetrieve": false,
9928
+
9929
+
9930
+ /**
9931
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
9932
+ * the table's viewport to the given height at all times (useful for layout).
9933
+ * However, this can look odd when filtering data down to a small data set,
9934
+ * and the footer is left "floating" further down. This parameter (when
9935
+ * enabled) will cause DataTables to collapse the table's viewport down when
9936
+ * the result set will fit within the given Y height.
9937
+ * @type boolean
9938
+ * @default false
9939
+ *
9940
+ * @dtopt Options
9941
+ * @name DataTable.defaults.scrollCollapse
9942
+ *
9943
+ * @example
9944
+ * $(document).ready( function() {
9945
+ * $('#example').dataTable( {
9946
+ * "scrollY": "200",
9947
+ * "scrollCollapse": true
9948
+ * } );
9949
+ * } );
9950
+ */
9951
+ "bScrollCollapse": false,
9952
+
9953
+
9954
+ /**
9955
+ * Configure DataTables to use server-side processing. Note that the
9956
+ * `ajax` parameter must also be given in order to give DataTables a
9957
+ * source to obtain the required data for each draw.
9958
+ * @type boolean
9959
+ * @default false
9960
+ *
9961
+ * @dtopt Features
9962
+ * @dtopt Server-side
9963
+ * @name DataTable.defaults.serverSide
9964
+ *
9965
+ * @example
9966
+ * $(document).ready( function () {
9967
+ * $('#example').dataTable( {
9968
+ * "serverSide": true,
9969
+ * "ajax": "xhr.php"
9970
+ * } );
9971
+ * } );
9972
+ */
9973
+ "bServerSide": false,
9974
+
9975
+
9976
+ /**
9977
+ * Enable or disable sorting of columns. Sorting of individual columns can be
9978
+ * disabled by the `sortable` option for each column.
9979
+ * @type boolean
9980
+ * @default true
9981
+ *
9982
+ * @dtopt Features
9983
+ * @name DataTable.defaults.ordering
9984
+ *
9985
+ * @example
9986
+ * $(document).ready( function () {
9987
+ * $('#example').dataTable( {
9988
+ * "ordering": false
9989
+ * } );
9990
+ * } );
9991
+ */
9992
+ "bSort": true,
9993
+
9994
+
9995
+ /**
9996
+ * Enable or display DataTables' ability to sort multiple columns at the
9997
+ * same time (activated by shift-click by the user).
9998
+ * @type boolean
9999
+ * @default true
10000
+ *
10001
+ * @dtopt Options
10002
+ * @name DataTable.defaults.orderMulti
10003
+ *
10004
+ * @example
10005
+ * // Disable multiple column sorting ability
10006
+ * $(document).ready( function () {
10007
+ * $('#example').dataTable( {
10008
+ * "orderMulti": false
10009
+ * } );
10010
+ * } );
10011
+ */
10012
+ "bSortMulti": true,
10013
+
10014
+
10015
+ /**
10016
+ * Allows control over whether DataTables should use the top (true) unique
10017
+ * cell that is found for a single column, or the bottom (false - default).
10018
+ * This is useful when using complex headers.
10019
+ * @type boolean
10020
+ * @default false
10021
+ *
10022
+ * @dtopt Options
10023
+ * @name DataTable.defaults.orderCellsTop
10024
+ *
10025
+ * @example
10026
+ * $(document).ready( function() {
10027
+ * $('#example').dataTable( {
10028
+ * "orderCellsTop": true
10029
+ * } );
10030
+ * } );
10031
+ */
10032
+ "bSortCellsTop": false,
10033
+
10034
+
10035
+ /**
10036
+ * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10037
+ * `sorting\_3` to the columns which are currently being sorted on. This is
10038
+ * presented as a feature switch as it can increase processing time (while
10039
+ * classes are removed and added) so for large data sets you might want to
10040
+ * turn this off.
10041
+ * @type boolean
10042
+ * @default true
10043
+ *
10044
+ * @dtopt Features
10045
+ * @name DataTable.defaults.orderClasses
10046
+ *
10047
+ * @example
10048
+ * $(document).ready( function () {
10049
+ * $('#example').dataTable( {
10050
+ * "orderClasses": false
10051
+ * } );
10052
+ * } );
10053
+ */
10054
+ "bSortClasses": true,
10055
+
10056
+
10057
+ /**
10058
+ * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10059
+ * used to save table display information such as pagination information,
10060
+ * display length, filtering and sorting. As such when the end user reloads
10061
+ * the page the display display will match what thy had previously set up.
10062
+ *
10063
+ * Due to the use of `localStorage` the default state saving is not supported
10064
+ * in IE6 or 7. If state saving is required in those browsers, use
10065
+ * `stateSaveCallback` to provide a storage solution such as cookies.
10066
+ * @type boolean
10067
+ * @default false
10068
+ *
10069
+ * @dtopt Features
10070
+ * @name DataTable.defaults.stateSave
10071
+ *
10072
+ * @example
10073
+ * $(document).ready( function () {
10074
+ * $('#example').dataTable( {
10075
+ * "stateSave": true
10076
+ * } );
10077
+ * } );
10078
+ */
10079
+ "bStateSave": false,
10080
+
10081
+
10082
+ /**
10083
+ * This function is called when a TR element is created (and all TD child
10084
+ * elements have been inserted), or registered if using a DOM source, allowing
10085
+ * manipulation of the TR element (adding classes etc).
10086
+ * @type function
10087
+ * @param {node} row "TR" element for the current row
10088
+ * @param {array} data Raw data array for this row
10089
+ * @param {int} dataIndex The index of this row in the internal aoData array
10090
+ *
10091
+ * @dtopt Callbacks
10092
+ * @name DataTable.defaults.createdRow
10093
+ *
10094
+ * @example
10095
+ * $(document).ready( function() {
10096
+ * $('#example').dataTable( {
10097
+ * "createdRow": function( row, data, dataIndex ) {
10098
+ * // Bold the grade for all 'A' grade browsers
10099
+ * if ( data[4] == "A" )
10100
+ * {
10101
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10102
+ * }
10103
+ * }
10104
+ * } );
10105
+ * } );
10106
+ */
10107
+ "fnCreatedRow": null,
10108
+
10109
+
10110
+ /**
10111
+ * This function is called on every 'draw' event, and allows you to
10112
+ * dynamically modify any aspect you want about the created DOM.
10113
+ * @type function
10114
+ * @param {object} settings DataTables settings object
10115
+ *
10116
+ * @dtopt Callbacks
10117
+ * @name DataTable.defaults.drawCallback
10118
+ *
10119
+ * @example
10120
+ * $(document).ready( function() {
10121
+ * $('#example').dataTable( {
10122
+ * "drawCallback": function( settings ) {
10123
+ * alert( 'DataTables has redrawn the table' );
10124
+ * }
10125
+ * } );
10126
+ * } );
10127
+ */
10128
+ "fnDrawCallback": null,
10129
+
10130
+
10131
+ /**
10132
+ * Identical to fnHeaderCallback() but for the table footer this function
10133
+ * allows you to modify the table footer on every 'draw' event.
10134
+ * @type function
10135
+ * @param {node} foot "TR" element for the footer
10136
+ * @param {array} data Full table data (as derived from the original HTML)
10137
+ * @param {int} start Index for the current display starting point in the
10138
+ * display array
10139
+ * @param {int} end Index for the current display ending point in the
10140
+ * display array
10141
+ * @param {array int} display Index array to translate the visual position
10142
+ * to the full data array
10143
+ *
10144
+ * @dtopt Callbacks
10145
+ * @name DataTable.defaults.footerCallback
10146
+ *
10147
+ * @example
10148
+ * $(document).ready( function() {
10149
+ * $('#example').dataTable( {
10150
+ * "footerCallback": function( tfoot, data, start, end, display ) {
10151
+ * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10152
+ * }
10153
+ * } );
10154
+ * } )
10155
+ */
10156
+ "fnFooterCallback": null,
10157
+
10158
+
10159
+ /**
10160
+ * When rendering large numbers in the information element for the table
10161
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10162
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
10163
+ * rendered as "1,000,000") to help readability for the end user. This
10164
+ * function will override the default method DataTables uses.
10165
+ * @type function
10166
+ * @member
10167
+ * @param {int} toFormat number to be formatted
10168
+ * @returns {string} formatted string for DataTables to show the number
10169
+ *
10170
+ * @dtopt Callbacks
10171
+ * @name DataTable.defaults.formatNumber
10172
+ *
10173
+ * @example
10174
+ * // Format a number using a single quote for the separator (note that
10175
+ * // this can also be done with the language.thousands option)
10176
+ * $(document).ready( function() {
10177
+ * $('#example').dataTable( {
10178
+ * "formatNumber": function ( toFormat ) {
10179
+ * return toFormat.toString().replace(
10180
+ * /\B(?=(\d{3})+(?!\d))/g, "'"
10181
+ * );
10182
+ * };
10183
+ * } );
10184
+ * } );
10185
+ */
10186
+ "fnFormatNumber": function ( toFormat ) {
10187
+ return toFormat.toString().replace(
10188
+ /\B(?=(\d{3})+(?!\d))/g,
10189
+ this.oLanguage.sThousands
10190
+ );
10191
+ },
10192
+
10193
+
10194
+ /**
10195
+ * This function is called on every 'draw' event, and allows you to
10196
+ * dynamically modify the header row. This can be used to calculate and
10197
+ * display useful information about the table.
10198
+ * @type function
10199
+ * @param {node} head "TR" element for the header
10200
+ * @param {array} data Full table data (as derived from the original HTML)
10201
+ * @param {int} start Index for the current display starting point in the
10202
+ * display array
10203
+ * @param {int} end Index for the current display ending point in the
10204
+ * display array
10205
+ * @param {array int} display Index array to translate the visual position
10206
+ * to the full data array
10207
+ *
10208
+ * @dtopt Callbacks
10209
+ * @name DataTable.defaults.headerCallback
10210
+ *
10211
+ * @example
10212
+ * $(document).ready( function() {
10213
+ * $('#example').dataTable( {
10214
+ * "fheaderCallback": function( head, data, start, end, display ) {
10215
+ * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10216
+ * }
10217
+ * } );
10218
+ * } )
10219
+ */
10220
+ "fnHeaderCallback": null,
10221
+
10222
+
10223
+ /**
10224
+ * The information element can be used to convey information about the current
10225
+ * state of the table. Although the internationalisation options presented by
10226
+ * DataTables are quite capable of dealing with most customisations, there may
10227
+ * be times where you wish to customise the string further. This callback
10228
+ * allows you to do exactly that.
10229
+ * @type function
10230
+ * @param {object} oSettings DataTables settings object
10231
+ * @param {int} start Starting position in data for the draw
10232
+ * @param {int} end End position in data for the draw
10233
+ * @param {int} max Total number of rows in the table (regardless of
10234
+ * filtering)
10235
+ * @param {int} total Total number of rows in the data set, after filtering
10236
+ * @param {string} pre The string that DataTables has formatted using it's
10237
+ * own rules
10238
+ * @returns {string} The string to be displayed in the information element.
10239
+ *
10240
+ * @dtopt Callbacks
10241
+ * @name DataTable.defaults.infoCallback
10242
+ *
10243
+ * @example
10244
+ * $('#example').dataTable( {
10245
+ * "infoCallback": function( settings, start, end, max, total, pre ) {
10246
+ * return start +" to "+ end;
10247
+ * }
10248
+ * } );
10249
+ */
10250
+ "fnInfoCallback": null,
10251
+
10252
+
10253
+ /**
10254
+ * Called when the table has been initialised. Normally DataTables will
10255
+ * initialise sequentially and there will be no need for this function,
10256
+ * however, this does not hold true when using external language information
10257
+ * since that is obtained using an async XHR call.
10258
+ * @type function
10259
+ * @param {object} settings DataTables settings object
10260
+ * @param {object} json The JSON object request from the server - only
10261
+ * present if client-side Ajax sourced data is used
10262
+ *
10263
+ * @dtopt Callbacks
10264
+ * @name DataTable.defaults.initComplete
10265
+ *
10266
+ * @example
10267
+ * $(document).ready( function() {
10268
+ * $('#example').dataTable( {
10269
+ * "initComplete": function(settings, json) {
10270
+ * alert( 'DataTables has finished its initialisation.' );
10271
+ * }
10272
+ * } );
10273
+ * } )
10274
+ */
10275
+ "fnInitComplete": null,
10276
+
10277
+
10278
+ /**
10279
+ * Called at the very start of each table draw and can be used to cancel the
10280
+ * draw by returning false, any other return (including undefined) results in
10281
+ * the full draw occurring).
10282
+ * @type function
10283
+ * @param {object} settings DataTables settings object
10284
+ * @returns {boolean} False will cancel the draw, anything else (including no
10285
+ * return) will allow it to complete.
10286
+ *
10287
+ * @dtopt Callbacks
10288
+ * @name DataTable.defaults.preDrawCallback
10289
+ *
10290
+ * @example
10291
+ * $(document).ready( function() {
10292
+ * $('#example').dataTable( {
10293
+ * "preDrawCallback": function( settings ) {
10294
+ * if ( $('#test').val() == 1 ) {
10295
+ * return false;
10296
+ * }
10297
+ * }
10298
+ * } );
10299
+ * } );
10300
+ */
10301
+ "fnPreDrawCallback": null,
10302
+
10303
+
10304
+ /**
10305
+ * This function allows you to 'post process' each row after it have been
10306
+ * generated for each table draw, but before it is rendered on screen. This
10307
+ * function might be used for setting the row class name etc.
10308
+ * @type function
10309
+ * @param {node} row "TR" element for the current row
10310
+ * @param {array} data Raw data array for this row
10311
+ * @param {int} displayIndex The display index for the current table draw
10312
+ * @param {int} displayIndexFull The index of the data in the full list of
10313
+ * rows (after filtering)
10314
+ *
10315
+ * @dtopt Callbacks
10316
+ * @name DataTable.defaults.rowCallback
10317
+ *
10318
+ * @example
10319
+ * $(document).ready( function() {
10320
+ * $('#example').dataTable( {
10321
+ * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10322
+ * // Bold the grade for all 'A' grade browsers
10323
+ * if ( data[4] == "A" ) {
10324
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10325
+ * }
10326
+ * }
10327
+ * } );
10328
+ * } );
10329
+ */
10330
+ "fnRowCallback": null,
10331
+
10332
+
10333
+ /**
10334
+ * __Deprecated__ The functionality provided by this parameter has now been
10335
+ * superseded by that provided through `ajax`, which should be used instead.
10336
+ *
10337
+ * This parameter allows you to override the default function which obtains
10338
+ * the data from the server so something more suitable for your application.
10339
+ * For example you could use POST data, or pull information from a Gears or
10340
+ * AIR database.
10341
+ * @type function
10342
+ * @member
10343
+ * @param {string} source HTTP source to obtain the data from (`ajax`)
10344
+ * @param {array} data A key/value pair object containing the data to send
10345
+ * to the server
10346
+ * @param {function} callback to be called on completion of the data get
10347
+ * process that will draw the data on the page.
10348
+ * @param {object} settings DataTables settings object
10349
+ *
10350
+ * @dtopt Callbacks
10351
+ * @dtopt Server-side
10352
+ * @name DataTable.defaults.serverData
10353
+ *
10354
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10355
+ */
10356
+ "fnServerData": null,
10357
+
10358
+
10359
+ /**
10360
+ * __Deprecated__ The functionality provided by this parameter has now been
10361
+ * superseded by that provided through `ajax`, which should be used instead.
10362
+ *
10363
+ * It is often useful to send extra data to the server when making an Ajax
10364
+ * request - for example custom filtering information, and this callback
10365
+ * function makes it trivial to send extra information to the server. The
10366
+ * passed in parameter is the data set that has been constructed by
10367
+ * DataTables, and you can add to this or modify it as you require.
10368
+ * @type function
10369
+ * @param {array} data Data array (array of objects which are name/value
10370
+ * pairs) that has been constructed by DataTables and will be sent to the
10371
+ * server. In the case of Ajax sourced data with server-side processing
10372
+ * this will be an empty array, for server-side processing there will be a
10373
+ * significant number of parameters!
10374
+ * @returns {undefined} Ensure that you modify the data array passed in,
10375
+ * as this is passed by reference.
10376
+ *
10377
+ * @dtopt Callbacks
10378
+ * @dtopt Server-side
10379
+ * @name DataTable.defaults.serverParams
10380
+ *
10381
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10382
+ */
10383
+ "fnServerParams": null,
10384
+
10385
+
10386
+ /**
10387
+ * Load the table state. With this function you can define from where, and how, the
10388
+ * state of a table is loaded. By default DataTables will load from `localStorage`
10389
+ * but you might wish to use a server-side database or cookies.
10390
+ * @type function
10391
+ * @member
10392
+ * @param {object} settings DataTables settings object
10393
+ * @return {object} The DataTables state object to be loaded
10394
+ *
10395
+ * @dtopt Callbacks
10396
+ * @name DataTable.defaults.stateLoadCallback
10397
+ *
10398
+ * @example
10399
+ * $(document).ready( function() {
10400
+ * $('#example').dataTable( {
10401
+ * "stateSave": true,
10402
+ * "stateLoadCallback": function (settings) {
10403
+ * var o;
10404
+ *
10405
+ * // Send an Ajax request to the server to get the data. Note that
10406
+ * // this is a synchronous request.
10407
+ * $.ajax( {
10408
+ * "url": "/state_load",
10409
+ * "async": false,
10410
+ * "dataType": "json",
10411
+ * "success": function (json) {
10412
+ * o = json;
10413
+ * }
10414
+ * } );
10415
+ *
10416
+ * return o;
10417
+ * }
10418
+ * } );
10419
+ * } );
10420
+ */
10421
+ "fnStateLoadCallback": function ( settings ) {
10422
+ try {
10423
+ return JSON.parse(
10424
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10425
+ 'DataTables_'+settings.sInstance+'_'+location.pathname
10426
+ )
10427
+ );
10428
+ } catch (e) {}
10429
+ },
10430
+
10431
+
10432
+ /**
10433
+ * Callback which allows modification of the saved state prior to loading that state.
10434
+ * This callback is called when the table is loading state from the stored data, but
10435
+ * prior to the settings object being modified by the saved state. Note that for
10436
+ * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10437
+ * a plug-in.
10438
+ * @type function
10439
+ * @param {object} settings DataTables settings object
10440
+ * @param {object} data The state object that is to be loaded
10441
+ *
10442
+ * @dtopt Callbacks
10443
+ * @name DataTable.defaults.stateLoadParams
10444
+ *
10445
+ * @example
10446
+ * // Remove a saved filter, so filtering is never loaded
10447
+ * $(document).ready( function() {
10448
+ * $('#example').dataTable( {
10449
+ * "stateSave": true,
10450
+ * "stateLoadParams": function (settings, data) {
10451
+ * data.oSearch.sSearch = "";
10452
+ * }
10453
+ * } );
10454
+ * } );
10455
+ *
10456
+ * @example
10457
+ * // Disallow state loading by returning false
10458
+ * $(document).ready( function() {
10459
+ * $('#example').dataTable( {
10460
+ * "stateSave": true,
10461
+ * "stateLoadParams": function (settings, data) {
10462
+ * return false;
10463
+ * }
10464
+ * } );
10465
+ * } );
10466
+ */
10467
+ "fnStateLoadParams": null,
10468
+
10469
+
10470
+ /**
10471
+ * Callback that is called when the state has been loaded from the state saving method
10472
+ * and the DataTables settings object has been modified as a result of the loaded state.
10473
+ * @type function
10474
+ * @param {object} settings DataTables settings object
10475
+ * @param {object} data The state object that was loaded
10476
+ *
10477
+ * @dtopt Callbacks
10478
+ * @name DataTable.defaults.stateLoaded
10479
+ *
10480
+ * @example
10481
+ * // Show an alert with the filtering value that was saved
10482
+ * $(document).ready( function() {
10483
+ * $('#example').dataTable( {
10484
+ * "stateSave": true,
10485
+ * "stateLoaded": function (settings, data) {
10486
+ * alert( 'Saved filter was: '+data.oSearch.sSearch );
10487
+ * }
10488
+ * } );
10489
+ * } );
10490
+ */
10491
+ "fnStateLoaded": null,
10492
+
10493
+
10494
+ /**
10495
+ * Save the table state. This function allows you to define where and how the state
10496
+ * information for the table is stored By default DataTables will use `localStorage`
10497
+ * but you might wish to use a server-side database or cookies.
10498
+ * @type function
10499
+ * @member
10500
+ * @param {object} settings DataTables settings object
10501
+ * @param {object} data The state object to be saved
10502
+ *
10503
+ * @dtopt Callbacks
10504
+ * @name DataTable.defaults.stateSaveCallback
10505
+ *
10506
+ * @example
10507
+ * $(document).ready( function() {
10508
+ * $('#example').dataTable( {
10509
+ * "stateSave": true,
10510
+ * "stateSaveCallback": function (settings, data) {
10511
+ * // Send an Ajax request to the server with the state object
10512
+ * $.ajax( {
10513
+ * "url": "/state_save",
10514
+ * "data": data,
10515
+ * "dataType": "json",
10516
+ * "method": "POST"
10517
+ * "success": function () {}
10518
+ * } );
10519
+ * }
10520
+ * } );
10521
+ * } );
10522
+ */
10523
+ "fnStateSaveCallback": function ( settings, data ) {
10524
+ try {
10525
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10526
+ 'DataTables_'+settings.sInstance+'_'+location.pathname,
10527
+ JSON.stringify( data )
10528
+ );
10529
+ } catch (e) {}
10530
+ },
10531
+
10532
+
10533
+ /**
10534
+ * Callback which allows modification of the state to be saved. Called when the table
10535
+ * has changed state a new state save is required. This method allows modification of
10536
+ * the state saving object prior to actually doing the save, including addition or
10537
+ * other state properties or modification. Note that for plug-in authors, you should
10538
+ * use the `stateSaveParams` event to save parameters for a plug-in.
10539
+ * @type function
10540
+ * @param {object} settings DataTables settings object
10541
+ * @param {object} data The state object to be saved
10542
+ *
10543
+ * @dtopt Callbacks
10544
+ * @name DataTable.defaults.stateSaveParams
10545
+ *
10546
+ * @example
10547
+ * // Remove a saved filter, so filtering is never saved
10548
+ * $(document).ready( function() {
10549
+ * $('#example').dataTable( {
10550
+ * "stateSave": true,
10551
+ * "stateSaveParams": function (settings, data) {
10552
+ * data.oSearch.sSearch = "";
10553
+ * }
10554
+ * } );
10555
+ * } );
10556
+ */
10557
+ "fnStateSaveParams": null,
10558
+
10559
+
10560
+ /**
10561
+ * Duration for which the saved state information is considered valid. After this period
10562
+ * has elapsed the state will be returned to the default.
10563
+ * Value is given in seconds.
10564
+ * @type int
10565
+ * @default 7200 <i>(2 hours)</i>
10566
+ *
10567
+ * @dtopt Options
10568
+ * @name DataTable.defaults.stateDuration
10569
+ *
10570
+ * @example
10571
+ * $(document).ready( function() {
10572
+ * $('#example').dataTable( {
10573
+ * "stateDuration": 60*60*24; // 1 day
10574
+ * } );
10575
+ * } )
10576
+ */
10577
+ "iStateDuration": 7200,
10578
+
10579
+
10580
+ /**
10581
+ * When enabled DataTables will not make a request to the server for the first
10582
+ * page draw - rather it will use the data already on the page (no sorting etc
10583
+ * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10584
+ * is used to indicate that deferred loading is required, but it is also used
10585
+ * to tell DataTables how many records there are in the full table (allowing
10586
+ * the information element and pagination to be displayed correctly). In the case
10587
+ * where a filtering is applied to the table on initial load, this can be
10588
+ * indicated by giving the parameter as an array, where the first element is
10589
+ * the number of records available after filtering and the second element is the
10590
+ * number of records without filtering (allowing the table information element
10591
+ * to be shown correctly).
10592
+ * @type int | array
10593
+ * @default null
10594
+ *
10595
+ * @dtopt Options
10596
+ * @name DataTable.defaults.deferLoading
10597
+ *
10598
+ * @example
10599
+ * // 57 records available in the table, no filtering applied
10600
+ * $(document).ready( function() {
10601
+ * $('#example').dataTable( {
10602
+ * "serverSide": true,
10603
+ * "ajax": "scripts/server_processing.php",
10604
+ * "deferLoading": 57
10605
+ * } );
10606
+ * } );
10607
+ *
10608
+ * @example
10609
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
10610
+ * $(document).ready( function() {
10611
+ * $('#example').dataTable( {
10612
+ * "serverSide": true,
10613
+ * "ajax": "scripts/server_processing.php",
10614
+ * "deferLoading": [ 57, 100 ],
10615
+ * "search": {
10616
+ * "search": "my_filter"
10617
+ * }
10618
+ * } );
10619
+ * } );
10620
+ */
10621
+ "iDeferLoading": null,
10622
+
10623
+
10624
+ /**
10625
+ * Number of rows to display on a single page when using pagination. If
10626
+ * feature enabled (`lengthChange`) then the end user will be able to override
10627
+ * this to a custom setting using a pop-up menu.
10628
+ * @type int
10629
+ * @default 10
10630
+ *
10631
+ * @dtopt Options
10632
+ * @name DataTable.defaults.pageLength
10633
+ *
10634
+ * @example
10635
+ * $(document).ready( function() {
10636
+ * $('#example').dataTable( {
10637
+ * "pageLength": 50
10638
+ * } );
10639
+ * } )
10640
+ */
10641
+ "iDisplayLength": 10,
10642
+
10643
+
10644
+ /**
10645
+ * Define the starting point for data display when using DataTables with
10646
+ * pagination. Note that this parameter is the number of records, rather than
10647
+ * the page number, so if you have 10 records per page and want to start on
10648
+ * the third page, it should be "20".
10649
+ * @type int
10650
+ * @default 0
10651
+ *
10652
+ * @dtopt Options
10653
+ * @name DataTable.defaults.displayStart
10654
+ *
10655
+ * @example
10656
+ * $(document).ready( function() {
10657
+ * $('#example').dataTable( {
10658
+ * "displayStart": 20
10659
+ * } );
10660
+ * } )
10661
+ */
10662
+ "iDisplayStart": 0,
10663
+
10664
+
10665
+ /**
10666
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
10667
+ * and filtering) by adding a `tabindex` attribute to the required elements. This
10668
+ * allows you to tab through the controls and press the enter key to activate them.
10669
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
10670
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
10671
+ * disable built-in keyboard navigation.
10672
+ * @type int
10673
+ * @default 0
10674
+ *
10675
+ * @dtopt Options
10676
+ * @name DataTable.defaults.tabIndex
10677
+ *
10678
+ * @example
10679
+ * $(document).ready( function() {
10680
+ * $('#example').dataTable( {
10681
+ * "tabIndex": 1
10682
+ * } );
10683
+ * } );
10684
+ */
10685
+ "iTabIndex": 0,
10686
+
10687
+
10688
+ /**
10689
+ * Classes that DataTables assigns to the various components and features
10690
+ * that it adds to the HTML table. This allows classes to be configured
10691
+ * during initialisation in addition to through the static
10692
+ * {@link DataTable.ext.oStdClasses} object).
10693
+ * @namespace
10694
+ * @name DataTable.defaults.classes
10695
+ */
10696
+ "oClasses": {},
10697
+
10698
+
10699
+ /**
10700
+ * All strings that DataTables uses in the user interface that it creates
10701
+ * are defined in this object, allowing you to modified them individually or
10702
+ * completely replace them all as required.
10703
+ * @namespace
10704
+ * @name DataTable.defaults.language
10705
+ */
10706
+ "oLanguage": {
10707
+ /**
10708
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
10709
+ * actually visible on the page, but will be read by screenreaders, and thus
10710
+ * must be internationalised as well).
10711
+ * @namespace
10712
+ * @name DataTable.defaults.language.aria
10713
+ */
10714
+ "oAria": {
10715
+ /**
10716
+ * ARIA label that is added to the table headers when the column may be
10717
+ * sorted ascending by activing the column (click or return when focused).
10718
+ * Note that the column header is prefixed to this string.
10719
+ * @type string
10720
+ * @default : activate to sort column ascending
10721
+ *
10722
+ * @dtopt Language
10723
+ * @name DataTable.defaults.language.aria.sortAscending
10724
+ *
10725
+ * @example
10726
+ * $(document).ready( function() {
10727
+ * $('#example').dataTable( {
10728
+ * "language": {
10729
+ * "aria": {
10730
+ * "sortAscending": " - click/return to sort ascending"
10731
+ * }
10732
+ * }
10733
+ * } );
10734
+ * } );
10735
+ */
10736
+ "sSortAscending": ": activate to sort column ascending",
10737
+
10738
+ /**
10739
+ * ARIA label that is added to the table headers when the column may be
10740
+ * sorted descending by activing the column (click or return when focused).
10741
+ * Note that the column header is prefixed to this string.
10742
+ * @type string
10743
+ * @default : activate to sort column ascending
10744
+ *
10745
+ * @dtopt Language
10746
+ * @name DataTable.defaults.language.aria.sortDescending
10747
+ *
10748
+ * @example
10749
+ * $(document).ready( function() {
10750
+ * $('#example').dataTable( {
10751
+ * "language": {
10752
+ * "aria": {
10753
+ * "sortDescending": " - click/return to sort descending"
10754
+ * }
10755
+ * }
10756
+ * } );
10757
+ * } );
10758
+ */
10759
+ "sSortDescending": ": activate to sort column descending"
10760
+ },
10761
+
10762
+ /**
10763
+ * Pagination string used by DataTables for the built-in pagination
10764
+ * control types.
10765
+ * @namespace
10766
+ * @name DataTable.defaults.language.paginate
10767
+ */
10768
+ "oPaginate": {
10769
+ /**
10770
+ * Text to use when using the 'full_numbers' type of pagination for the
10771
+ * button to take the user to the first page.
10772
+ * @type string
10773
+ * @default First
10774
+ *
10775
+ * @dtopt Language
10776
+ * @name DataTable.defaults.language.paginate.first
10777
+ *
10778
+ * @example
10779
+ * $(document).ready( function() {
10780
+ * $('#example').dataTable( {
10781
+ * "language": {
10782
+ * "paginate": {
10783
+ * "first": "First page"
10784
+ * }
10785
+ * }
10786
+ * } );
10787
+ * } );
10788
+ */
10789
+ "sFirst": "First",
10790
+
10791
+
10792
+ /**
10793
+ * Text to use when using the 'full_numbers' type of pagination for the
10794
+ * button to take the user to the last page.
10795
+ * @type string
10796
+ * @default Last
10797
+ *
10798
+ * @dtopt Language
10799
+ * @name DataTable.defaults.language.paginate.last
10800
+ *
10801
+ * @example
10802
+ * $(document).ready( function() {
10803
+ * $('#example').dataTable( {
10804
+ * "language": {
10805
+ * "paginate": {
10806
+ * "last": "Last page"
10807
+ * }
10808
+ * }
10809
+ * } );
10810
+ * } );
10811
+ */
10812
+ "sLast": "Last",
10813
+
10814
+
10815
+ /**
10816
+ * Text to use for the 'next' pagination button (to take the user to the
10817
+ * next page).
10818
+ * @type string
10819
+ * @default Next
10820
+ *
10821
+ * @dtopt Language
10822
+ * @name DataTable.defaults.language.paginate.next
10823
+ *
10824
+ * @example
10825
+ * $(document).ready( function() {
10826
+ * $('#example').dataTable( {
10827
+ * "language": {
10828
+ * "paginate": {
10829
+ * "next": "Next page"
10830
+ * }
10831
+ * }
10832
+ * } );
10833
+ * } );
10834
+ */
10835
+ "sNext": "Next",
10836
+
10837
+
10838
+ /**
10839
+ * Text to use for the 'previous' pagination button (to take the user to
10840
+ * the previous page).
10841
+ * @type string
10842
+ * @default Previous
10843
+ *
10844
+ * @dtopt Language
10845
+ * @name DataTable.defaults.language.paginate.previous
10846
+ *
10847
+ * @example
10848
+ * $(document).ready( function() {
10849
+ * $('#example').dataTable( {
10850
+ * "language": {
10851
+ * "paginate": {
10852
+ * "previous": "Previous page"
10853
+ * }
10854
+ * }
10855
+ * } );
10856
+ * } );
10857
+ */
10858
+ "sPrevious": "Previous"
10859
+ },
10860
+
10861
+ /**
10862
+ * This string is shown in preference to `zeroRecords` when the table is
10863
+ * empty of data (regardless of filtering). Note that this is an optional
10864
+ * parameter - if it is not given, the value of `zeroRecords` will be used
10865
+ * instead (either the default or given value).
10866
+ * @type string
10867
+ * @default No data available in table
10868
+ *
10869
+ * @dtopt Language
10870
+ * @name DataTable.defaults.language.emptyTable
10871
+ *
10872
+ * @example
10873
+ * $(document).ready( function() {
10874
+ * $('#example').dataTable( {
10875
+ * "language": {
10876
+ * "emptyTable": "No data available in table"
10877
+ * }
10878
+ * } );
10879
+ * } );
10880
+ */
10881
+ "sEmptyTable": "No data available in table",
10882
+
10883
+
10884
+ /**
10885
+ * This string gives information to the end user about the information
10886
+ * that is current on display on the page. The following tokens can be
10887
+ * used in the string and will be dynamically replaced as the table
10888
+ * display updates. This tokens can be placed anywhere in the string, or
10889
+ * removed as needed by the language requires:
10890
+ *
10891
+ * * `\_START\_` - Display index of the first record on the current page
10892
+ * * `\_END\_` - Display index of the last record on the current page
10893
+ * * `\_TOTAL\_` - Number of records in the table after filtering
10894
+ * * `\_MAX\_` - Number of records in the table without filtering
10895
+ * * `\_PAGE\_` - Current page number
10896
+ * * `\_PAGES\_` - Total number of pages of data in the table
10897
+ *
10898
+ * @type string
10899
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
10900
+ *
10901
+ * @dtopt Language
10902
+ * @name DataTable.defaults.language.info
10903
+ *
10904
+ * @example
10905
+ * $(document).ready( function() {
10906
+ * $('#example').dataTable( {
10907
+ * "language": {
10908
+ * "info": "Showing page _PAGE_ of _PAGES_"
10909
+ * }
10910
+ * } );
10911
+ * } );
10912
+ */
10913
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
10914
+
10915
+
10916
+ /**
10917
+ * Display information string for when the table is empty. Typically the
10918
+ * format of this string should match `info`.
10919
+ * @type string
10920
+ * @default Showing 0 to 0 of 0 entries
10921
+ *
10922
+ * @dtopt Language
10923
+ * @name DataTable.defaults.language.infoEmpty
10924
+ *
10925
+ * @example
10926
+ * $(document).ready( function() {
10927
+ * $('#example').dataTable( {
10928
+ * "language": {
10929
+ * "infoEmpty": "No entries to show"
10930
+ * }
10931
+ * } );
10932
+ * } );
10933
+ */
10934
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
10935
+
10936
+
10937
+ /**
10938
+ * When a user filters the information in a table, this string is appended
10939
+ * to the information (`info`) to give an idea of how strong the filtering
10940
+ * is. The variable _MAX_ is dynamically updated.
10941
+ * @type string
10942
+ * @default (filtered from _MAX_ total entries)
10943
+ *
10944
+ * @dtopt Language
10945
+ * @name DataTable.defaults.language.infoFiltered
10946
+ *
10947
+ * @example
10948
+ * $(document).ready( function() {
10949
+ * $('#example').dataTable( {
10950
+ * "language": {
10951
+ * "infoFiltered": " - filtering from _MAX_ records"
10952
+ * }
10953
+ * } );
10954
+ * } );
10955
+ */
10956
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
10957
+
10958
+
10959
+ /**
10960
+ * If can be useful to append extra information to the info string at times,
10961
+ * and this variable does exactly that. This information will be appended to
10962
+ * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
10963
+ * being used) at all times.
10964
+ * @type string
10965
+ * @default <i>Empty string</i>
10966
+ *
10967
+ * @dtopt Language
10968
+ * @name DataTable.defaults.language.infoPostFix
10969
+ *
10970
+ * @example
10971
+ * $(document).ready( function() {
10972
+ * $('#example').dataTable( {
10973
+ * "language": {
10974
+ * "infoPostFix": "All records shown are derived from real information."
10975
+ * }
10976
+ * } );
10977
+ * } );
10978
+ */
10979
+ "sInfoPostFix": "",
10980
+
10981
+
10982
+ /**
10983
+ * This decimal place operator is a little different from the other
10984
+ * language options since DataTables doesn't output floating point
10985
+ * numbers, so it won't ever use this for display of a number. Rather,
10986
+ * what this parameter does is modify the sort methods of the table so
10987
+ * that numbers which are in a format which has a character other than
10988
+ * a period (`.`) as a decimal place will be sorted numerically.
10989
+ *
10990
+ * Note that numbers with different decimal places cannot be shown in
10991
+ * the same table and still be sortable, the table must be consistent.
10992
+ * However, multiple different tables on the page can use different
10993
+ * decimal place characters.
10994
+ * @type string
10995
+ * @default
10996
+ *
10997
+ * @dtopt Language
10998
+ * @name DataTable.defaults.language.decimal
10999
+ *
11000
+ * @example
11001
+ * $(document).ready( function() {
11002
+ * $('#example').dataTable( {
11003
+ * "language": {
11004
+ * "decimal": ","
11005
+ * "thousands": "."
11006
+ * }
11007
+ * } );
11008
+ * } );
11009
+ */
11010
+ "sDecimal": "",
11011
+
11012
+
11013
+ /**
11014
+ * DataTables has a build in number formatter (`formatNumber`) which is
11015
+ * used to format large numbers that are used in the table information.
11016
+ * By default a comma is used, but this can be trivially changed to any
11017
+ * character you wish with this parameter.
11018
+ * @type string
11019
+ * @default ,
11020
+ *
11021
+ * @dtopt Language
11022
+ * @name DataTable.defaults.language.thousands
11023
+ *
11024
+ * @example
11025
+ * $(document).ready( function() {
11026
+ * $('#example').dataTable( {
11027
+ * "language": {
11028
+ * "thousands": "'"
11029
+ * }
11030
+ * } );
11031
+ * } );
11032
+ */
11033
+ "sThousands": ",",
11034
+
11035
+
11036
+ /**
11037
+ * Detail the action that will be taken when the drop down menu for the
11038
+ * pagination length option is changed. The '_MENU_' variable is replaced
11039
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
11040
+ * with a custom select box if required.
11041
+ * @type string
11042
+ * @default Show _MENU_ entries
11043
+ *
11044
+ * @dtopt Language
11045
+ * @name DataTable.defaults.language.lengthMenu
11046
+ *
11047
+ * @example
11048
+ * // Language change only
11049
+ * $(document).ready( function() {
11050
+ * $('#example').dataTable( {
11051
+ * "language": {
11052
+ * "lengthMenu": "Display _MENU_ records"
11053
+ * }
11054
+ * } );
11055
+ * } );
11056
+ *
11057
+ * @example
11058
+ * // Language and options change
11059
+ * $(document).ready( function() {
11060
+ * $('#example').dataTable( {
11061
+ * "language": {
11062
+ * "lengthMenu": 'Display <select>'+
11063
+ * '<option value="10">10</option>'+
11064
+ * '<option value="20">20</option>'+
11065
+ * '<option value="30">30</option>'+
11066
+ * '<option value="40">40</option>'+
11067
+ * '<option value="50">50</option>'+
11068
+ * '<option value="-1">All</option>'+
11069
+ * '</select> records'
11070
+ * }
11071
+ * } );
11072
+ * } );
11073
+ */
11074
+ "sLengthMenu": "Show _MENU_ entries",
11075
+
11076
+
11077
+ /**
11078
+ * When using Ajax sourced data and during the first draw when DataTables is
11079
+ * gathering the data, this message is shown in an empty row in the table to
11080
+ * indicate to the end user the the data is being loaded. Note that this
11081
+ * parameter is not used when loading data by server-side processing, just
11082
+ * Ajax sourced data with client-side processing.
11083
+ * @type string
11084
+ * @default Loading...
11085
+ *
11086
+ * @dtopt Language
11087
+ * @name DataTable.defaults.language.loadingRecords
11088
+ *
11089
+ * @example
11090
+ * $(document).ready( function() {
11091
+ * $('#example').dataTable( {
11092
+ * "language": {
11093
+ * "loadingRecords": "Please wait - loading..."
11094
+ * }
11095
+ * } );
11096
+ * } );
11097
+ */
11098
+ "sLoadingRecords": "Loading...",
11099
+
11100
+
11101
+ /**
11102
+ * Text which is displayed when the table is processing a user action
11103
+ * (usually a sort command or similar).
11104
+ * @type string
11105
+ * @default Processing...
11106
+ *
11107
+ * @dtopt Language
11108
+ * @name DataTable.defaults.language.processing
11109
+ *
11110
+ * @example
11111
+ * $(document).ready( function() {
11112
+ * $('#example').dataTable( {
11113
+ * "language": {
11114
+ * "processing": "DataTables is currently busy"
11115
+ * }
11116
+ * } );
11117
+ * } );
11118
+ */
11119
+ "sProcessing": "Processing...",
11120
+
11121
+
11122
+ /**
11123
+ * Details the actions that will be taken when the user types into the
11124
+ * filtering input text box. The variable "_INPUT_", if used in the string,
11125
+ * is replaced with the HTML text box for the filtering input allowing
11126
+ * control over where it appears in the string. If "_INPUT_" is not given
11127
+ * then the input box is appended to the string automatically.
11128
+ * @type string
11129
+ * @default Search:
11130
+ *
11131
+ * @dtopt Language
11132
+ * @name DataTable.defaults.language.search
11133
+ *
11134
+ * @example
11135
+ * // Input text box will be appended at the end automatically
11136
+ * $(document).ready( function() {
11137
+ * $('#example').dataTable( {
11138
+ * "language": {
11139
+ * "search": "Filter records:"
11140
+ * }
11141
+ * } );
11142
+ * } );
11143
+ *
11144
+ * @example
11145
+ * // Specify where the filter should appear
11146
+ * $(document).ready( function() {
11147
+ * $('#example').dataTable( {
11148
+ * "language": {
11149
+ * "search": "Apply filter _INPUT_ to table"
11150
+ * }
11151
+ * } );
11152
+ * } );
11153
+ */
11154
+ "sSearch": "Search:",
11155
+
11156
+
11157
+ /**
11158
+ * Assign a `placeholder` attribute to the search `input` element
11159
+ * @type string
11160
+ * @default
11161
+ *
11162
+ * @dtopt Language
11163
+ * @name DataTable.defaults.language.searchPlaceholder
11164
+ */
11165
+ "sSearchPlaceholder": "",
11166
+
11167
+
11168
+ /**
11169
+ * All of the language information can be stored in a file on the
11170
+ * server-side, which DataTables will look up if this parameter is passed.
11171
+ * It must store the URL of the language file, which is in a JSON format,
11172
+ * and the object has the same properties as the oLanguage object in the
11173
+ * initialiser object (i.e. the above parameters). Please refer to one of
11174
+ * the example language files to see how this works in action.
11175
+ * @type string
11176
+ * @default <i>Empty string - i.e. disabled</i>
11177
+ *
11178
+ * @dtopt Language
11179
+ * @name DataTable.defaults.language.url
11180
+ *
11181
+ * @example
11182
+ * $(document).ready( function() {
11183
+ * $('#example').dataTable( {
11184
+ * "language": {
11185
+ * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11186
+ * }
11187
+ * } );
11188
+ * } );
11189
+ */
11190
+ "sUrl": "",
11191
+
11192
+
11193
+ /**
11194
+ * Text shown inside the table records when the is no information to be
11195
+ * displayed after filtering. `emptyTable` is shown when there is simply no
11196
+ * information in the table at all (regardless of filtering).
11197
+ * @type string
11198
+ * @default No matching records found
11199
+ *
11200
+ * @dtopt Language
11201
+ * @name DataTable.defaults.language.zeroRecords
11202
+ *
11203
+ * @example
11204
+ * $(document).ready( function() {
11205
+ * $('#example').dataTable( {
11206
+ * "language": {
11207
+ * "zeroRecords": "No records to display"
11208
+ * }
11209
+ * } );
11210
+ * } );
11211
+ */
11212
+ "sZeroRecords": "No matching records found"
11213
+ },
11214
+
11215
+
11216
+ /**
11217
+ * This parameter allows you to have define the global filtering state at
11218
+ * initialisation time. As an object the `search` parameter must be
11219
+ * defined, but all other parameters are optional. When `regex` is true,
11220
+ * the search string will be treated as a regular expression, when false
11221
+ * (default) it will be treated as a straight string. When `smart`
11222
+ * DataTables will use it's smart filtering methods (to word match at
11223
+ * any point in the data), when false this will not be done.
11224
+ * @namespace
11225
+ * @extends DataTable.models.oSearch
11226
+ *
11227
+ * @dtopt Options
11228
+ * @name DataTable.defaults.search
11229
+ *
11230
+ * @example
11231
+ * $(document).ready( function() {
11232
+ * $('#example').dataTable( {
11233
+ * "search": {"search": "Initial search"}
11234
+ * } );
11235
+ * } )
11236
+ */
11237
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
11238
+
11239
+
11240
+ /**
11241
+ * __Deprecated__ The functionality provided by this parameter has now been
11242
+ * superseded by that provided through `ajax`, which should be used instead.
11243
+ *
11244
+ * By default DataTables will look for the property `data` (or `aaData` for
11245
+ * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11246
+ * source or for server-side processing - this parameter allows that
11247
+ * property to be changed. You can use Javascript dotted object notation to
11248
+ * get a data source for multiple levels of nesting.
11249
+ * @type string
11250
+ * @default data
11251
+ *
11252
+ * @dtopt Options
11253
+ * @dtopt Server-side
11254
+ * @name DataTable.defaults.ajaxDataProp
11255
+ *
11256
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11257
+ */
11258
+ "sAjaxDataProp": "data",
11259
+
11260
+
11261
+ /**
11262
+ * __Deprecated__ The functionality provided by this parameter has now been
11263
+ * superseded by that provided through `ajax`, which should be used instead.
11264
+ *
11265
+ * You can instruct DataTables to load data from an external
11266
+ * source using this parameter (use aData if you want to pass data in you
11267
+ * already have). Simply provide a url a JSON object can be obtained from.
11268
+ * @type string
11269
+ * @default null
11270
+ *
11271
+ * @dtopt Options
11272
+ * @dtopt Server-side
11273
+ * @name DataTable.defaults.ajaxSource
11274
+ *
11275
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11276
+ */
11277
+ "sAjaxSource": null,
11278
+
11279
+
11280
+ /**
11281
+ * This initialisation variable allows you to specify exactly where in the
11282
+ * DOM you want DataTables to inject the various controls it adds to the page
11283
+ * (for example you might want the pagination controls at the top of the
11284
+ * table). DIV elements (with or without a custom class) can also be added to
11285
+ * aid styling. The follow syntax is used:
11286
+ * <ul>
11287
+ * <li>The following options are allowed:
11288
+ * <ul>
11289
+ * <li>'l' - Length changing</li>
11290
+ * <li>'f' - Filtering input</li>
11291
+ * <li>'t' - The table!</li>
11292
+ * <li>'i' - Information</li>
11293
+ * <li>'p' - Pagination</li>
11294
+ * <li>'r' - pRocessing</li>
11295
+ * </ul>
11296
+ * </li>
11297
+ * <li>The following constants are allowed:
11298
+ * <ul>
11299
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11300
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11301
+ * </ul>
11302
+ * </li>
11303
+ * <li>The following syntax is expected:
11304
+ * <ul>
11305
+ * <li>'&lt;' and '&gt;' - div elements</li>
11306
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
11307
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11308
+ * </ul>
11309
+ * </li>
11310
+ * <li>Examples:
11311
+ * <ul>
11312
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
11313
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11314
+ * </ul>
11315
+ * </li>
11316
+ * </ul>
11317
+ * @type string
11318
+ * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11319
+ * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11320
+ *
11321
+ * @dtopt Options
11322
+ * @name DataTable.defaults.dom
11323
+ *
11324
+ * @example
11325
+ * $(document).ready( function() {
11326
+ * $('#example').dataTable( {
11327
+ * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11328
+ * } );
11329
+ * } );
11330
+ */
11331
+ "sDom": "lfrtip",
11332
+
11333
+
11334
+ /**
11335
+ * DataTables features four different built-in options for the buttons to
11336
+ * display for pagination control:
11337
+ *
11338
+ * * `simple` - 'Previous' and 'Next' buttons only
11339
+ * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11340
+ * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11341
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11342
+ * page numbers
11343
+ *
11344
+ * Further methods can be added using {@link DataTable.ext.oPagination}.
11345
+ * @type string
11346
+ * @default simple_numbers
11347
+ *
11348
+ * @dtopt Options
11349
+ * @name DataTable.defaults.pagingType
11350
+ *
11351
+ * @example
11352
+ * $(document).ready( function() {
11353
+ * $('#example').dataTable( {
11354
+ * "pagingType": "full_numbers"
11355
+ * } );
11356
+ * } )
11357
+ */
11358
+ "sPaginationType": "simple_numbers",
11359
+
11360
+
11361
+ /**
11362
+ * Enable horizontal scrolling. When a table is too wide to fit into a
11363
+ * certain layout, or you have a large number of columns in the table, you
11364
+ * can enable x-scrolling to show the table in a viewport, which can be
11365
+ * scrolled. This property can be `true` which will allow the table to
11366
+ * scroll horizontally when needed, or any CSS unit, or a number (in which
11367
+ * case it will be treated as a pixel measurement). Setting as simply `true`
11368
+ * is recommended.
11369
+ * @type boolean|string
11370
+ * @default <i>blank string - i.e. disabled</i>
11371
+ *
11372
+ * @dtopt Features
11373
+ * @name DataTable.defaults.scrollX
11374
+ *
11375
+ * @example
11376
+ * $(document).ready( function() {
11377
+ * $('#example').dataTable( {
11378
+ * "scrollX": true,
11379
+ * "scrollCollapse": true
11380
+ * } );
11381
+ * } );
11382
+ */
11383
+ "sScrollX": "",
11384
+
11385
+
11386
+ /**
11387
+ * This property can be used to force a DataTable to use more width than it
11388
+ * might otherwise do when x-scrolling is enabled. For example if you have a
11389
+ * table which requires to be well spaced, this parameter is useful for
11390
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
11391
+ * any CSS unit, or a number (in which case it will be treated as a pixel
11392
+ * measurement).
11393
+ * @type string
11394
+ * @default <i>blank string - i.e. disabled</i>
11395
+ *
11396
+ * @dtopt Options
11397
+ * @name DataTable.defaults.scrollXInner
11398
+ *
11399
+ * @example
11400
+ * $(document).ready( function() {
11401
+ * $('#example').dataTable( {
11402
+ * "scrollX": "100%",
11403
+ * "scrollXInner": "110%"
11404
+ * } );
11405
+ * } );
11406
+ */
11407
+ "sScrollXInner": "",
11408
+
11409
+
11410
+ /**
11411
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11412
+ * to the given height, and enable scrolling for any data which overflows the
11413
+ * current viewport. This can be used as an alternative to paging to display
11414
+ * a lot of data in a small area (although paging and scrolling can both be
11415
+ * enabled at the same time). This property can be any CSS unit, or a number
11416
+ * (in which case it will be treated as a pixel measurement).
11417
+ * @type string
11418
+ * @default <i>blank string - i.e. disabled</i>
11419
+ *
11420
+ * @dtopt Features
11421
+ * @name DataTable.defaults.scrollY
11422
+ *
11423
+ * @example
11424
+ * $(document).ready( function() {
11425
+ * $('#example').dataTable( {
11426
+ * "scrollY": "200px",
11427
+ * "paginate": false
11428
+ * } );
11429
+ * } );
11430
+ */
11431
+ "sScrollY": "",
11432
+
11433
+
11434
+ /**
11435
+ * __Deprecated__ The functionality provided by this parameter has now been
11436
+ * superseded by that provided through `ajax`, which should be used instead.
11437
+ *
11438
+ * Set the HTTP method that is used to make the Ajax call for server-side
11439
+ * processing or Ajax sourced data.
11440
+ * @type string
11441
+ * @default GET
11442
+ *
11443
+ * @dtopt Options
11444
+ * @dtopt Server-side
11445
+ * @name DataTable.defaults.serverMethod
11446
+ *
11447
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11448
+ */
11449
+ "sServerMethod": "GET",
11450
+
11451
+
11452
+ /**
11453
+ * DataTables makes use of renderers when displaying HTML elements for
11454
+ * a table. These renderers can be added or modified by plug-ins to
11455
+ * generate suitable mark-up for a site. For example the Bootstrap
11456
+ * integration plug-in for DataTables uses a paging button renderer to
11457
+ * display pagination buttons in the mark-up required by Bootstrap.
11458
+ *
11459
+ * For further information about the renderers available see
11460
+ * DataTable.ext.renderer
11461
+ * @type string|object
11462
+ * @default null
11463
+ *
11464
+ * @name DataTable.defaults.renderer
11465
+ *
11466
+ */
11467
+ "renderer": null
11468
+ };
11469
+
11470
+ _fnHungarianMap( DataTable.defaults );
11471
+
11472
+
11473
+
11474
+ /*
11475
+ * Developer note - See note in model.defaults.js about the use of Hungarian
11476
+ * notation and camel case.
11477
+ */
11478
+
11479
+ /**
11480
+ * Column options that can be given to DataTables at initialisation time.
11481
+ * @namespace
11482
+ */
11483
+ DataTable.defaults.column = {
11484
+ /**
11485
+ * Define which column(s) an order will occur on for this column. This
11486
+ * allows a column's ordering to take multiple columns into account when
11487
+ * doing a sort or use the data from a different column. For example first
11488
+ * name / last name columns make sense to do a multi-column sort over the
11489
+ * two columns.
11490
+ * @type array|int
11491
+ * @default null <i>Takes the value of the column index automatically</i>
11492
+ *
11493
+ * @name DataTable.defaults.column.orderData
11494
+ * @dtopt Columns
11495
+ *
11496
+ * @example
11497
+ * // Using `columnDefs`
11498
+ * $(document).ready( function() {
11499
+ * $('#example').dataTable( {
11500
+ * "columnDefs": [
11501
+ * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11502
+ * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11503
+ * { "orderData": 2, "targets": [ 2 ] }
11504
+ * ]
11505
+ * } );
11506
+ * } );
11507
+ *
11508
+ * @example
11509
+ * // Using `columns`
11510
+ * $(document).ready( function() {
11511
+ * $('#example').dataTable( {
11512
+ * "columns": [
11513
+ * { "orderData": [ 0, 1 ] },
11514
+ * { "orderData": [ 1, 0 ] },
11515
+ * { "orderData": 2 },
11516
+ * null,
11517
+ * null
11518
+ * ]
11519
+ * } );
11520
+ * } );
11521
+ */
11522
+ "aDataSort": null,
11523
+ "iDataSort": -1,
11524
+
11525
+
11526
+ /**
11527
+ * You can control the default ordering direction, and even alter the
11528
+ * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11529
+ * using this parameter.
11530
+ * @type array
11531
+ * @default [ 'asc', 'desc' ]
11532
+ *
11533
+ * @name DataTable.defaults.column.orderSequence
11534
+ * @dtopt Columns
11535
+ *
11536
+ * @example
11537
+ * // Using `columnDefs`
11538
+ * $(document).ready( function() {
11539
+ * $('#example').dataTable( {
11540
+ * "columnDefs": [
11541
+ * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11542
+ * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11543
+ * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11544
+ * ]
11545
+ * } );
11546
+ * } );
11547
+ *
11548
+ * @example
11549
+ * // Using `columns`
11550
+ * $(document).ready( function() {
11551
+ * $('#example').dataTable( {
11552
+ * "columns": [
11553
+ * null,
11554
+ * { "orderSequence": [ "asc" ] },
11555
+ * { "orderSequence": [ "desc", "asc", "asc" ] },
11556
+ * { "orderSequence": [ "desc" ] },
11557
+ * null
11558
+ * ]
11559
+ * } );
11560
+ * } );
11561
+ */
11562
+ "asSorting": [ 'asc', 'desc' ],
11563
+
11564
+
11565
+ /**
11566
+ * Enable or disable filtering on the data in this column.
11567
+ * @type boolean
11568
+ * @default true
11569
+ *
11570
+ * @name DataTable.defaults.column.searchable
11571
+ * @dtopt Columns
11572
+ *
11573
+ * @example
11574
+ * // Using `columnDefs`
11575
+ * $(document).ready( function() {
11576
+ * $('#example').dataTable( {
11577
+ * "columnDefs": [
11578
+ * { "searchable": false, "targets": [ 0 ] }
11579
+ * ] } );
11580
+ * } );
11581
+ *
11582
+ * @example
11583
+ * // Using `columns`
11584
+ * $(document).ready( function() {
11585
+ * $('#example').dataTable( {
11586
+ * "columns": [
11587
+ * { "searchable": false },
11588
+ * null,
11589
+ * null,
11590
+ * null,
11591
+ * null
11592
+ * ] } );
11593
+ * } );
11594
+ */
11595
+ "bSearchable": true,
11596
+
11597
+
11598
+ /**
11599
+ * Enable or disable ordering on this column.
11600
+ * @type boolean
11601
+ * @default true
11602
+ *
11603
+ * @name DataTable.defaults.column.orderable
11604
+ * @dtopt Columns
11605
+ *
11606
+ * @example
11607
+ * // Using `columnDefs`
11608
+ * $(document).ready( function() {
11609
+ * $('#example').dataTable( {
11610
+ * "columnDefs": [
11611
+ * { "orderable": false, "targets": [ 0 ] }
11612
+ * ] } );
11613
+ * } );
11614
+ *
11615
+ * @example
11616
+ * // Using `columns`
11617
+ * $(document).ready( function() {
11618
+ * $('#example').dataTable( {
11619
+ * "columns": [
11620
+ * { "orderable": false },
11621
+ * null,
11622
+ * null,
11623
+ * null,
11624
+ * null
11625
+ * ] } );
11626
+ * } );
11627
+ */
11628
+ "bSortable": true,
11629
+
11630
+
11631
+ /**
11632
+ * Enable or disable the display of this column.
11633
+ * @type boolean
11634
+ * @default true
11635
+ *
11636
+ * @name DataTable.defaults.column.visible
11637
+ * @dtopt Columns
11638
+ *
11639
+ * @example
11640
+ * // Using `columnDefs`
11641
+ * $(document).ready( function() {
11642
+ * $('#example').dataTable( {
11643
+ * "columnDefs": [
11644
+ * { "visible": false, "targets": [ 0 ] }
11645
+ * ] } );
11646
+ * } );
11647
+ *
11648
+ * @example
11649
+ * // Using `columns`
11650
+ * $(document).ready( function() {
11651
+ * $('#example').dataTable( {
11652
+ * "columns": [
11653
+ * { "visible": false },
11654
+ * null,
11655
+ * null,
11656
+ * null,
11657
+ * null
11658
+ * ] } );
11659
+ * } );
11660
+ */
11661
+ "bVisible": true,
11662
+
11663
+
11664
+ /**
11665
+ * Developer definable function that is called whenever a cell is created (Ajax source,
11666
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11667
+ * allowing you to modify the DOM element (add background colour for example) when the
11668
+ * element is available.
11669
+ * @type function
11670
+ * @param {element} td The TD node that has been created
11671
+ * @param {*} cellData The Data for the cell
11672
+ * @param {array|object} rowData The data for the whole row
11673
+ * @param {int} row The row index for the aoData data store
11674
+ * @param {int} col The column index for aoColumns
11675
+ *
11676
+ * @name DataTable.defaults.column.createdCell
11677
+ * @dtopt Columns
11678
+ *
11679
+ * @example
11680
+ * $(document).ready( function() {
11681
+ * $('#example').dataTable( {
11682
+ * "columnDefs": [ {
11683
+ * "targets": [3],
11684
+ * "createdCell": function (td, cellData, rowData, row, col) {
11685
+ * if ( cellData == "1.7" ) {
11686
+ * $(td).css('color', 'blue')
11687
+ * }
11688
+ * }
11689
+ * } ]
11690
+ * });
11691
+ * } );
11692
+ */
11693
+ "fnCreatedCell": null,
11694
+
11695
+
11696
+ /**
11697
+ * This parameter has been replaced by `data` in DataTables to ensure naming
11698
+ * consistency. `dataProp` can still be used, as there is backwards
11699
+ * compatibility in DataTables for this option, but it is strongly
11700
+ * recommended that you use `data` in preference to `dataProp`.
11701
+ * @name DataTable.defaults.column.dataProp
11702
+ */
11703
+
11704
+
11705
+ /**
11706
+ * This property can be used to read data from any data source property,
11707
+ * including deeply nested objects / properties. `data` can be given in a
11708
+ * number of different ways which effect its behaviour:
11709
+ *
11710
+ * * `integer` - treated as an array index for the data source. This is the
11711
+ * default that DataTables uses (incrementally increased for each column).
11712
+ * * `string` - read an object property from the data source. There are
11713
+ * three 'special' options that can be used in the string to alter how
11714
+ * DataTables reads the data from the source object:
11715
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
11716
+ * Javascript to read from nested objects, so to can the options
11717
+ * specified in `data`. For example: `browser.version` or
11718
+ * `browser.name`. If your object parameter name contains a period, use
11719
+ * `\\` to escape it - i.e. `first\\.name`.
11720
+ * * `[]` - Array notation. DataTables can automatically combine data
11721
+ * from and array source, joining the data with the characters provided
11722
+ * between the two brackets. For example: `name[, ]` would provide a
11723
+ * comma-space separated list from the source array. If no characters
11724
+ * are provided between the brackets, the original array source is
11725
+ * returned.
11726
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
11727
+ * execute a function of the name given. For example: `browser()` for a
11728
+ * simple function on the data source, `browser.version()` for a
11729
+ * function in a nested property or even `browser().version` to get an
11730
+ * object property if the function called returns an object. Note that
11731
+ * function notation is recommended for use in `render` rather than
11732
+ * `data` as it is much simpler to use as a renderer.
11733
+ * * `null` - use the original data source for the row rather than plucking
11734
+ * data directly from it. This action has effects on two other
11735
+ * initialisation options:
11736
+ * * `defaultContent` - When null is given as the `data` option and
11737
+ * `defaultContent` is specified for the column, the value defined by
11738
+ * `defaultContent` will be used for the cell.
11739
+ * * `render` - When null is used for the `data` option and the `render`
11740
+ * option is specified for the column, the whole data source for the
11741
+ * row is used for the renderer.
11742
+ * * `function` - the function given will be executed whenever DataTables
11743
+ * needs to set or get the data for a cell in the column. The function
11744
+ * takes three parameters:
11745
+ * * Parameters:
11746
+ * * `{array|object}` The data source for the row
11747
+ * * `{string}` The type call data requested - this will be 'set' when
11748
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined
11749
+ * when gathering data. Note that when `undefined` is given for the
11750
+ * type DataTables expects to get the raw data for the object back<
11751
+ * * `{*}` Data to set when the second parameter is 'set'.
11752
+ * * Return:
11753
+ * * The return value from the function is not required when 'set' is
11754
+ * the type of call, but otherwise the return is what will be used
11755
+ * for the data requested.
11756
+ *
11757
+ * Note that `data` is a getter and setter option. If you just require
11758
+ * formatting of data for output, you will likely want to use `render` which
11759
+ * is simply a getter and thus simpler to use.
11760
+ *
11761
+ * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11762
+ * name change reflects the flexibility of this property and is consistent
11763
+ * with the naming of mRender. If 'mDataProp' is given, then it will still
11764
+ * be used by DataTables, as it automatically maps the old name to the new
11765
+ * if required.
11766
+ *
11767
+ * @type string|int|function|null
11768
+ * @default null <i>Use automatically calculated column index</i>
11769
+ *
11770
+ * @name DataTable.defaults.column.data
11771
+ * @dtopt Columns
11772
+ *
11773
+ * @example
11774
+ * // Read table data from objects
11775
+ * // JSON structure for each row:
11776
+ * // {
11777
+ * // "engine": {value},
11778
+ * // "browser": {value},
11779
+ * // "platform": {value},
11780
+ * // "version": {value},
11781
+ * // "grade": {value}
11782
+ * // }
11783
+ * $(document).ready( function() {
11784
+ * $('#example').dataTable( {
11785
+ * "ajaxSource": "sources/objects.txt",
11786
+ * "columns": [
11787
+ * { "data": "engine" },
11788
+ * { "data": "browser" },
11789
+ * { "data": "platform" },
11790
+ * { "data": "version" },
11791
+ * { "data": "grade" }
11792
+ * ]
11793
+ * } );
11794
+ * } );
11795
+ *
11796
+ * @example
11797
+ * // Read information from deeply nested objects
11798
+ * // JSON structure for each row:
11799
+ * // {
11800
+ * // "engine": {value},
11801
+ * // "browser": {value},
11802
+ * // "platform": {
11803
+ * // "inner": {value}
11804
+ * // },
11805
+ * // "details": [
11806
+ * // {value}, {value}
11807
+ * // ]
11808
+ * // }
11809
+ * $(document).ready( function() {
11810
+ * $('#example').dataTable( {
11811
+ * "ajaxSource": "sources/deep.txt",
11812
+ * "columns": [
11813
+ * { "data": "engine" },
11814
+ * { "data": "browser" },
11815
+ * { "data": "platform.inner" },
11816
+ * { "data": "platform.details.0" },
11817
+ * { "data": "platform.details.1" }
11818
+ * ]
11819
+ * } );
11820
+ * } );
11821
+ *
11822
+ * @example
11823
+ * // Using `data` as a function to provide different information for
11824
+ * // sorting, filtering and display. In this case, currency (price)
11825
+ * $(document).ready( function() {
11826
+ * $('#example').dataTable( {
11827
+ * "columnDefs": [ {
11828
+ * "targets": [ 0 ],
11829
+ * "data": function ( source, type, val ) {
11830
+ * if (type === 'set') {
11831
+ * source.price = val;
11832
+ * // Store the computed dislay and filter values for efficiency
11833
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
11834
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
11835
+ * return;
11836
+ * }
11837
+ * else if (type === 'display') {
11838
+ * return source.price_display;
11839
+ * }
11840
+ * else if (type === 'filter') {
11841
+ * return source.price_filter;
11842
+ * }
11843
+ * // 'sort', 'type' and undefined all just use the integer
11844
+ * return source.price;
11845
+ * }
11846
+ * } ]
11847
+ * } );
11848
+ * } );
11849
+ *
11850
+ * @example
11851
+ * // Using default content
11852
+ * $(document).ready( function() {
11853
+ * $('#example').dataTable( {
11854
+ * "columnDefs": [ {
11855
+ * "targets": [ 0 ],
11856
+ * "data": null,
11857
+ * "defaultContent": "Click to edit"
11858
+ * } ]
11859
+ * } );
11860
+ * } );
11861
+ *
11862
+ * @example
11863
+ * // Using array notation - outputting a list from an array
11864
+ * $(document).ready( function() {
11865
+ * $('#example').dataTable( {
11866
+ * "columnDefs": [ {
11867
+ * "targets": [ 0 ],
11868
+ * "data": "name[, ]"
11869
+ * } ]
11870
+ * } );
11871
+ * } );
11872
+ *
11873
+ */
11874
+ "mData": null,
11875
+
11876
+
11877
+ /**
11878
+ * This property is the rendering partner to `data` and it is suggested that
11879
+ * when you want to manipulate data for display (including filtering,
11880
+ * sorting etc) without altering the underlying data for the table, use this
11881
+ * property. `render` can be considered to be the the read only companion to
11882
+ * `data` which is read / write (then as such more complex). Like `data`
11883
+ * this option can be given in a number of different ways to effect its
11884
+ * behaviour:
11885
+ *
11886
+ * * `integer` - treated as an array index for the data source. This is the
11887
+ * default that DataTables uses (incrementally increased for each column).
11888
+ * * `string` - read an object property from the data source. There are
11889
+ * three 'special' options that can be used in the string to alter how
11890
+ * DataTables reads the data from the source object:
11891
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
11892
+ * Javascript to read from nested objects, so to can the options
11893
+ * specified in `data`. For example: `browser.version` or
11894
+ * `browser.name`. If your object parameter name contains a period, use
11895
+ * `\\` to escape it - i.e. `first\\.name`.
11896
+ * * `[]` - Array notation. DataTables can automatically combine data
11897
+ * from and array source, joining the data with the characters provided
11898
+ * between the two brackets. For example: `name[, ]` would provide a
11899
+ * comma-space separated list from the source array. If no characters
11900
+ * are provided between the brackets, the original array source is
11901
+ * returned.
11902
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
11903
+ * execute a function of the name given. For example: `browser()` for a
11904
+ * simple function on the data source, `browser.version()` for a
11905
+ * function in a nested property or even `browser().version` to get an
11906
+ * object property if the function called returns an object.
11907
+ * * `object` - use different data for the different data types requested by
11908
+ * DataTables ('filter', 'display', 'type' or 'sort'). The property names
11909
+ * of the object is the data type the property refers to and the value can
11910
+ * defined using an integer, string or function using the same rules as
11911
+ * `render` normally does. Note that an `_` option _must_ be specified.
11912
+ * This is the default value to use if you haven't specified a value for
11913
+ * the data type requested by DataTables.
11914
+ * * `function` - the function given will be executed whenever DataTables
11915
+ * needs to set or get the data for a cell in the column. The function
11916
+ * takes three parameters:
11917
+ * * Parameters:
11918
+ * * {array|object} The data source for the row (based on `data`)
11919
+ * * {string} The type call data requested - this will be 'filter',
11920
+ * 'display', 'type' or 'sort'.
11921
+ * * {array|object} The full data source for the row (not based on
11922
+ * `data`)
11923
+ * * Return:
11924
+ * * The return value from the function is what will be used for the
11925
+ * data requested.
11926
+ *
11927
+ * @type string|int|function|object|null
11928
+ * @default null Use the data source value.
11929
+ *
11930
+ * @name DataTable.defaults.column.render
11931
+ * @dtopt Columns
11932
+ *
11933
+ * @example
11934
+ * // Create a comma separated list from an array of objects
11935
+ * $(document).ready( function() {
11936
+ * $('#example').dataTable( {
11937
+ * "ajaxSource": "sources/deep.txt",
11938
+ * "columns": [
11939
+ * { "data": "engine" },
11940
+ * { "data": "browser" },
11941
+ * {
11942
+ * "data": "platform",
11943
+ * "render": "[, ].name"
11944
+ * }
11945
+ * ]
11946
+ * } );
11947
+ * } );
11948
+ *
11949
+ * @example
11950
+ * // Execute a function to obtain data
11951
+ * $(document).ready( function() {
11952
+ * $('#example').dataTable( {
11953
+ * "columnDefs": [ {
11954
+ * "targets": [ 0 ],
11955
+ * "data": null, // Use the full data source object for the renderer's source
11956
+ * "render": "browserName()"
11957
+ * } ]
11958
+ * } );
11959
+ * } );
11960
+ *
11961
+ * @example
11962
+ * // As an object, extracting different data for the different types
11963
+ * // This would be used with a data source such as:
11964
+ * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
11965
+ * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
11966
+ * // (which has both forms) is used for filtering for if a user inputs either format, while
11967
+ * // the formatted phone number is the one that is shown in the table.
11968
+ * $(document).ready( function() {
11969
+ * $('#example').dataTable( {
11970
+ * "columnDefs": [ {
11971
+ * "targets": [ 0 ],
11972
+ * "data": null, // Use the full data source object for the renderer's source
11973
+ * "render": {
11974
+ * "_": "phone",
11975
+ * "filter": "phone_filter",
11976
+ * "display": "phone_display"
11977
+ * }
11978
+ * } ]
11979
+ * } );
11980
+ * } );
11981
+ *
11982
+ * @example
11983
+ * // Use as a function to create a link from the data source
11984
+ * $(document).ready( function() {
11985
+ * $('#example').dataTable( {
11986
+ * "columnDefs": [ {
11987
+ * "targets": [ 0 ],
11988
+ * "data": "download_link",
11989
+ * "render": function ( data, type, full ) {
11990
+ * return '<a href="'+data+'">Download</a>';
11991
+ * }
11992
+ * } ]
11993
+ * } );
11994
+ * } );
11995
+ */
11996
+ "mRender": null,
11997
+
11998
+
11999
+ /**
12000
+ * Change the cell type created for the column - either TD cells or TH cells. This
12001
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
12002
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12003
+ * @type string
12004
+ * @default td
12005
+ *
12006
+ * @name DataTable.defaults.column.cellType
12007
+ * @dtopt Columns
12008
+ *
12009
+ * @example
12010
+ * // Make the first column use TH cells
12011
+ * $(document).ready( function() {
12012
+ * $('#example').dataTable( {
12013
+ * "columnDefs": [ {
12014
+ * "targets": [ 0 ],
12015
+ * "cellType": "th"
12016
+ * } ]
12017
+ * } );
12018
+ * } );
12019
+ */
12020
+ "sCellType": "td",
12021
+
12022
+
12023
+ /**
12024
+ * Class to give to each cell in this column.
12025
+ * @type string
12026
+ * @default <i>Empty string</i>
12027
+ *
12028
+ * @name DataTable.defaults.column.class
12029
+ * @dtopt Columns
12030
+ *
12031
+ * @example
12032
+ * // Using `columnDefs`
12033
+ * $(document).ready( function() {
12034
+ * $('#example').dataTable( {
12035
+ * "columnDefs": [
12036
+ * { "class": "my_class", "targets": [ 0 ] }
12037
+ * ]
12038
+ * } );
12039
+ * } );
12040
+ *
12041
+ * @example
12042
+ * // Using `columns`
12043
+ * $(document).ready( function() {
12044
+ * $('#example').dataTable( {
12045
+ * "columns": [
12046
+ * { "class": "my_class" },
12047
+ * null,
12048
+ * null,
12049
+ * null,
12050
+ * null
12051
+ * ]
12052
+ * } );
12053
+ * } );
12054
+ */
12055
+ "sClass": "",
12056
+
12057
+ /**
12058
+ * When DataTables calculates the column widths to assign to each column,
12059
+ * it finds the longest string in each column and then constructs a
12060
+ * temporary table and reads the widths from that. The problem with this
12061
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
12062
+ * string - thus the calculation can go wrong (doing it properly and putting
12063
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
12064
+ * a "work around" we provide this option. It will append its value to the
12065
+ * text that is found to be the longest string for the column - i.e. padding.
12066
+ * Generally you shouldn't need this!
12067
+ * @type string
12068
+ * @default <i>Empty string<i>
12069
+ *
12070
+ * @name DataTable.defaults.column.contentPadding
12071
+ * @dtopt Columns
12072
+ *
12073
+ * @example
12074
+ * // Using `columns`
12075
+ * $(document).ready( function() {
12076
+ * $('#example').dataTable( {
12077
+ * "columns": [
12078
+ * null,
12079
+ * null,
12080
+ * null,
12081
+ * {
12082
+ * "contentPadding": "mmm"
12083
+ * }
12084
+ * ]
12085
+ * } );
12086
+ * } );
12087
+ */
12088
+ "sContentPadding": "",
12089
+
12090
+
12091
+ /**
12092
+ * Allows a default value to be given for a column's data, and will be used
12093
+ * whenever a null data source is encountered (this can be because `data`
12094
+ * is set to null, or because the data source itself is null).
12095
+ * @type string
12096
+ * @default null
12097
+ *
12098
+ * @name DataTable.defaults.column.defaultContent
12099
+ * @dtopt Columns
12100
+ *
12101
+ * @example
12102
+ * // Using `columnDefs`
12103
+ * $(document).ready( function() {
12104
+ * $('#example').dataTable( {
12105
+ * "columnDefs": [
12106
+ * {
12107
+ * "data": null,
12108
+ * "defaultContent": "Edit",
12109
+ * "targets": [ -1 ]
12110
+ * }
12111
+ * ]
12112
+ * } );
12113
+ * } );
12114
+ *
12115
+ * @example
12116
+ * // Using `columns`
12117
+ * $(document).ready( function() {
12118
+ * $('#example').dataTable( {
12119
+ * "columns": [
12120
+ * null,
12121
+ * null,
12122
+ * null,
12123
+ * {
12124
+ * "data": null,
12125
+ * "defaultContent": "Edit"
12126
+ * }
12127
+ * ]
12128
+ * } );
12129
+ * } );
12130
+ */
12131
+ "sDefaultContent": null,
12132
+
12133
+
12134
+ /**
12135
+ * This parameter is only used in DataTables' server-side processing. It can
12136
+ * be exceptionally useful to know what columns are being displayed on the
12137
+ * client side, and to map these to database fields. When defined, the names
12138
+ * also allow DataTables to reorder information from the server if it comes
12139
+ * back in an unexpected order (i.e. if you switch your columns around on the
12140
+ * client-side, your server-side code does not also need updating).
12141
+ * @type string
12142
+ * @default <i>Empty string</i>
12143
+ *
12144
+ * @name DataTable.defaults.column.name
12145
+ * @dtopt Columns
12146
+ *
12147
+ * @example
12148
+ * // Using `columnDefs`
12149
+ * $(document).ready( function() {
12150
+ * $('#example').dataTable( {
12151
+ * "columnDefs": [
12152
+ * { "name": "engine", "targets": [ 0 ] },
12153
+ * { "name": "browser", "targets": [ 1 ] },
12154
+ * { "name": "platform", "targets": [ 2 ] },
12155
+ * { "name": "version", "targets": [ 3 ] },
12156
+ * { "name": "grade", "targets": [ 4 ] }
12157
+ * ]
12158
+ * } );
12159
+ * } );
12160
+ *
12161
+ * @example
12162
+ * // Using `columns`
12163
+ * $(document).ready( function() {
12164
+ * $('#example').dataTable( {
12165
+ * "columns": [
12166
+ * { "name": "engine" },
12167
+ * { "name": "browser" },
12168
+ * { "name": "platform" },
12169
+ * { "name": "version" },
12170
+ * { "name": "grade" }
12171
+ * ]
12172
+ * } );
12173
+ * } );
12174
+ */
12175
+ "sName": "",
12176
+
12177
+
12178
+ /**
12179
+ * Defines a data source type for the ordering which can be used to read
12180
+ * real-time information from the table (updating the internally cached
12181
+ * version) prior to ordering. This allows ordering to occur on user
12182
+ * editable elements such as form inputs.
12183
+ * @type string
12184
+ * @default std
12185
+ *
12186
+ * @name DataTable.defaults.column.orderDataType
12187
+ * @dtopt Columns
12188
+ *
12189
+ * @example
12190
+ * // Using `columnDefs`
12191
+ * $(document).ready( function() {
12192
+ * $('#example').dataTable( {
12193
+ * "columnDefs": [
12194
+ * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12195
+ * { "type": "numeric", "targets": [ 3 ] },
12196
+ * { "orderDataType": "dom-select", "targets": [ 4 ] },
12197
+ * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12198
+ * ]
12199
+ * } );
12200
+ * } );
12201
+ *
12202
+ * @example
12203
+ * // Using `columns`
12204
+ * $(document).ready( function() {
12205
+ * $('#example').dataTable( {
12206
+ * "columns": [
12207
+ * null,
12208
+ * null,
12209
+ * { "orderDataType": "dom-text" },
12210
+ * { "orderDataType": "dom-text", "type": "numeric" },
12211
+ * { "orderDataType": "dom-select" },
12212
+ * { "orderDataType": "dom-checkbox" }
12213
+ * ]
12214
+ * } );
12215
+ * } );
12216
+ */
12217
+ "sSortDataType": "std",
12218
+
12219
+
12220
+ /**
12221
+ * The title of this column.
12222
+ * @type string
12223
+ * @default null <i>Derived from the 'TH' value for this column in the
12224
+ * original HTML table.</i>
12225
+ *
12226
+ * @name DataTable.defaults.column.title
12227
+ * @dtopt Columns
12228
+ *
12229
+ * @example
12230
+ * // Using `columnDefs`
12231
+ * $(document).ready( function() {
12232
+ * $('#example').dataTable( {
12233
+ * "columnDefs": [
12234
+ * { "title": "My column title", "targets": [ 0 ] }
12235
+ * ]
12236
+ * } );
12237
+ * } );
12238
+ *
12239
+ * @example
12240
+ * // Using `columns`
12241
+ * $(document).ready( function() {
12242
+ * $('#example').dataTable( {
12243
+ * "columns": [
12244
+ * { "title": "My column title" },
12245
+ * null,
12246
+ * null,
12247
+ * null,
12248
+ * null
12249
+ * ]
12250
+ * } );
12251
+ * } );
12252
+ */
12253
+ "sTitle": null,
12254
+
12255
+
12256
+ /**
12257
+ * The type allows you to specify how the data for this column will be
12258
+ * ordered. Four types (string, numeric, date and html (which will strip
12259
+ * HTML tags before ordering)) are currently available. Note that only date
12260
+ * formats understood by Javascript's Date() object will be accepted as type
12261
+ * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12262
+ * 'numeric', 'date' or 'html' (by default). Further types can be adding
12263
+ * through plug-ins.
12264
+ * @type string
12265
+ * @default null <i>Auto-detected from raw data</i>
12266
+ *
12267
+ * @name DataTable.defaults.column.type
12268
+ * @dtopt Columns
12269
+ *
12270
+ * @example
12271
+ * // Using `columnDefs`
12272
+ * $(document).ready( function() {
12273
+ * $('#example').dataTable( {
12274
+ * "columnDefs": [
12275
+ * { "type": "html", "targets": [ 0 ] }
12276
+ * ]
12277
+ * } );
12278
+ * } );
12279
+ *
12280
+ * @example
12281
+ * // Using `columns`
12282
+ * $(document).ready( function() {
12283
+ * $('#example').dataTable( {
12284
+ * "columns": [
12285
+ * { "type": "html" },
12286
+ * null,
12287
+ * null,
12288
+ * null,
12289
+ * null
12290
+ * ]
12291
+ * } );
12292
+ * } );
12293
+ */
12294
+ "sType": null,
12295
+
12296
+
12297
+ /**
12298
+ * Defining the width of the column, this parameter may take any CSS value
12299
+ * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12300
+ * been given a specific width through this interface ensuring that the table
12301
+ * remains readable.
12302
+ * @type string
12303
+ * @default null <i>Automatic</i>
12304
+ *
12305
+ * @name DataTable.defaults.column.width
12306
+ * @dtopt Columns
12307
+ *
12308
+ * @example
12309
+ * // Using `columnDefs`
12310
+ * $(document).ready( function() {
12311
+ * $('#example').dataTable( {
12312
+ * "columnDefs": [
12313
+ * { "width": "20%", "targets": [ 0 ] }
12314
+ * ]
12315
+ * } );
12316
+ * } );
12317
+ *
12318
+ * @example
12319
+ * // Using `columns`
12320
+ * $(document).ready( function() {
12321
+ * $('#example').dataTable( {
12322
+ * "columns": [
12323
+ * { "width": "20%" },
12324
+ * null,
12325
+ * null,
12326
+ * null,
12327
+ * null
12328
+ * ]
12329
+ * } );
12330
+ * } );
12331
+ */
12332
+ "sWidth": null
12333
+ };
12334
+
12335
+ _fnHungarianMap( DataTable.defaults.column );
12336
+
12337
+
12338
+
12339
+ /**
12340
+ * DataTables settings object - this holds all the information needed for a
12341
+ * given table, including configuration, data and current application of the
12342
+ * table options. DataTables does not have a single instance for each DataTable
12343
+ * with the settings attached to that instance, but rather instances of the
12344
+ * DataTable "class" are created on-the-fly as needed (typically by a
12345
+ * $().dataTable() call) and the settings object is then applied to that
12346
+ * instance.
12347
+ *
12348
+ * Note that this object is related to {@link DataTable.defaults} but this
12349
+ * one is the internal data store for DataTables's cache of columns. It should
12350
+ * NOT be manipulated outside of DataTables. Any configuration should be done
12351
+ * through the initialisation options.
12352
+ * @namespace
12353
+ * @todo Really should attach the settings object to individual instances so we
12354
+ * don't need to create new instances on each $().dataTable() call (if the
12355
+ * table already exists). It would also save passing oSettings around and
12356
+ * into every single function. However, this is a very significant
12357
+ * architecture change for DataTables and will almost certainly break
12358
+ * backwards compatibility with older installations. This is something that
12359
+ * will be done in 2.0.
12360
+ */
12361
+ DataTable.models.oSettings = {
12362
+ /**
12363
+ * Primary features of DataTables and their enablement state.
12364
+ * @namespace
12365
+ */
12366
+ "oFeatures": {
12367
+
12368
+ /**
12369
+ * Flag to say if DataTables should automatically try to calculate the
12370
+ * optimum table and columns widths (true) or not (false).
12371
+ * Note that this parameter will be set by the initialisation routine. To
12372
+ * set a default use {@link DataTable.defaults}.
12373
+ * @type boolean
12374
+ */
12375
+ "bAutoWidth": null,
12376
+
12377
+ /**
12378
+ * Delay the creation of TR and TD elements until they are actually
12379
+ * needed by a driven page draw. This can give a significant speed
12380
+ * increase for Ajax source and Javascript source data, but makes no
12381
+ * difference at all fro DOM and server-side processing tables.
12382
+ * Note that this parameter will be set by the initialisation routine. To
12383
+ * set a default use {@link DataTable.defaults}.
12384
+ * @type boolean
12385
+ */
12386
+ "bDeferRender": null,
12387
+
12388
+ /**
12389
+ * Enable filtering on the table or not. Note that if this is disabled
12390
+ * then there is no filtering at all on the table, including fnFilter.
12391
+ * To just remove the filtering input use sDom and remove the 'f' option.
12392
+ * Note that this parameter will be set by the initialisation routine. To
12393
+ * set a default use {@link DataTable.defaults}.
12394
+ * @type boolean
12395
+ */
12396
+ "bFilter": null,
12397
+
12398
+ /**
12399
+ * Table information element (the 'Showing x of y records' div) enable
12400
+ * flag.
12401
+ * Note that this parameter will be set by the initialisation routine. To
12402
+ * set a default use {@link DataTable.defaults}.
12403
+ * @type boolean
12404
+ */
12405
+ "bInfo": null,
12406
+
12407
+ /**
12408
+ * Present a user control allowing the end user to change the page size
12409
+ * when pagination is enabled.
12410
+ * Note that this parameter will be set by the initialisation routine. To
12411
+ * set a default use {@link DataTable.defaults}.
12412
+ * @type boolean
12413
+ */
12414
+ "bLengthChange": null,
12415
+
12416
+ /**
12417
+ * Pagination enabled or not. Note that if this is disabled then length
12418
+ * changing must also be disabled.
12419
+ * Note that this parameter will be set by the initialisation routine. To
12420
+ * set a default use {@link DataTable.defaults}.
12421
+ * @type boolean
12422
+ */
12423
+ "bPaginate": null,
12424
+
12425
+ /**
12426
+ * Processing indicator enable flag whenever DataTables is enacting a
12427
+ * user request - typically an Ajax request for server-side processing.
12428
+ * Note that this parameter will be set by the initialisation routine. To
12429
+ * set a default use {@link DataTable.defaults}.
12430
+ * @type boolean
12431
+ */
12432
+ "bProcessing": null,
12433
+
12434
+ /**
12435
+ * Server-side processing enabled flag - when enabled DataTables will
12436
+ * get all data from the server for every draw - there is no filtering,
12437
+ * sorting or paging done on the client-side.
12438
+ * Note that this parameter will be set by the initialisation routine. To
12439
+ * set a default use {@link DataTable.defaults}.
12440
+ * @type boolean
12441
+ */
12442
+ "bServerSide": null,
12443
+
12444
+ /**
12445
+ * Sorting enablement flag.
12446
+ * Note that this parameter will be set by the initialisation routine. To
12447
+ * set a default use {@link DataTable.defaults}.
12448
+ * @type boolean
12449
+ */
12450
+ "bSort": null,
12451
+
12452
+ /**
12453
+ * Multi-column sorting
12454
+ * Note that this parameter will be set by the initialisation routine. To
12455
+ * set a default use {@link DataTable.defaults}.
12456
+ * @type boolean
12457
+ */
12458
+ "bSortMulti": null,
12459
+
12460
+ /**
12461
+ * Apply a class to the columns which are being sorted to provide a
12462
+ * visual highlight or not. This can slow things down when enabled since
12463
+ * there is a lot of DOM interaction.
12464
+ * Note that this parameter will be set by the initialisation routine. To
12465
+ * set a default use {@link DataTable.defaults}.
12466
+ * @type boolean
12467
+ */
12468
+ "bSortClasses": null,
12469
+
12470
+ /**
12471
+ * State saving enablement flag.
12472
+ * Note that this parameter will be set by the initialisation routine. To
12473
+ * set a default use {@link DataTable.defaults}.
12474
+ * @type boolean
12475
+ */
12476
+ "bStateSave": null
12477
+ },
12478
+
12479
+
12480
+ /**
12481
+ * Scrolling settings for a table.
12482
+ * @namespace
12483
+ */
12484
+ "oScroll": {
12485
+ /**
12486
+ * When the table is shorter in height than sScrollY, collapse the
12487
+ * table container down to the height of the table (when true).
12488
+ * Note that this parameter will be set by the initialisation routine. To
12489
+ * set a default use {@link DataTable.defaults}.
12490
+ * @type boolean
12491
+ */
12492
+ "bCollapse": null,
12493
+
12494
+ /**
12495
+ * Width of the scrollbar for the web-browser's platform. Calculated
12496
+ * during table initialisation.
12497
+ * @type int
12498
+ * @default 0
12499
+ */
12500
+ "iBarWidth": 0,
12501
+
12502
+ /**
12503
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
12504
+ * disabled if an empty string.
12505
+ * Note that this parameter will be set by the initialisation routine. To
12506
+ * set a default use {@link DataTable.defaults}.
12507
+ * @type string
12508
+ */
12509
+ "sX": null,
12510
+
12511
+ /**
12512
+ * Width to expand the table to when using x-scrolling. Typically you
12513
+ * should not need to use this.
12514
+ * Note that this parameter will be set by the initialisation routine. To
12515
+ * set a default use {@link DataTable.defaults}.
12516
+ * @type string
12517
+ * @deprecated
12518
+ */
12519
+ "sXInner": null,
12520
+
12521
+ /**
12522
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
12523
+ * if an empty string.
12524
+ * Note that this parameter will be set by the initialisation routine. To
12525
+ * set a default use {@link DataTable.defaults}.
12526
+ * @type string
12527
+ */
12528
+ "sY": null
12529
+ },
12530
+
12531
+ /**
12532
+ * Language information for the table.
12533
+ * @namespace
12534
+ * @extends DataTable.defaults.oLanguage
12535
+ */
12536
+ "oLanguage": {
12537
+ /**
12538
+ * Information callback function. See
12539
+ * {@link DataTable.defaults.fnInfoCallback}
12540
+ * @type function
12541
+ * @default null
12542
+ */
12543
+ "fnInfoCallback": null
12544
+ },
12545
+
12546
+ /**
12547
+ * Browser support parameters
12548
+ * @namespace
12549
+ */
12550
+ "oBrowser": {
12551
+ /**
12552
+ * Indicate if the browser incorrectly calculates width:100% inside a
12553
+ * scrolling element (IE6/7)
12554
+ * @type boolean
12555
+ * @default false
12556
+ */
12557
+ "bScrollOversize": false,
12558
+
12559
+ /**
12560
+ * Determine if the vertical scrollbar is on the right or left of the
12561
+ * scrolling container - needed for rtl language layout, although not
12562
+ * all browsers move the scrollbar (Safari).
12563
+ * @type boolean
12564
+ * @default false
12565
+ */
12566
+ "bScrollbarLeft": false
12567
+ },
12568
+
12569
+
12570
+ "ajax": null,
12571
+
12572
+
12573
+ /**
12574
+ * Array referencing the nodes which are used for the features. The
12575
+ * parameters of this object match what is allowed by sDom - i.e.
12576
+ * <ul>
12577
+ * <li>'l' - Length changing</li>
12578
+ * <li>'f' - Filtering input</li>
12579
+ * <li>'t' - The table!</li>
12580
+ * <li>'i' - Information</li>
12581
+ * <li>'p' - Pagination</li>
12582
+ * <li>'r' - pRocessing</li>
12583
+ * </ul>
12584
+ * @type array
12585
+ * @default []
12586
+ */
12587
+ "aanFeatures": [],
12588
+
12589
+ /**
12590
+ * Store data information - see {@link DataTable.models.oRow} for detailed
12591
+ * information.
12592
+ * @type array
12593
+ * @default []
12594
+ */
12595
+ "aoData": [],
12596
+
12597
+ /**
12598
+ * Array of indexes which are in the current display (after filtering etc)
12599
+ * @type array
12600
+ * @default []
12601
+ */
12602
+ "aiDisplay": [],
12603
+
12604
+ /**
12605
+ * Array of indexes for display - no filtering
12606
+ * @type array
12607
+ * @default []
12608
+ */
12609
+ "aiDisplayMaster": [],
12610
+
12611
+ /**
12612
+ * Store information about each column that is in use
12613
+ * @type array
12614
+ * @default []
12615
+ */
12616
+ "aoColumns": [],
12617
+
12618
+ /**
12619
+ * Store information about the table's header
12620
+ * @type array
12621
+ * @default []
12622
+ */
12623
+ "aoHeader": [],
12624
+
12625
+ /**
12626
+ * Store information about the table's footer
12627
+ * @type array
12628
+ * @default []
12629
+ */
12630
+ "aoFooter": [],
12631
+
12632
+ /**
12633
+ * Store the applied global search information in case we want to force a
12634
+ * research or compare the old search to a new one.
12635
+ * Note that this parameter will be set by the initialisation routine. To
12636
+ * set a default use {@link DataTable.defaults}.
12637
+ * @namespace
12638
+ * @extends DataTable.models.oSearch
12639
+ */
12640
+ "oPreviousSearch": {},
12641
+
12642
+ /**
12643
+ * Store the applied search for each column - see
12644
+ * {@link DataTable.models.oSearch} for the format that is used for the
12645
+ * filtering information for each column.
12646
+ * @type array
12647
+ * @default []
12648
+ */
12649
+ "aoPreSearchCols": [],
12650
+
12651
+ /**
12652
+ * Sorting that is applied to the table. Note that the inner arrays are
12653
+ * used in the following manner:
12654
+ * <ul>
12655
+ * <li>Index 0 - column number</li>
12656
+ * <li>Index 1 - current sorting direction</li>
12657
+ * </ul>
12658
+ * Note that this parameter will be set by the initialisation routine. To
12659
+ * set a default use {@link DataTable.defaults}.
12660
+ * @type array
12661
+ * @todo These inner arrays should really be objects
12662
+ */
12663
+ "aaSorting": null,
12664
+
12665
+ /**
12666
+ * Sorting that is always applied to the table (i.e. prefixed in front of
12667
+ * aaSorting).
12668
+ * Note that this parameter will be set by the initialisation routine. To
12669
+ * set a default use {@link DataTable.defaults}.
12670
+ * @type array
12671
+ * @default []
12672
+ */
12673
+ "aaSortingFixed": [],
12674
+
12675
+ /**
12676
+ * Classes to use for the striping of a table.
12677
+ * Note that this parameter will be set by the initialisation routine. To
12678
+ * set a default use {@link DataTable.defaults}.
12679
+ * @type array
12680
+ * @default []
12681
+ */
12682
+ "asStripeClasses": null,
12683
+
12684
+ /**
12685
+ * If restoring a table - we should restore its striping classes as well
12686
+ * @type array
12687
+ * @default []
12688
+ */
12689
+ "asDestroyStripes": [],
12690
+
12691
+ /**
12692
+ * If restoring a table - we should restore its width
12693
+ * @type int
12694
+ * @default 0
12695
+ */
12696
+ "sDestroyWidth": 0,
12697
+
12698
+ /**
12699
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
12700
+ * @type array
12701
+ * @default []
12702
+ */
12703
+ "aoRowCallback": [],
12704
+
12705
+ /**
12706
+ * Callback functions for the header on each draw.
12707
+ * @type array
12708
+ * @default []
12709
+ */
12710
+ "aoHeaderCallback": [],
12711
+
12712
+ /**
12713
+ * Callback function for the footer on each draw.
12714
+ * @type array
12715
+ * @default []
12716
+ */
12717
+ "aoFooterCallback": [],
12718
+
12719
+ /**
12720
+ * Array of callback functions for draw callback functions
12721
+ * @type array
12722
+ * @default []
12723
+ */
12724
+ "aoDrawCallback": [],
12725
+
12726
+ /**
12727
+ * Array of callback functions for row created function
12728
+ * @type array
12729
+ * @default []
12730
+ */
12731
+ "aoRowCreatedCallback": [],
12732
+
12733
+ /**
12734
+ * Callback functions for just before the table is redrawn. A return of
12735
+ * false will be used to cancel the draw.
12736
+ * @type array
12737
+ * @default []
12738
+ */
12739
+ "aoPreDrawCallback": [],
12740
+
12741
+ /**
12742
+ * Callback functions for when the table has been initialised.
12743
+ * @type array
12744
+ * @default []
12745
+ */
12746
+ "aoInitComplete": [],
12747
+
12748
+
12749
+ /**
12750
+ * Callbacks for modifying the settings to be stored for state saving, prior to
12751
+ * saving state.
12752
+ * @type array
12753
+ * @default []
12754
+ */
12755
+ "aoStateSaveParams": [],
12756
+
12757
+ /**
12758
+ * Callbacks for modifying the settings that have been stored for state saving
12759
+ * prior to using the stored values to restore the state.
12760
+ * @type array
12761
+ * @default []
12762
+ */
12763
+ "aoStateLoadParams": [],
12764
+
12765
+ /**
12766
+ * Callbacks for operating on the settings object once the saved state has been
12767
+ * loaded
12768
+ * @type array
12769
+ * @default []
12770
+ */
12771
+ "aoStateLoaded": [],
12772
+
12773
+ /**
12774
+ * Cache the table ID for quick access
12775
+ * @type string
12776
+ * @default <i>Empty string</i>
12777
+ */
12778
+ "sTableId": "",
12779
+
12780
+ /**
12781
+ * The TABLE node for the main table
12782
+ * @type node
12783
+ * @default null
12784
+ */
12785
+ "nTable": null,
12786
+
12787
+ /**
12788
+ * Permanent ref to the thead element
12789
+ * @type node
12790
+ * @default null
12791
+ */
12792
+ "nTHead": null,
12793
+
12794
+ /**
12795
+ * Permanent ref to the tfoot element - if it exists
12796
+ * @type node
12797
+ * @default null
12798
+ */
12799
+ "nTFoot": null,
12800
+
12801
+ /**
12802
+ * Permanent ref to the tbody element
12803
+ * @type node
12804
+ * @default null
12805
+ */
12806
+ "nTBody": null,
12807
+
12808
+ /**
12809
+ * Cache the wrapper node (contains all DataTables controlled elements)
12810
+ * @type node
12811
+ * @default null
12812
+ */
12813
+ "nTableWrapper": null,
12814
+
12815
+ /**
12816
+ * Indicate if when using server-side processing the loading of data
12817
+ * should be deferred until the second draw.
12818
+ * Note that this parameter will be set by the initialisation routine. To
12819
+ * set a default use {@link DataTable.defaults}.
12820
+ * @type boolean
12821
+ * @default false
12822
+ */
12823
+ "bDeferLoading": false,
12824
+
12825
+ /**
12826
+ * Indicate if all required information has been read in
12827
+ * @type boolean
12828
+ * @default false
12829
+ */
12830
+ "bInitialised": false,
12831
+
12832
+ /**
12833
+ * Information about open rows. Each object in the array has the parameters
12834
+ * 'nTr' and 'nParent'
12835
+ * @type array
12836
+ * @default []
12837
+ */
12838
+ "aoOpenRows": [],
12839
+
12840
+ /**
12841
+ * Dictate the positioning of DataTables' control elements - see
12842
+ * {@link DataTable.model.oInit.sDom}.
12843
+ * Note that this parameter will be set by the initialisation routine. To
12844
+ * set a default use {@link DataTable.defaults}.
12845
+ * @type string
12846
+ * @default null
12847
+ */
12848
+ "sDom": null,
12849
+
12850
+ /**
12851
+ * Which type of pagination should be used.
12852
+ * Note that this parameter will be set by the initialisation routine. To
12853
+ * set a default use {@link DataTable.defaults}.
12854
+ * @type string
12855
+ * @default two_button
12856
+ */
12857
+ "sPaginationType": "two_button",
12858
+
12859
+ /**
12860
+ * The state duration (for `stateSave`) in seconds.
12861
+ * Note that this parameter will be set by the initialisation routine. To
12862
+ * set a default use {@link DataTable.defaults}.
12863
+ * @type int
12864
+ * @default 0
12865
+ */
12866
+ "iStateDuration": 0,
12867
+
12868
+ /**
12869
+ * Array of callback functions for state saving. Each array element is an
12870
+ * object with the following parameters:
12871
+ * <ul>
12872
+ * <li>function:fn - function to call. Takes two parameters, oSettings
12873
+ * and the JSON string to save that has been thus far created. Returns
12874
+ * a JSON string to be inserted into a json object
12875
+ * (i.e. '"param": [ 0, 1, 2]')</li>
12876
+ * <li>string:sName - name of callback</li>
12877
+ * </ul>
12878
+ * @type array
12879
+ * @default []
12880
+ */
12881
+ "aoStateSave": [],
12882
+
12883
+ /**
12884
+ * Array of callback functions for state loading. Each array element is an
12885
+ * object with the following parameters:
12886
+ * <ul>
12887
+ * <li>function:fn - function to call. Takes two parameters, oSettings
12888
+ * and the object stored. May return false to cancel state loading</li>
12889
+ * <li>string:sName - name of callback</li>
12890
+ * </ul>
12891
+ * @type array
12892
+ * @default []
12893
+ */
12894
+ "aoStateLoad": [],
12895
+
12896
+ /**
12897
+ * State that was saved. Useful for back reference
12898
+ * @type object
12899
+ * @default null
12900
+ */
12901
+ "oSavedState": null,
12902
+
12903
+ /**
12904
+ * State that was loaded. Useful for back reference
12905
+ * @type object
12906
+ * @default null
12907
+ */
12908
+ "oLoadedState": null,
12909
+
12910
+ /**
12911
+ * Source url for AJAX data for the table.
12912
+ * Note that this parameter will be set by the initialisation routine. To
12913
+ * set a default use {@link DataTable.defaults}.
12914
+ * @type string
12915
+ * @default null
12916
+ */
12917
+ "sAjaxSource": null,
12918
+
12919
+ /**
12920
+ * Property from a given object from which to read the table data from. This
12921
+ * can be an empty string (when not server-side processing), in which case
12922
+ * it is assumed an an array is given directly.
12923
+ * Note that this parameter will be set by the initialisation routine. To
12924
+ * set a default use {@link DataTable.defaults}.
12925
+ * @type string
12926
+ */
12927
+ "sAjaxDataProp": null,
12928
+
12929
+ /**
12930
+ * Note if draw should be blocked while getting data
12931
+ * @type boolean
12932
+ * @default true
12933
+ */
12934
+ "bAjaxDataGet": true,
12935
+
12936
+ /**
12937
+ * The last jQuery XHR object that was used for server-side data gathering.
12938
+ * This can be used for working with the XHR information in one of the
12939
+ * callbacks
12940
+ * @type object
12941
+ * @default null
12942
+ */
12943
+ "jqXHR": null,
12944
+
12945
+ /**
12946
+ * JSON returned from the server in the last Ajax request
12947
+ * @type object
12948
+ * @default undefined
12949
+ */
12950
+ "json": undefined,
12951
+
12952
+ /**
12953
+ * Data submitted as part of the last Ajax request
12954
+ * @type object
12955
+ * @default undefined
12956
+ */
12957
+ "oAjaxData": undefined,
12958
+
12959
+ /**
12960
+ * Function to get the server-side data.
12961
+ * Note that this parameter will be set by the initialisation routine. To
12962
+ * set a default use {@link DataTable.defaults}.
12963
+ * @type function
12964
+ */
12965
+ "fnServerData": null,
12966
+
12967
+ /**
12968
+ * Functions which are called prior to sending an Ajax request so extra
12969
+ * parameters can easily be sent to the server
12970
+ * @type array
12971
+ * @default []
12972
+ */
12973
+ "aoServerParams": [],
12974
+
12975
+ /**
12976
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
12977
+ * required).
12978
+ * Note that this parameter will be set by the initialisation routine. To
12979
+ * set a default use {@link DataTable.defaults}.
12980
+ * @type string
12981
+ */
12982
+ "sServerMethod": null,
12983
+
12984
+ /**
12985
+ * Format numbers for display.
12986
+ * Note that this parameter will be set by the initialisation routine. To
12987
+ * set a default use {@link DataTable.defaults}.
12988
+ * @type function
12989
+ */
12990
+ "fnFormatNumber": null,
12991
+
12992
+ /**
12993
+ * List of options that can be used for the user selectable length menu.
12994
+ * Note that this parameter will be set by the initialisation routine. To
12995
+ * set a default use {@link DataTable.defaults}.
12996
+ * @type array
12997
+ * @default []
12998
+ */
12999
+ "aLengthMenu": null,
13000
+
13001
+ /**
13002
+ * Counter for the draws that the table does. Also used as a tracker for
13003
+ * server-side processing
13004
+ * @type int
13005
+ * @default 0
13006
+ */
13007
+ "iDraw": 0,
13008
+
13009
+ /**
13010
+ * Indicate if a redraw is being done - useful for Ajax
13011
+ * @type boolean
13012
+ * @default false
13013
+ */
13014
+ "bDrawing": false,
13015
+
13016
+ /**
13017
+ * Draw index (iDraw) of the last error when parsing the returned data
13018
+ * @type int
13019
+ * @default -1
13020
+ */
13021
+ "iDrawError": -1,
13022
+
13023
+ /**
13024
+ * Paging display length
13025
+ * @type int
13026
+ * @default 10
13027
+ */
13028
+ "_iDisplayLength": 10,
13029
+
13030
+ /**
13031
+ * Paging start point - aiDisplay index
13032
+ * @type int
13033
+ * @default 0
13034
+ */
13035
+ "_iDisplayStart": 0,
13036
+
13037
+ /**
13038
+ * Server-side processing - number of records in the result set
13039
+ * (i.e. before filtering), Use fnRecordsTotal rather than
13040
+ * this property to get the value of the number of records, regardless of
13041
+ * the server-side processing setting.
13042
+ * @type int
13043
+ * @default 0
13044
+ * @private
13045
+ */
13046
+ "_iRecordsTotal": 0,
13047
+
13048
+ /**
13049
+ * Server-side processing - number of records in the current display set
13050
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
13051
+ * this property to get the value of the number of records, regardless of
13052
+ * the server-side processing setting.
13053
+ * @type boolean
13054
+ * @default 0
13055
+ * @private
13056
+ */
13057
+ "_iRecordsDisplay": 0,
13058
+
13059
+ /**
13060
+ * Flag to indicate if jQuery UI marking and classes should be used.
13061
+ * Note that this parameter will be set by the initialisation routine. To
13062
+ * set a default use {@link DataTable.defaults}.
13063
+ * @type boolean
13064
+ */
13065
+ "bJUI": null,
13066
+
13067
+ /**
13068
+ * The classes to use for the table
13069
+ * @type object
13070
+ * @default {}
13071
+ */
13072
+ "oClasses": {},
13073
+
13074
+ /**
13075
+ * Flag attached to the settings object so you can check in the draw
13076
+ * callback if filtering has been done in the draw. Deprecated in favour of
13077
+ * events.
13078
+ * @type boolean
13079
+ * @default false
13080
+ * @deprecated
13081
+ */
13082
+ "bFiltered": false,
13083
+
13084
+ /**
13085
+ * Flag attached to the settings object so you can check in the draw
13086
+ * callback if sorting has been done in the draw. Deprecated in favour of
13087
+ * events.
13088
+ * @type boolean
13089
+ * @default false
13090
+ * @deprecated
13091
+ */
13092
+ "bSorted": false,
13093
+
13094
+ /**
13095
+ * Indicate that if multiple rows are in the header and there is more than
13096
+ * one unique cell per column, if the top one (true) or bottom one (false)
13097
+ * should be used for sorting / title by DataTables.
13098
+ * Note that this parameter will be set by the initialisation routine. To
13099
+ * set a default use {@link DataTable.defaults}.
13100
+ * @type boolean
13101
+ */
13102
+ "bSortCellsTop": null,
13103
+
13104
+ /**
13105
+ * Initialisation object that is used for the table
13106
+ * @type object
13107
+ * @default null
13108
+ */
13109
+ "oInit": null,
13110
+
13111
+ /**
13112
+ * Destroy callback functions - for plug-ins to attach themselves to the
13113
+ * destroy so they can clean up markup and events.
13114
+ * @type array
13115
+ * @default []
13116
+ */
13117
+ "aoDestroyCallback": [],
13118
+
13119
+
13120
+ /**
13121
+ * Get the number of records in the current record set, before filtering
13122
+ * @type function
13123
+ */
13124
+ "fnRecordsTotal": function ()
13125
+ {
13126
+ return _fnDataSource( this ) == 'ssp' ?
13127
+ this._iRecordsTotal * 1 :
13128
+ this.aiDisplayMaster.length;
13129
+ },
13130
+
13131
+ /**
13132
+ * Get the number of records in the current record set, after filtering
13133
+ * @type function
13134
+ */
13135
+ "fnRecordsDisplay": function ()
13136
+ {
13137
+ return _fnDataSource( this ) == 'ssp' ?
13138
+ this._iRecordsDisplay * 1 :
13139
+ this.aiDisplay.length;
13140
+ },
13141
+
13142
+ /**
13143
+ * Get the display end point - aiDisplay index
13144
+ * @type function
13145
+ */
13146
+ "fnDisplayEnd": function ()
13147
+ {
13148
+ var
13149
+ len = this._iDisplayLength,
13150
+ start = this._iDisplayStart,
13151
+ calc = start + len,
13152
+ records = this.aiDisplay.length,
13153
+ features = this.oFeatures,
13154
+ paginate = features.bPaginate;
13155
+
13156
+ if ( features.bServerSide ) {
13157
+ return paginate === false || len === -1 ?
13158
+ start + records :
13159
+ Math.min( start+len, this._iRecordsDisplay );
13160
+ }
13161
+ else {
13162
+ return ! paginate || calc>records || len===-1 ?
13163
+ records :
13164
+ calc;
13165
+ }
13166
+ },
13167
+
13168
+ /**
13169
+ * The DataTables object for this table
13170
+ * @type object
13171
+ * @default null
13172
+ */
13173
+ "oInstance": null,
13174
+
13175
+ /**
13176
+ * Unique identifier for each instance of the DataTables object. If there
13177
+ * is an ID on the table node, then it takes that value, otherwise an
13178
+ * incrementing internal counter is used.
13179
+ * @type string
13180
+ * @default null
13181
+ */
13182
+ "sInstance": null,
13183
+
13184
+ /**
13185
+ * tabindex attribute value that is added to DataTables control elements, allowing
13186
+ * keyboard navigation of the table and its controls.
13187
+ */
13188
+ "iTabIndex": 0,
13189
+
13190
+ /**
13191
+ * DIV container for the footer scrolling table if scrolling
13192
+ */
13193
+ "nScrollHead": null,
13194
+
13195
+ /**
13196
+ * DIV container for the footer scrolling table if scrolling
13197
+ */
13198
+ "nScrollFoot": null,
13199
+
13200
+ /**
13201
+ * Last applied sort
13202
+ * @type array
13203
+ * @default []
13204
+ */
13205
+ "aLastSort": [],
13206
+
13207
+ /**
13208
+ * Stored plug-in instances
13209
+ * @type object
13210
+ * @default {}
13211
+ */
13212
+ "oPlugins": {}
13213
+ };
13214
+
13215
+ /**
13216
+ * Extension object for DataTables that is used to provide all extension
13217
+ * options.
13218
+ *
13219
+ * Note that the `DataTable.ext` object is available through
13220
+ * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13221
+ * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13222
+ * @namespace
13223
+ * @extends DataTable.models.ext
13224
+ */
13225
+
13226
+
13227
+ /**
13228
+ * DataTables extensions
13229
+ *
13230
+ * This namespace acts as a collection area for plug-ins that can be used to
13231
+ * extend DataTables capabilities. Indeed many of the build in methods
13232
+ * use this method to provide their own capabilities (sorting methods for
13233
+ * example).
13234
+ *
13235
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13236
+ * reasons
13237
+ *
13238
+ * @namespace
13239
+ */
13240
+ DataTable.ext = _ext = {
13241
+ /**
13242
+ * Element class names
13243
+ *
13244
+ * @type object
13245
+ * @default {}
13246
+ */
13247
+ classes: {},
13248
+
13249
+
13250
+ /**
13251
+ * Error reporting.
13252
+ *
13253
+ * How should DataTables report an error. Can take the value 'alert' or
13254
+ * 'throw'
13255
+ *
13256
+ * @type string
13257
+ * @default alert
13258
+ */
13259
+ errMode: "alert",
13260
+
13261
+
13262
+ /**
13263
+ * Feature plug-ins.
13264
+ *
13265
+ * This is an array of objects which describe the feature plug-ins that are
13266
+ * available to DataTables. These feature plug-ins are then available for
13267
+ * use through the `dom` initialisation option.
13268
+ *
13269
+ * Each feature plug-in is described by an object which must have the
13270
+ * following properties:
13271
+ *
13272
+ * * `fnInit` - function that is used to initialise the plug-in,
13273
+ * * `cFeature` - a character so the feature can be enabled by the `dom`
13274
+ * instillation option. This is case sensitive.
13275
+ *
13276
+ * The `fnInit` function has the following input parameters:
13277
+ *
13278
+ * 1. `{object}` DataTables settings object: see
13279
+ * {@link DataTable.models.oSettings}
13280
+ *
13281
+ * And the following return is expected:
13282
+ *
13283
+ * * {node|null} The element which contains your feature. Note that the
13284
+ * return may also be void if your plug-in does not require to inject any
13285
+ * DOM elements into DataTables control (`dom`) - for example this might
13286
+ * be useful when developing a plug-in which allows table control via
13287
+ * keyboard entry
13288
+ *
13289
+ * @type array
13290
+ *
13291
+ * @example
13292
+ * $.fn.dataTable.ext.features.push( {
13293
+ * "fnInit": function( oSettings ) {
13294
+ * return new TableTools( { "oDTSettings": oSettings } );
13295
+ * },
13296
+ * "cFeature": "T"
13297
+ * } );
13298
+ */
13299
+ feature: [],
13300
+
13301
+
13302
+ /**
13303
+ * Row searching.
13304
+ *
13305
+ * This method of searching is complimentary to the default type based
13306
+ * searching, and a lot more comprehensive as it allows you complete control
13307
+ * over the searching logic. Each element in this array is a function
13308
+ * (parameters described below) that is called for every row in the table,
13309
+ * and your logic decides if it should be included in the searching data set
13310
+ * or not.
13311
+ *
13312
+ * Searching functions have the following input parameters:
13313
+ *
13314
+ * 1. `{object}` DataTables settings object: see
13315
+ * {@link DataTable.models.oSettings}
13316
+ * 2. `{array|object}` Data for the row to be processed (same as the
13317
+ * original format that was passed in as the data source, or an array
13318
+ * from a DOM data source
13319
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13320
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
13321
+ *
13322
+ * And the following return is expected:
13323
+ *
13324
+ * * {boolean} Include the row in the searched result set (true) or not
13325
+ * (false)
13326
+ *
13327
+ * Note that as with the main search ability in DataTables, technically this
13328
+ * is "filtering", since it is subtractive. However, for consistency in
13329
+ * naming we call it searching here.
13330
+ *
13331
+ * @type array
13332
+ * @default []
13333
+ *
13334
+ * @example
13335
+ * // The following example shows custom search being applied to the
13336
+ * // fourth column (i.e. the data[3] index) based on two input values
13337
+ * // from the end-user, matching the data in a certain range.
13338
+ * $.fn.dataTable.ext.search.push(
13339
+ * function( settings, data, dataIndex ) {
13340
+ * var min = document.getElementById('min').value * 1;
13341
+ * var max = document.getElementById('max').value * 1;
13342
+ * var version = data[3] == "-" ? 0 : data[3]*1;
13343
+ *
13344
+ * if ( min == "" && max == "" ) {
13345
+ * return true;
13346
+ * }
13347
+ * else if ( min == "" && version < max ) {
13348
+ * return true;
13349
+ * }
13350
+ * else if ( min < version && "" == max ) {
13351
+ * return true;
13352
+ * }
13353
+ * else if ( min < version && version < max ) {
13354
+ * return true;
13355
+ * }
13356
+ * return false;
13357
+ * }
13358
+ * );
13359
+ */
13360
+ search: [],
13361
+
13362
+
13363
+ /**
13364
+ * Internal functions, exposed for used in plug-ins.
13365
+ *
13366
+ * Please note that you should not need to use the internal methods for
13367
+ * anything other than a plug-in (and even then, try to avoid if possible).
13368
+ * The internal function may change between releases.
13369
+ *
13370
+ * @type object
13371
+ * @default {}
13372
+ */
13373
+ internal: {},
13374
+
13375
+
13376
+ /**
13377
+ * Legacy configuration options. Enable and disable legacy options that
13378
+ * are available in DataTables.
13379
+ *
13380
+ * @type object
13381
+ */
13382
+ legacy: {
13383
+ /**
13384
+ * Enable / disable DataTables 1.9 compatible server-side processing
13385
+ * requests
13386
+ *
13387
+ * @type boolean
13388
+ * @default null
13389
+ */
13390
+ ajax: null
13391
+ },
13392
+
13393
+
13394
+ /**
13395
+ * Pagination plug-in methods.
13396
+ *
13397
+ * Each entry in this object is a function and defines which buttons should
13398
+ * be shown by the pagination rendering method that is used for the table:
13399
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13400
+ * buttons are displayed in the document, while the functions here tell it
13401
+ * what buttons to display. This is done by returning an array of button
13402
+ * descriptions (what each button will do).
13403
+ *
13404
+ * Pagination types (the four built in options and any additional plug-in
13405
+ * options defined here) can be used through the `paginationType`
13406
+ * initialisation parameter.
13407
+ *
13408
+ * The functions defined take two parameters:
13409
+ *
13410
+ * 1. `{int} page` The current page index
13411
+ * 2. `{int} pages` The number of pages in the table
13412
+ *
13413
+ * Each function is expected to return an array where each element of the
13414
+ * array can be one of:
13415
+ *
13416
+ * * `first` - Jump to first page when activated
13417
+ * * `last` - Jump to last page when activated
13418
+ * * `previous` - Show previous page when activated
13419
+ * * `next` - Show next page when activated
13420
+ * * `{int}` - Show page of the index given
13421
+ * * `{array}` - A nested array containing the above elements to add a
13422
+ * containing 'DIV' element (might be useful for styling).
13423
+ *
13424
+ * Note that DataTables v1.9- used this object slightly differently whereby
13425
+ * an object with two functions would be defined for each plug-in. That
13426
+ * ability is still supported by DataTables 1.10+ to provide backwards
13427
+ * compatibility, but this option of use is now decremented and no longer
13428
+ * documented in DataTables 1.10+.
13429
+ *
13430
+ * @type object
13431
+ * @default {}
13432
+ *
13433
+ * @example
13434
+ * // Show previous, next and current page buttons only
13435
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13436
+ * return [ 'previous', page, 'next' ];
13437
+ * };
13438
+ */
13439
+ pager: {},
13440
+
13441
+
13442
+ renderer: {
13443
+ pageButton: {},
13444
+ header: {}
13445
+ },
13446
+
13447
+
13448
+ /**
13449
+ * Ordering plug-ins - custom data source
13450
+ *
13451
+ * The extension options for ordering of data available here is complimentary
13452
+ * to the default type based ordering that DataTables typically uses. It
13453
+ * allows much greater control over the the data that is being used to
13454
+ * order a column, but is necessarily therefore more complex.
13455
+ *
13456
+ * This type of ordering is useful if you want to do ordering based on data
13457
+ * live from the DOM (for example the contents of an 'input' element) rather
13458
+ * than just the static string that DataTables knows of.
13459
+ *
13460
+ * The way these plug-ins work is that you create an array of the values you
13461
+ * wish to be ordering for the column in question and then return that
13462
+ * array. The data in the array much be in the index order of the rows in
13463
+ * the table (not the currently ordering order!). Which order data gathering
13464
+ * function is run here depends on the `dt-init columns.orderDataType`
13465
+ * parameter that is used for the column (if any).
13466
+ *
13467
+ * The functions defined take two parameters:
13468
+ *
13469
+ * 1. `{object}` DataTables settings object: see
13470
+ * {@link DataTable.models.oSettings}
13471
+ * 2. `{int}` Target column index
13472
+ *
13473
+ * Each function is expected to return an array:
13474
+ *
13475
+ * * `{array}` Data for the column to be ordering upon
13476
+ *
13477
+ * @type array
13478
+ *
13479
+ * @example
13480
+ * // Ordering using `input` node values
13481
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13482
+ * {
13483
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13484
+ * return $('input', td).val();
13485
+ * } );
13486
+ * }
13487
+ */
13488
+ order: {},
13489
+
13490
+
13491
+ /**
13492
+ * Type based plug-ins.
13493
+ *
13494
+ * Each column in DataTables has a type assigned to it, either by automatic
13495
+ * detection or by direct assignment using the `type` option for the column.
13496
+ * The type of a column will effect how it is ordering and search (plug-ins
13497
+ * can also make use of the column type if required).
13498
+ *
13499
+ * @namespace
13500
+ */
13501
+ type: {
13502
+ /**
13503
+ * Type detection functions.
13504
+ *
13505
+ * The functions defined in this object are used to automatically detect
13506
+ * a column's type, making initialisation of DataTables super easy, even
13507
+ * when complex data is in the table.
13508
+ *
13509
+ * The functions defined take two parameters:
13510
+ *
13511
+ * 1. `{*}` Data from the column cell to be analysed
13512
+ * 2. `{settings}` DataTables settings object. This can be used to
13513
+ * perform context specific type detection - for example detection
13514
+ * based on language settings such as using a comma for a decimal
13515
+ * place. Generally speaking the options from the settings will not
13516
+ * be required
13517
+ *
13518
+ * Each function is expected to return:
13519
+ *
13520
+ * * `{string|null}` Data type detected, or null if unknown (and thus
13521
+ * pass it on to the other type detection functions.
13522
+ *
13523
+ * @type array
13524
+ *
13525
+ * @example
13526
+ * // Currency type detection plug-in:
13527
+ * $.fn.dataTable.ext.type.detect.push(
13528
+ * function ( data, settings ) {
13529
+ * // Check the numeric part
13530
+ * if ( ! $.isNumeric( data.substring(1) ) ) {
13531
+ * return null;
13532
+ * }
13533
+ *
13534
+ * // Check prefixed by currency
13535
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
13536
+ * return 'currency';
13537
+ * }
13538
+ * return null;
13539
+ * }
13540
+ * );
13541
+ */
13542
+ detect: [],
13543
+
13544
+
13545
+ /**
13546
+ * Type based search formatting.
13547
+ *
13548
+ * The type based searching functions can be used to pre-format the
13549
+ * data to be search on. For example, it can be used to strip HTML
13550
+ * tags or to de-format telephone numbers for numeric only searching.
13551
+ *
13552
+ * Note that is a search is not defined for a column of a given type,
13553
+ * no search formatting will be performed.
13554
+ *
13555
+ * Pre-processing of searching data plug-ins - When you assign the sType
13556
+ * for a column (or have it automatically detected for you by DataTables
13557
+ * or a type detection plug-in), you will typically be using this for
13558
+ * custom sorting, but it can also be used to provide custom searching
13559
+ * by allowing you to pre-processing the data and returning the data in
13560
+ * the format that should be searched upon. This is done by adding
13561
+ * functions this object with a parameter name which matches the sType
13562
+ * for that target column. This is the corollary of <i>afnSortData</i>
13563
+ * for searching data.
13564
+ *
13565
+ * The functions defined take a single parameter:
13566
+ *
13567
+ * 1. `{*}` Data from the column cell to be prepared for searching
13568
+ *
13569
+ * Each function is expected to return:
13570
+ *
13571
+ * * `{string|null}` Formatted string that will be used for the searching.
13572
+ *
13573
+ * @type object
13574
+ * @default {}
13575
+ *
13576
+ * @example
13577
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13578
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13579
+ * }
13580
+ */
13581
+ search: {},
13582
+
13583
+
13584
+ /**
13585
+ * Type based ordering.
13586
+ *
13587
+ * The column type tells DataTables what ordering to apply to the table
13588
+ * when a column is sorted upon. The order for each type that is defined,
13589
+ * is defined by the functions available in this object.
13590
+ *
13591
+ * Each ordering option can be described by three properties added to
13592
+ * this object:
13593
+ *
13594
+ * * `{type}-pre` - Pre-formatting function
13595
+ * * `{type}-asc` - Ascending order function
13596
+ * * `{type}-desc` - Descending order function
13597
+ *
13598
+ * All three can be used together, only `{type}-pre` or only
13599
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
13600
+ * that only `{type}-pre` is used, as this provides the optimal
13601
+ * implementation in terms of speed, although the others are provided
13602
+ * for compatibility with existing Javascript sort functions.
13603
+ *
13604
+ * `{type}-pre`: Functions defined take a single parameter:
13605
+ *
13606
+ * 1. `{*}` Data from the column cell to be prepared for ordering
13607
+ *
13608
+ * And return:
13609
+ *
13610
+ * * `{*}` Data to be sorted upon
13611
+ *
13612
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13613
+ * functions, taking two parameters:
13614
+ *
13615
+ * 1. `{*}` Data to compare to the second parameter
13616
+ * 2. `{*}` Data to compare to the first parameter
13617
+ *
13618
+ * And returning:
13619
+ *
13620
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13621
+ * than the second parameter, ===0 if the two parameters are equal and
13622
+ * >0 if the first parameter should be sorted height than the second
13623
+ * parameter.
13624
+ *
13625
+ * @type object
13626
+ * @default {}
13627
+ *
13628
+ * @example
13629
+ * // Numeric ordering of formatted numbers with a pre-formatter
13630
+ * $.extend( $.fn.dataTable.ext.type.order, {
13631
+ * "string-pre": function(x) {
13632
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13633
+ * return parseFloat( a );
13634
+ * }
13635
+ * } );
13636
+ *
13637
+ * @example
13638
+ * // Case-sensitive string ordering, with no pre-formatting method
13639
+ * $.extend( $.fn.dataTable.ext.order, {
13640
+ * "string-case-asc": function(x,y) {
13641
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13642
+ * },
13643
+ * "string-case-desc": function(x,y) {
13644
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13645
+ * }
13646
+ * } );
13647
+ */
13648
+ order: {}
13649
+ },
13650
+
13651
+ /**
13652
+ * Unique DataTables instance counter
13653
+ *
13654
+ * @type int
13655
+ * @private
13656
+ */
13657
+ _unique: 0,
13658
+
13659
+
13660
+ //
13661
+ // Depreciated
13662
+ // The following properties are retained for backwards compatiblity only.
13663
+ // The should not be used in new projects and will be removed in a future
13664
+ // version
13665
+ //
13666
+
13667
+ /**
13668
+ * Version check function.
13669
+ * @type function
13670
+ * @depreciated Since 1.10
13671
+ */
13672
+ fnVersionCheck: DataTable.fnVersionCheck,
13673
+
13674
+
13675
+ /**
13676
+ * Index for what 'this' index API functions should use
13677
+ * @type int
13678
+ * @deprecated Since v1.10
13679
+ */
13680
+ iApiIndex: 0,
13681
+
13682
+
13683
+ /**
13684
+ * jQuery UI class container
13685
+ * @type object
13686
+ * @deprecated Since v1.10
13687
+ */
13688
+ oJUIClasses: {},
13689
+
13690
+
13691
+ /**
13692
+ * Software version
13693
+ * @type string
13694
+ * @deprecated Since v1.10
13695
+ */
13696
+ sVersion: DataTable.version
13697
+ };
13698
+
13699
+
13700
+ //
13701
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
13702
+ //
13703
+ $.extend( _ext, {
13704
+ afnFiltering: _ext.search,
13705
+ aTypes: _ext.type.detect,
13706
+ ofnSearch: _ext.type.search,
13707
+ oSort: _ext.type.order,
13708
+ afnSortData: _ext.order,
13709
+ aoFeatures: _ext.feature,
13710
+ oApi: _ext.internal,
13711
+ oStdClasses: _ext.classes,
13712
+ oPagination: _ext.pager
13713
+ } );
13714
+
13715
+
13716
+ $.extend( DataTable.ext.classes, {
13717
+ "sTable": "dataTable",
13718
+ "sNoFooter": "no-footer",
13719
+
13720
+ /* Paging buttons */
13721
+ "sPageButton": "paginate_button",
13722
+ "sPageButtonActive": "current",
13723
+ "sPageButtonDisabled": "disabled",
13724
+
13725
+ /* Striping classes */
13726
+ "sStripeOdd": "odd",
13727
+ "sStripeEven": "even",
13728
+
13729
+ /* Empty row */
13730
+ "sRowEmpty": "dataTables_empty",
13731
+
13732
+ /* Features */
13733
+ "sWrapper": "dataTables_wrapper",
13734
+ "sFilter": "dataTables_filter",
13735
+ "sInfo": "dataTables_info",
13736
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
13737
+ "sLength": "dataTables_length",
13738
+ "sProcessing": "dataTables_processing",
13739
+
13740
+ /* Sorting */
13741
+ "sSortAsc": "sorting_asc",
13742
+ "sSortDesc": "sorting_desc",
13743
+ "sSortable": "sorting", /* Sortable in both directions */
13744
+ "sSortableAsc": "sorting_asc_disabled",
13745
+ "sSortableDesc": "sorting_desc_disabled",
13746
+ "sSortableNone": "sorting_disabled",
13747
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
13748
+
13749
+ /* Filtering */
13750
+ "sFilterInput": "",
13751
+
13752
+ /* Page length */
13753
+ "sLengthSelect": "",
13754
+
13755
+ /* Scrolling */
13756
+ "sScrollWrapper": "dataTables_scroll",
13757
+ "sScrollHead": "dataTables_scrollHead",
13758
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
13759
+ "sScrollBody": "dataTables_scrollBody",
13760
+ "sScrollFoot": "dataTables_scrollFoot",
13761
+ "sScrollFootInner": "dataTables_scrollFootInner",
13762
+
13763
+ /* Misc */
13764
+ "sHeaderTH": "",
13765
+ "sFooterTH": "",
13766
+
13767
+ // Deprecated
13768
+ "sSortJUIAsc": "",
13769
+ "sSortJUIDesc": "",
13770
+ "sSortJUI": "",
13771
+ "sSortJUIAscAllowed": "",
13772
+ "sSortJUIDescAllowed": "",
13773
+ "sSortJUIWrapper": "",
13774
+ "sSortIcon": "",
13775
+ "sJUIHeader": "",
13776
+ "sJUIFooter": ""
13777
+ } );
13778
+
13779
+
13780
+ (function() {
13781
+
13782
+ // Reused strings for better compression. Closure compiler appears to have a
13783
+ // weird edge case where it is trying to expand strings rather than use the
13784
+ // variable version. This results in about 200 bytes being added, for very
13785
+ // little preference benefit since it this run on script load only.
13786
+ var _empty = '';
13787
+ _empty = '';
13788
+
13789
+ var _stateDefault = _empty + 'ui-state-default';
13790
+ var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
13791
+ var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
13792
+
13793
+ $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
13794
+ /* Full numbers paging buttons */
13795
+ "sPageButton": "fg-button ui-button "+_stateDefault,
13796
+ "sPageButtonActive": "ui-state-disabled",
13797
+ "sPageButtonDisabled": "ui-state-disabled",
13798
+
13799
+ /* Features */
13800
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
13801
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
13802
+
13803
+ /* Sorting */
13804
+ "sSortAsc": _stateDefault+" sorting_asc",
13805
+ "sSortDesc": _stateDefault+" sorting_desc",
13806
+ "sSortable": _stateDefault+" sorting",
13807
+ "sSortableAsc": _stateDefault+" sorting_asc_disabled",
13808
+ "sSortableDesc": _stateDefault+" sorting_desc_disabled",
13809
+ "sSortableNone": _stateDefault+" sorting_disabled",
13810
+ "sSortJUIAsc": _sortIcon+"triangle-1-n",
13811
+ "sSortJUIDesc": _sortIcon+"triangle-1-s",
13812
+ "sSortJUI": _sortIcon+"carat-2-n-s",
13813
+ "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
13814
+ "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
13815
+ "sSortJUIWrapper": "DataTables_sort_wrapper",
13816
+ "sSortIcon": "DataTables_sort_icon",
13817
+
13818
+ /* Scrolling */
13819
+ "sScrollHead": "dataTables_scrollHead "+_stateDefault,
13820
+ "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
13821
+
13822
+ /* Misc */
13823
+ "sHeaderTH": _stateDefault,
13824
+ "sFooterTH": _stateDefault,
13825
+ "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
13826
+ "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
13827
+ } );
13828
+
13829
+ }());
13830
+
13831
+
13832
+
13833
+ var extPagination = DataTable.ext.pager;
13834
+
13835
+ function _numbers ( page, pages ) {
13836
+ var
13837
+ numbers = [],
13838
+ buttons = extPagination.numbers_length,
13839
+ half = Math.floor( buttons / 2 ),
13840
+ i = 1;
13841
+
13842
+ if ( pages <= buttons ) {
13843
+ numbers = _range( 0, pages );
13844
+ }
13845
+ else if ( page <= half ) {
13846
+ numbers = _range( 0, buttons-2 );
13847
+ numbers.push( 'ellipsis' );
13848
+ numbers.push( pages-1 );
13849
+ }
13850
+ else if ( page >= pages - 1 - half ) {
13851
+ numbers = _range( pages-(buttons-2), pages );
13852
+ numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
13853
+ numbers.splice( 0, 0, 0 );
13854
+ }
13855
+ else {
13856
+ numbers = _range( page-1, page+2 );
13857
+ numbers.push( 'ellipsis' );
13858
+ numbers.push( pages-1 );
13859
+ numbers.splice( 0, 0, 'ellipsis' );
13860
+ numbers.splice( 0, 0, 0 );
13861
+ }
13862
+
13863
+ numbers.DT_el = 'span';
13864
+ return numbers;
13865
+ }
13866
+
13867
+
13868
+ $.extend( extPagination, {
13869
+ simple: function ( page, pages ) {
13870
+ return [ 'previous', 'next' ];
13871
+ },
13872
+
13873
+ full: function ( page, pages ) {
13874
+ return [ 'first', 'previous', 'next', 'last' ];
13875
+ },
13876
+
13877
+ simple_numbers: function ( page, pages ) {
13878
+ return [ 'previous', _numbers(page, pages), 'next' ];
13879
+ },
13880
+
13881
+ full_numbers: function ( page, pages ) {
13882
+ return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
13883
+ },
13884
+
13885
+ // For testing and plug-ins to use
13886
+ _numbers: _numbers,
13887
+ numbers_length: 7
13888
+ } );
13889
+
13890
+
13891
+ $.extend( true, DataTable.ext.renderer, {
13892
+ pageButton: {
13893
+ _: function ( settings, host, idx, buttons, page, pages ) {
13894
+ var classes = settings.oClasses;
13895
+ var lang = settings.oLanguage.oPaginate;
13896
+ var btnDisplay, btnClass, counter=0;
13897
+
13898
+ var attach = function( container, buttons ) {
13899
+ var i, ien, node, button;
13900
+ var clickHandler = function ( e ) {
13901
+ _fnPageChange( settings, e.data.action, true );
13902
+ };
13903
+
13904
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
13905
+ button = buttons[i];
13906
+
13907
+ if ( $.isArray( button ) ) {
13908
+ var inner = $( '<'+(button.DT_el || 'div')+'/>' )
13909
+ .appendTo( container );
13910
+ attach( inner, button );
13911
+ }
13912
+ else {
13913
+ btnDisplay = '';
13914
+ btnClass = '';
13915
+
13916
+ switch ( button ) {
13917
+ case 'ellipsis':
13918
+ container.append('<span>&hellip;</span>');
13919
+ break;
13920
+
13921
+ case 'first':
13922
+ btnDisplay = lang.sFirst;
13923
+ btnClass = button + (page > 0 ?
13924
+ '' : ' '+classes.sPageButtonDisabled);
13925
+ break;
13926
+
13927
+ case 'previous':
13928
+ btnDisplay = lang.sPrevious;
13929
+ btnClass = button + (page > 0 ?
13930
+ '' : ' '+classes.sPageButtonDisabled);
13931
+ break;
13932
+
13933
+ case 'next':
13934
+ btnDisplay = lang.sNext;
13935
+ btnClass = button + (page < pages-1 ?
13936
+ '' : ' '+classes.sPageButtonDisabled);
13937
+ break;
13938
+
13939
+ case 'last':
13940
+ btnDisplay = lang.sLast;
13941
+ btnClass = button + (page < pages-1 ?
13942
+ '' : ' '+classes.sPageButtonDisabled);
13943
+ break;
13944
+
13945
+ default:
13946
+ btnDisplay = button + 1;
13947
+ btnClass = page === button ?
13948
+ classes.sPageButtonActive : '';
13949
+ break;
13950
+ }
13951
+
13952
+ if ( btnDisplay ) {
13953
+ node = $('<a>', {
13954
+ 'class': classes.sPageButton+' '+btnClass,
13955
+ 'aria-controls': settings.sTableId,
13956
+ 'data-dt-idx': counter,
13957
+ 'tabindex': settings.iTabIndex,
13958
+ 'id': idx === 0 && typeof button === 'string' ?
13959
+ settings.sTableId +'_'+ button :
13960
+ null
13961
+ } )
13962
+ .html( btnDisplay )
13963
+ .appendTo( container );
13964
+
13965
+ _fnBindAction(
13966
+ node, {action: button}, clickHandler
13967
+ );
13968
+
13969
+ counter++;
13970
+ }
13971
+ }
13972
+ }
13973
+ };
13974
+
13975
+ // IE9 throws an 'unknown error' if document.activeElement is used
13976
+ // inside an iframe or frame. Try / catch the error. Not good for
13977
+ // accessibility, but neither are frames.
13978
+ try {
13979
+ // Because this approach is destroying and recreating the paging
13980
+ // elements, focus is lost on the select button which is bad for
13981
+ // accessibility. So we want to restore focus once the draw has
13982
+ // completed
13983
+ var activeEl = $(document.activeElement).data('dt-idx');
13984
+
13985
+ attach( $(host).empty(), buttons );
13986
+
13987
+ if ( activeEl !== null ) {
13988
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
13989
+ }
13990
+ }
13991
+ catch (e) {}
13992
+ }
13993
+ }
13994
+ } );
13995
+
13996
+
13997
+
13998
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
13999
+ if ( !d || d === '-' ) {
14000
+ return -Infinity;
14001
+ }
14002
+
14003
+ // If a decimal place other than `.` is used, it needs to be given to the
14004
+ // function so we can detect it and replace with a `.` which is the only
14005
+ // decimal place Javascript recognises - it is not locale aware.
14006
+ if ( decimalPlace ) {
14007
+ d = _numToDecimal( d, decimalPlace );
14008
+ }
14009
+
14010
+ if ( d.replace ) {
14011
+ if ( re1 ) {
14012
+ d = d.replace( re1, '' );
14013
+ }
14014
+
14015
+ if ( re2 ) {
14016
+ d = d.replace( re2, '' );
14017
+ }
14018
+ }
14019
+
14020
+ return d * 1;
14021
+ };
14022
+
14023
+
14024
+ // Add the numeric 'deformatting' functions for sorting. This is done in a
14025
+ // function to provide an easy ability for the language options to add
14026
+ // additional methods if a non-period decimal place is used.
14027
+ function _addNumericSort ( decimalPlace ) {
14028
+ $.each(
14029
+ {
14030
+ // Plain numbers
14031
+ "num": function ( d ) {
14032
+ return __numericReplace( d, decimalPlace );
14033
+ },
14034
+
14035
+ // Formatted numbers
14036
+ "num-fmt": function ( d ) {
14037
+ return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14038
+ },
14039
+
14040
+ // HTML numeric
14041
+ "html-num": function ( d ) {
14042
+ return __numericReplace( d, decimalPlace, _re_html );
14043
+ },
14044
+
14045
+ // HTML numeric, formatted
14046
+ "html-num-fmt": function ( d ) {
14047
+ return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14048
+ }
14049
+ },
14050
+ function ( key, fn ) {
14051
+ _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14052
+ }
14053
+ );
14054
+ }
14055
+
14056
+
14057
+ // Default sort methods
14058
+ $.extend( _ext.type.order, {
14059
+ // Dates
14060
+ "date-pre": function ( d ) {
14061
+ return Date.parse( d ) || 0;
14062
+ },
14063
+
14064
+ // html
14065
+ "html-pre": function ( a ) {
14066
+ return _empty(a) ?
14067
+ '' :
14068
+ a.replace ?
14069
+ a.replace( /<.*?>/g, "" ).toLowerCase() :
14070
+ a+'';
14071
+ },
14072
+
14073
+ // string
14074
+ "string-pre": function ( a ) {
14075
+ // This is a little complex, but faster than always calling toString,
14076
+ // http://jsperf.com/tostring-v-check
14077
+ return _empty(a) ?
14078
+ '' :
14079
+ typeof a === 'string' ?
14080
+ a.toLowerCase() :
14081
+ ! a.toString ?
14082
+ '' :
14083
+ a.toString();
14084
+ },
14085
+
14086
+ // string-asc and -desc are retained only for compatibility with the old
14087
+ // sort methods
14088
+ "string-asc": function ( x, y ) {
14089
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14090
+ },
14091
+
14092
+ "string-desc": function ( x, y ) {
14093
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14094
+ }
14095
+ } );
14096
+
14097
+
14098
+ // Numeric sorting types - order doesn't matter here
14099
+ _addNumericSort( '' );
14100
+
14101
+
14102
+ // Built in type detection. See model.ext.aTypes for information about
14103
+ // what is required from this methods.
14104
+ $.extend( DataTable.ext.type.detect, [
14105
+ // Plain numbers - first since V8 detects some plain numbers as dates
14106
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14107
+ function ( d, settings )
14108
+ {
14109
+ var decimal = settings.oLanguage.sDecimal;
14110
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14111
+ },
14112
+
14113
+ // Dates (only those recognised by the browser's Date.parse)
14114
+ function ( d, settings )
14115
+ {
14116
+ // V8 will remove any unknown characters at the start and end of the
14117
+ // expression, leading to false matches such as `$245.12` or `10%` being
14118
+ // a valid date. See forum thread 18941 for detail.
14119
+ if ( d && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14120
+ return null;
14121
+ }
14122
+ var parsed = Date.parse(d);
14123
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14124
+ },
14125
+
14126
+ // Formatted numbers
14127
+ function ( d, settings )
14128
+ {
14129
+ var decimal = settings.oLanguage.sDecimal;
14130
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14131
+ },
14132
+
14133
+ // HTML numeric
14134
+ function ( d, settings )
14135
+ {
14136
+ var decimal = settings.oLanguage.sDecimal;
14137
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14138
+ },
14139
+
14140
+ // HTML numeric, formatted
14141
+ function ( d, settings )
14142
+ {
14143
+ var decimal = settings.oLanguage.sDecimal;
14144
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14145
+ },
14146
+
14147
+ // HTML (this is strict checking - there must be html)
14148
+ function ( d, settings )
14149
+ {
14150
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14151
+ 'html' : null;
14152
+ }
14153
+ ] );
14154
+
14155
+
14156
+
14157
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14158
+ // what is required from these methods.
14159
+
14160
+
14161
+ $.extend( DataTable.ext.type.search, {
14162
+ html: function ( data ) {
14163
+ return _empty(data) ?
14164
+ data :
14165
+ typeof data === 'string' ?
14166
+ data
14167
+ .replace( _re_new_lines, " " )
14168
+ .replace( _re_html, "" ) :
14169
+ '';
14170
+ },
14171
+
14172
+ string: function ( data ) {
14173
+ return _empty(data) ?
14174
+ data :
14175
+ typeof data === 'string' ?
14176
+ data.replace( _re_new_lines, " " ) :
14177
+ data;
14178
+ }
14179
+ } );
14180
+
14181
+
14182
+
14183
+ $.extend( true, DataTable.ext.renderer, {
14184
+ header: {
14185
+ _: function ( settings, cell, column, classes ) {
14186
+ // No additional mark-up required
14187
+ // Attach a sort listener to update on sort - note that using the
14188
+ // `DT` namespace will allow the event to be removed automatically
14189
+ // on destroy, while the `dt` namespaced event is the one we are
14190
+ // listening for
14191
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14192
+ if ( settings !== ctx ) { // need to check this this is the host
14193
+ return; // table, not a nested one
14194
+ }
14195
+
14196
+ var colIdx = column.idx;
14197
+
14198
+ cell
14199
+ .removeClass(
14200
+ column.sSortingClass +' '+
14201
+ classes.sSortAsc +' '+
14202
+ classes.sSortDesc
14203
+ )
14204
+ .addClass( columns[ colIdx ] == 'asc' ?
14205
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14206
+ classes.sSortDesc :
14207
+ column.sSortingClass
14208
+ );
14209
+ } );
14210
+ },
14211
+
14212
+ jqueryui: function ( settings, cell, column, classes ) {
14213
+ var colIdx = column.idx;
14214
+
14215
+ $('<div/>')
14216
+ .addClass( classes.sSortJUIWrapper )
14217
+ .append( cell.contents() )
14218
+ .append( $('<span/>')
14219
+ .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14220
+ )
14221
+ .appendTo( cell );
14222
+
14223
+ // Attach a sort listener to update on sort
14224
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14225
+ if ( settings !== ctx ) {
14226
+ return;
14227
+ }
14228
+
14229
+ cell
14230
+ .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14231
+ .addClass( columns[ colIdx ] == 'asc' ?
14232
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14233
+ classes.sSortDesc :
14234
+ column.sSortingClass
14235
+ );
14236
+
14237
+ cell
14238
+ .find( 'span.'+classes.sSortIcon )
14239
+ .removeClass(
14240
+ classes.sSortJUIAsc +" "+
14241
+ classes.sSortJUIDesc +" "+
14242
+ classes.sSortJUI +" "+
14243
+ classes.sSortJUIAscAllowed +" "+
14244
+ classes.sSortJUIDescAllowed
14245
+ )
14246
+ .addClass( columns[ colIdx ] == 'asc' ?
14247
+ classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14248
+ classes.sSortJUIDesc :
14249
+ column.sSortingClassJUI
14250
+ );
14251
+ } );
14252
+ }
14253
+ }
14254
+ } );
14255
+
14256
+ /*
14257
+ * Public helper functions. These aren't used internally by DataTables, or
14258
+ * called by any of the options passed into DataTables, but they can be used
14259
+ * externally by developers working with DataTables. They are helper functions
14260
+ * to make working with DataTables a little bit easier.
14261
+ */
14262
+
14263
+ /**
14264
+ * Helpers for `columns.render`.
14265
+ *
14266
+ * The options defined here can be used with the `columns.render` initialisation
14267
+ * option to provide a display renderer. The following functions are defined:
14268
+ *
14269
+ * * `number` - Will format numeric data (defined by `columns.data`) for
14270
+ * display, retaining the original unformatted data for sorting and filtering.
14271
+ * It takes 4 parameters:
14272
+ * * `string` - Thousands grouping separator
14273
+ * * `string` - Decimal point indicator
14274
+ * * `integer` - Number of decimal points to show
14275
+ * * `string` (optional) - Prefix.
14276
+ *
14277
+ * @example
14278
+ * // Column definition using the number renderer
14279
+ * {
14280
+ * data: "salary",
14281
+ * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14282
+ * }
14283
+ *
14284
+ * @namespace
14285
+ */
14286
+ DataTable.render = {
14287
+ number: function ( thousands, decimal, precision, prefix ) {
14288
+ return {
14289
+ display: function ( d ) {
14290
+ var negative = d < 0 ? '-' : '';
14291
+ d = Math.abs( parseFloat( d ) );
14292
+
14293
+ var intPart = parseInt( d, 10 );
14294
+ var floatPart = precision ?
14295
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14296
+ '';
14297
+
14298
+ return negative + (prefix||'') +
14299
+ intPart.toString().replace(
14300
+ /\B(?=(\d{3})+(?!\d))/g, thousands
14301
+ ) +
14302
+ floatPart;
14303
+ }
14304
+ };
14305
+ }
14306
+ };
14307
+
14308
+
14309
+ /*
14310
+ * This is really a good bit rubbish this method of exposing the internal methods
14311
+ * publicly... - To be fixed in 2.0 using methods on the prototype
14312
+ */
14313
+
14314
+
14315
+ /**
14316
+ * Create a wrapper function for exporting an internal functions to an external API.
14317
+ * @param {string} fn API function name
14318
+ * @returns {function} wrapped function
14319
+ * @memberof DataTable#internal
14320
+ */
14321
+ function _fnExternApiFunc (fn)
14322
+ {
14323
+ return function() {
14324
+ var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14325
+ Array.prototype.slice.call(arguments)
14326
+ );
14327
+ return DataTable.ext.internal[fn].apply( this, args );
14328
+ };
14329
+ }
14330
+
14331
+
14332
+ /**
14333
+ * Reference to internal functions for use by plug-in developers. Note that
14334
+ * these methods are references to internal functions and are considered to be
14335
+ * private. If you use these methods, be aware that they are liable to change
14336
+ * between versions.
14337
+ * @namespace
14338
+ */
14339
+ $.extend( DataTable.ext.internal, {
14340
+ _fnExternApiFunc: _fnExternApiFunc,
14341
+ _fnBuildAjax: _fnBuildAjax,
14342
+ _fnAjaxUpdate: _fnAjaxUpdate,
14343
+ _fnAjaxParameters: _fnAjaxParameters,
14344
+ _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14345
+ _fnAjaxDataSrc: _fnAjaxDataSrc,
14346
+ _fnAddColumn: _fnAddColumn,
14347
+ _fnColumnOptions: _fnColumnOptions,
14348
+ _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14349
+ _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14350
+ _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14351
+ _fnVisbleColumns: _fnVisbleColumns,
14352
+ _fnGetColumns: _fnGetColumns,
14353
+ _fnColumnTypes: _fnColumnTypes,
14354
+ _fnApplyColumnDefs: _fnApplyColumnDefs,
14355
+ _fnHungarianMap: _fnHungarianMap,
14356
+ _fnCamelToHungarian: _fnCamelToHungarian,
14357
+ _fnLanguageCompat: _fnLanguageCompat,
14358
+ _fnBrowserDetect: _fnBrowserDetect,
14359
+ _fnAddData: _fnAddData,
14360
+ _fnAddTr: _fnAddTr,
14361
+ _fnNodeToDataIndex: _fnNodeToDataIndex,
14362
+ _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14363
+ _fnGetCellData: _fnGetCellData,
14364
+ _fnSetCellData: _fnSetCellData,
14365
+ _fnSplitObjNotation: _fnSplitObjNotation,
14366
+ _fnGetObjectDataFn: _fnGetObjectDataFn,
14367
+ _fnSetObjectDataFn: _fnSetObjectDataFn,
14368
+ _fnGetDataMaster: _fnGetDataMaster,
14369
+ _fnClearTable: _fnClearTable,
14370
+ _fnDeleteIndex: _fnDeleteIndex,
14371
+ _fnInvalidateRow: _fnInvalidateRow,
14372
+ _fnGetRowElements: _fnGetRowElements,
14373
+ _fnCreateTr: _fnCreateTr,
14374
+ _fnBuildHead: _fnBuildHead,
14375
+ _fnDrawHead: _fnDrawHead,
14376
+ _fnDraw: _fnDraw,
14377
+ _fnReDraw: _fnReDraw,
14378
+ _fnAddOptionsHtml: _fnAddOptionsHtml,
14379
+ _fnDetectHeader: _fnDetectHeader,
14380
+ _fnGetUniqueThs: _fnGetUniqueThs,
14381
+ _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14382
+ _fnFilterComplete: _fnFilterComplete,
14383
+ _fnFilterCustom: _fnFilterCustom,
14384
+ _fnFilterColumn: _fnFilterColumn,
14385
+ _fnFilter: _fnFilter,
14386
+ _fnFilterCreateSearch: _fnFilterCreateSearch,
14387
+ _fnEscapeRegex: _fnEscapeRegex,
14388
+ _fnFilterData: _fnFilterData,
14389
+ _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14390
+ _fnUpdateInfo: _fnUpdateInfo,
14391
+ _fnInfoMacros: _fnInfoMacros,
14392
+ _fnInitialise: _fnInitialise,
14393
+ _fnInitComplete: _fnInitComplete,
14394
+ _fnLengthChange: _fnLengthChange,
14395
+ _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14396
+ _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14397
+ _fnPageChange: _fnPageChange,
14398
+ _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14399
+ _fnProcessingDisplay: _fnProcessingDisplay,
14400
+ _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14401
+ _fnScrollDraw: _fnScrollDraw,
14402
+ _fnApplyToChildren: _fnApplyToChildren,
14403
+ _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14404
+ _fnThrottle: _fnThrottle,
14405
+ _fnConvertToWidth: _fnConvertToWidth,
14406
+ _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14407
+ _fnGetWidestNode: _fnGetWidestNode,
14408
+ _fnGetMaxLenString: _fnGetMaxLenString,
14409
+ _fnStringToCss: _fnStringToCss,
14410
+ _fnScrollBarWidth: _fnScrollBarWidth,
14411
+ _fnSortFlatten: _fnSortFlatten,
14412
+ _fnSort: _fnSort,
14413
+ _fnSortAria: _fnSortAria,
14414
+ _fnSortListener: _fnSortListener,
14415
+ _fnSortAttachListener: _fnSortAttachListener,
14416
+ _fnSortingClasses: _fnSortingClasses,
14417
+ _fnSortData: _fnSortData,
14418
+ _fnSaveState: _fnSaveState,
14419
+ _fnLoadState: _fnLoadState,
14420
+ _fnSettingsFromNode: _fnSettingsFromNode,
14421
+ _fnLog: _fnLog,
14422
+ _fnMap: _fnMap,
14423
+ _fnBindAction: _fnBindAction,
14424
+ _fnCallbackReg: _fnCallbackReg,
14425
+ _fnCallbackFire: _fnCallbackFire,
14426
+ _fnLengthOverflow: _fnLengthOverflow,
14427
+ _fnRenderer: _fnRenderer,
14428
+ _fnDataSource: _fnDataSource,
14429
+ _fnRowAttributes: _fnRowAttributes,
14430
+ _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14431
+ // in 1.10, so this dead-end function is
14432
+ // added to prevent errors
14433
+ } );
14434
+
14435
+
14436
+ // jQuery access
14437
+ $.fn.dataTable = DataTable;
14438
+
14439
+ // Legacy aliases
14440
+ $.fn.dataTableSettings = DataTable.settings;
14441
+ $.fn.dataTableExt = DataTable.ext;
14442
+
14443
+ // With a capital `D` we return a DataTables API instance rather than a
14444
+ // jQuery object
14445
+ $.fn.DataTable = function ( opts ) {
14446
+ return $(this).dataTable( opts ).api();
14447
+ };
14448
+
14449
+ // All properties that are available to $.fn.dataTable should also be
14450
+ // available on $.fn.DataTable
14451
+ $.each( DataTable, function ( prop, val ) {
14452
+ $.fn.DataTable[ prop ] = val;
14453
+ } );
14454
+
14455
+
14456
+ // Information about events fired by DataTables - for documentation.
14457
+ /**
14458
+ * Draw event, fired whenever the table is redrawn on the page, at the same
14459
+ * point as fnDrawCallback. This may be useful for binding events or
14460
+ * performing calculations when the table is altered at all.
14461
+ * @name DataTable#draw.dt
14462
+ * @event
14463
+ * @param {event} e jQuery event object
14464
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14465
+ */
14466
+
14467
+ /**
14468
+ * Search event, fired when the searching applied to the table (using the
14469
+ * built-in global search, or column filters) is altered.
14470
+ * @name DataTable#search.dt
14471
+ * @event
14472
+ * @param {event} e jQuery event object
14473
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14474
+ */
14475
+
14476
+ /**
14477
+ * Page change event, fired when the paging of the table is altered.
14478
+ * @name DataTable#page.dt
14479
+ * @event
14480
+ * @param {event} e jQuery event object
14481
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14482
+ */
14483
+
14484
+ /**
14485
+ * Order event, fired when the ordering applied to the table is altered.
14486
+ * @name DataTable#order.dt
14487
+ * @event
14488
+ * @param {event} e jQuery event object
14489
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14490
+ */
14491
+
14492
+ /**
14493
+ * DataTables initialisation complete event, fired when the table is fully
14494
+ * drawn, including Ajax data loaded, if Ajax data is required.
14495
+ * @name DataTable#init.dt
14496
+ * @event
14497
+ * @param {event} e jQuery event object
14498
+ * @param {object} oSettings DataTables settings object
14499
+ * @param {object} json The JSON object request from the server - only
14500
+ * present if client-side Ajax sourced data is used</li></ol>
14501
+ */
14502
+
14503
+ /**
14504
+ * State save event, fired when the table has changed state a new state save
14505
+ * is required. This event allows modification of the state saving object
14506
+ * prior to actually doing the save, including addition or other state
14507
+ * properties (for plug-ins) or modification of a DataTables core property.
14508
+ * @name DataTable#stateSaveParams.dt
14509
+ * @event
14510
+ * @param {event} e jQuery event object
14511
+ * @param {object} oSettings DataTables settings object
14512
+ * @param {object} json The state information to be saved
14513
+ */
14514
+
14515
+ /**
14516
+ * State load event, fired when the table is loading state from the stored
14517
+ * data, but prior to the settings object being modified by the saved state
14518
+ * - allowing modification of the saved state is required or loading of
14519
+ * state for a plug-in.
14520
+ * @name DataTable#stateLoadParams.dt
14521
+ * @event
14522
+ * @param {event} e jQuery event object
14523
+ * @param {object} oSettings DataTables settings object
14524
+ * @param {object} json The saved state information
14525
+ */
14526
+
14527
+ /**
14528
+ * State loaded event, fired when state has been loaded from stored data and
14529
+ * the settings object has been modified by the loaded data.
14530
+ * @name DataTable#stateLoaded.dt
14531
+ * @event
14532
+ * @param {event} e jQuery event object
14533
+ * @param {object} oSettings DataTables settings object
14534
+ * @param {object} json The saved state information
14535
+ */
14536
+
14537
+ /**
14538
+ * Processing event, fired when DataTables is doing some kind of processing
14539
+ * (be it, order, searcg or anything else). It can be used to indicate to
14540
+ * the end user that there is something happening, or that something has
14541
+ * finished.
14542
+ * @name DataTable#processing.dt
14543
+ * @event
14544
+ * @param {event} e jQuery event object
14545
+ * @param {object} oSettings DataTables settings object
14546
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
14547
+ */
14548
+
14549
+ /**
14550
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14551
+ * request to made to the server for new data. This event is called before
14552
+ * DataTables processed the returned data, so it can also be used to pre-
14553
+ * process the data returned from the server, if needed.
14554
+ *
14555
+ * Note that this trigger is called in `fnServerData`, if you override
14556
+ * `fnServerData` and which to use this event, you need to trigger it in you
14557
+ * success function.
14558
+ * @name DataTable#xhr.dt
14559
+ * @event
14560
+ * @param {event} e jQuery event object
14561
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14562
+ * @param {object} json JSON returned from the server
14563
+ *
14564
+ * @example
14565
+ * // Use a custom property returned from the server in another DOM element
14566
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14567
+ * $('#status').html( json.status );
14568
+ * } );
14569
+ *
14570
+ * @example
14571
+ * // Pre-process the data returned from the server
14572
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14573
+ * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14574
+ * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14575
+ * }
14576
+ * // Note no return - manipulate the data directly in the JSON object.
14577
+ * } );
14578
+ */
14579
+
14580
+ /**
14581
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14582
+ * or passing the bDestroy:true parameter in the initialisation object. This
14583
+ * can be used to remove bound events, added DOM nodes, etc.
14584
+ * @name DataTable#destroy.dt
14585
+ * @event
14586
+ * @param {event} e jQuery event object
14587
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14588
+ */
14589
+
14590
+ /**
14591
+ * Page length change event, fired when number of records to show on each
14592
+ * page (the length) is changed.
14593
+ * @name DataTable#length.dt
14594
+ * @event
14595
+ * @param {event} e jQuery event object
14596
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14597
+ * @param {integer} len New length
14598
+ */
14599
+
14600
+ /**
14601
+ * Column sizing has changed.
14602
+ * @name DataTable#column-sizing.dt
14603
+ * @event
14604
+ * @param {event} e jQuery event object
14605
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14606
+ */
14607
+
14608
+ /**
14609
+ * Column visibility has changed.
14610
+ * @name DataTable#column-visibility.dt
14611
+ * @event
14612
+ * @param {event} e jQuery event object
14613
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14614
+ * @param {int} column Column index
14615
+ * @param {bool} vis `false` if column now hidden, or `true` if visible
14616
+ */
14617
+
14618
+ return $.fn.dataTable;
14619
+ }));
14620
+
14621
+ }(window, document));
14622
+