IP Geo Block - Version 3.0.5

Version Description

  • New feature: Add "Live update" mode on "Logs" tab.
  • Improvement: List all the IP addresses in cache are now displayed and manageable on "Statistics" tab.
  • Improvement: Add "Either blocked or passed" as a new condition for recording logs. It enables to verify the requests "passed" from the blacklisted countries or the countries not in the whitelist.
  • Improvement: Add two new filter hooks to utilize Google APIs from native domain in China.
  • See 3.0.5 release note for some details.
Download this release

Release Info

Developer tokkonopapa
Plugin Icon 128x128 IP Geo Block
Version 3.0.5
Comparing to
See all releases

Code changes from version 3.0.4.6 to 3.0.5

README.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: tokkonopapa
3
  Donate link:
4
  Tags: security, firewall, brute force, vulnerability, login, wp-admin, admin, ajax, xmlrpc, comment, pingback, trackback, spam, IP address, geo, geolocation, buddypress, bbPress
5
  Requires at least: 3.7
6
- Tested up to: 4.8.2
7
- Stable tag: 3.0.4.6
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -266,7 +266,7 @@ You can add an IP address to the `X-Forwarded-For` header to emulate the access
266
 
267
  See more details at "[How to test prevention of attacks](http://www.ipgeoblock.com/codex/#how-to-test-prevention-of-attacks 'Codex | IP Geo Block')".
268
 
269
- = I was locked down. What shall I do? =
270
 
271
  You can find the "**Emergent Functionality**" code section near the bottom of `ip-geo-block.php`. This code block can be activated by replacing `/*` (opening multi-line comment) at the top of the line to `//` (single line comment), or `*` at the end of the line to `*/` (closing multi-line comment).
272
 
@@ -352,6 +352,13 @@ Please refer to "[How can I fix permission troubles?](http://www.ipgeoblock.com/
352
 
353
  == Changelog ==
354
 
 
 
 
 
 
 
 
355
  = 3.0.4.6 =
356
  * **Bug fix:** Fix the issue that the emergent functionality didn't work when the number of login attempts reached to the limit.
357
  * **Bug fix:** Fix the issue that the result would be always `limited` when "Max number of failed login attempts per IP address" is "Disabled".
3
  Donate link:
4
  Tags: security, firewall, brute force, vulnerability, login, wp-admin, admin, ajax, xmlrpc, comment, pingback, trackback, spam, IP address, geo, geolocation, buddypress, bbPress
5
  Requires at least: 3.7
6
+ Tested up to: 4.9
7
+ Stable tag: 3.0.5
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
266
 
267
  See more details at "[How to test prevention of attacks](http://www.ipgeoblock.com/codex/#how-to-test-prevention-of-attacks 'Codex | IP Geo Block')".
268
 
269
+ = I'm locked out! What shall I do? =
270
 
271
  You can find the "**Emergent Functionality**" code section near the bottom of `ip-geo-block.php`. This code block can be activated by replacing `/*` (opening multi-line comment) at the top of the line to `//` (single line comment), or `*` at the end of the line to `*/` (closing multi-line comment).
272
 
352
 
353
  == Changelog ==
354
 
355
+ = 3.0.5 =
356
+ * **New feature:** Add "Live update" mode on "Logs" tab.
357
+ * **Improvement:** List all the IP addresses in cache are now displayed and manageable on "Statistics" tab.
358
+ * **Improvement:** Add "Either blocked or passed" as a new condition for recording logs. It enables to verify the requests "passed" from the blacklisted countries or the countries not in the whitelist.
359
+ * **Improvement:** Add two new filter hooks to utilize Google APIs from native domain in China.
360
+ * See [3.0.5 release note](http://www.ipgeoblock.com/changelog/release-3.0.5.html "3.0.5 Release Note | IP Geo Block") for some details.
361
+
362
  = 3.0.4.6 =
363
  * **Bug fix:** Fix the issue that the emergent functionality didn't work when the number of login attempts reached to the limit.
364
  * **Bug fix:** Fix the issue that the result would be always `limited` when "Max number of failed login attempts per IP address" is "Disabled".
admin/class-ip-geo-block-admin.php CHANGED
@@ -11,6 +11,13 @@
11
 
12
  class IP_Geo_Block_Admin {
13
 
 
 
 
 
 
 
 
14
  /**
15
  * Globals in this class
16
  *
@@ -24,6 +31,10 @@ class IP_Geo_Block_Admin {
24
  * and adding a settings page and menu.
25
  */
26
  private function __construct() {
 
 
 
 
27
  // Load plugin text domain and add body class
28
  add_action( 'init', array( $this, 'admin_init' ) );
29
 
@@ -56,13 +67,13 @@ class IP_Geo_Block_Admin {
56
  if ( is_multisite() ) {
57
  add_action( 'network_admin_menu', array( $this, 'setup_admin_page' ) );
58
 
59
- // when a blog is created or deleted.
60
- add_action( 'wpmu_new_blog', array( $this, 'create_blog' ), 10, 6 ); // @since MU
61
- add_action( 'delete_blog', array( $this, 'delete_blog' ), 10, 2 ); // @since 3.0.0
62
-
63
  // validate capability instead of nonce. @since 2.0.0 && 3.0.0
64
  if ( $this->is_network = is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) )
65
  add_filter( IP_Geo_Block::PLUGIN_NAME . '-bypass-admins', array( $this, 'verify_network_redirect' ), 10, 2 );
 
 
 
 
66
  }
67
 
68
  // loads a plugin’s translated strings.
@@ -117,11 +128,9 @@ class IP_Geo_Block_Admin {
117
  *
118
  */
119
  public function verify_network_redirect( $queries, $settings ) {
120
- if ( IP_Geo_Block_Util::is_user_logged_in() && $settings['network_wide'] ) {
121
- if ( 'GET' === $_SERVER['REQUEST_METHOD'] && isset( $_GET['page'] ) ) {
122
- $queries[] = $_GET['page']; // $_GET['action'] should be checked in IP_Geo_Block::validate_admin()
123
- }
124
- }
125
 
126
  return $queries;
127
  }
@@ -143,7 +152,7 @@ class IP_Geo_Block_Admin {
143
  IP_Geo_Block_Activate::activate_blog();
144
 
145
  // Copy option from main blog.
146
- if ( is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) && $settings['network_wide'] )
147
  update_option( IP_Geo_Block::OPTION_NAME, $settings );
148
 
149
  // Restore the main blog.
@@ -151,8 +160,8 @@ class IP_Geo_Block_Admin {
151
  }
152
 
153
  public function delete_blog( $blog_id, $drop ) {
154
- if ( $drop )
155
- IP_Geo_Block_Logs::delete_tables(); // blog is already switched to the target in wpmu_delete_blog()
156
  }
157
 
158
  /**
@@ -166,31 +175,44 @@ class IP_Geo_Block_Admin {
166
  /**
167
  * Register and enqueue plugin-specific style sheet and JavaScript.
168
  *
 
169
  */
170
  public function enqueue_admin_assets() {
171
  $footer = TRUE;
172
  $dependency = array( 'jquery' );
173
-
174
- // css for option page
175
- wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-styles',
176
- plugins_url( ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ?
177
- 'css/admin.min.css' : 'css/admin.css', __FILE__
178
- ),
179
- array(), IP_Geo_Block::VERSION
180
- );
181
 
182
  switch ( $this->admin_tab ) {
183
- case 1:
184
- case 5:
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  // js for google chart
186
  wp_register_script(
187
  $addon = IP_Geo_Block::PLUGIN_NAME . '-google-chart',
188
- 'https://www.google.com/jsapi', array(), NULL, $footer
 
189
  );
190
  wp_enqueue_script( $addon );
191
  break;
192
 
193
- case 2:
194
  // js for google map
195
  $settings = IP_Geo_Block::get_option();
196
  if ( $key = $settings['api_key']['GoogleMap'] ) {
@@ -201,7 +223,8 @@ class IP_Geo_Block_Admin {
201
  $dependency, IP_Geo_Block::VERSION, $footer
202
  );
203
  wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-google-map',
204
- '//maps.googleapis.com/maps/api/js' . ( 'default' !== $key ? "?key=$key" : '' ),
 
205
  $dependency, IP_Geo_Block::VERSION, $footer
206
  );
207
  }
@@ -212,20 +235,22 @@ class IP_Geo_Block_Admin {
212
  $dependency, IP_Geo_Block::VERSION, $footer
213
  );
214
  break;
215
-
216
- case 4:
217
- // footable https://github.com/bradvin/FooTable
218
- wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-footable-css',
219
- plugins_url( 'css/footable.core.min.css', __FILE__ ),
220
- array(), IP_Geo_Block::VERSION
221
- );
222
- wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-footable-js',
223
- plugins_url( 'js/footable.min.js', __FILE__ ),
224
- $dependency, IP_Geo_Block::VERSION, $footer
225
- );
226
- break;
227
  }
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  // js for IP Geo Block admin page
230
  wp_register_script(
231
  $handle = IP_Geo_Block::PLUGIN_NAME . '-admin-script',
@@ -233,8 +258,7 @@ class IP_Geo_Block_Admin {
233
  'js/admin.min.js' : 'js/admin.js', __FILE__
234
  ),
235
  $dependency + ( isset( $addon ) ? array( $addon ) : array() ),
236
- IP_Geo_Block::VERSION,
237
- $footer
238
  );
239
  wp_localize_script( $handle,
240
  'IP_GEO_BLOCK',
@@ -244,16 +268,37 @@ class IP_Geo_Block_Admin {
244
  'url' => admin_url( 'admin-ajax.php' ),
245
  'nonce' => IP_Geo_Block_Util::create_nonce( $this->get_ajax_action() ),
246
  'msg' => array(
247
- __( 'Import settings ?', 'ip-geo-block' ),
248
- __( 'Create table ?', 'ip-geo-block' ),
249
- __( 'Delete table ?', 'ip-geo-block' ),
250
- __( 'Clear statistics ?', 'ip-geo-block' ),
251
- __( 'Clear cache ?', 'ip-geo-block' ),
252
- __( 'Clear logs ?', 'ip-geo-block' ),
253
- __( 'ajax for logged-in user', 'ip-geo-block' ),
254
- __( 'ajax for non logged-in user', 'ip-geo-block' ),
255
- __( 'This feature is available with HTML5 compliant browsers.', 'ip-geo-block' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  ),
 
 
257
  )
258
  );
259
  wp_enqueue_script( $handle );
@@ -265,10 +310,9 @@ class IP_Geo_Block_Admin {
265
  */
266
  public function add_plugin_meta_links( $links, $file ) {
267
  if ( $file === IP_GEO_BLOCK_BASE ) {
268
- $title = __( 'Contribute at GitHub', 'ip-geo-block' );
269
  array_push(
270
  $links,
271
- "<a href=\"http://www.ipgeoblock.com\" title=\"$title\" target=_blank>$title</a>"
272
  );
273
  }
274
 
@@ -280,10 +324,9 @@ class IP_Geo_Block_Admin {
280
  *
281
  */
282
  public function add_action_links( $links ) {
 
283
  return array_merge(
284
- array(
285
- 'settings' => '<a href="' . esc_url( admin_url( 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME ) ) . '">' . __( 'Settings' ) . '</a>'
286
- ),
287
  $links
288
  );
289
  }
@@ -342,13 +385,10 @@ class IP_Geo_Block_Admin {
342
  $settings = IP_Geo_Block::get_option();
343
 
344
  // Network wide or not
345
- $admin_menu = 'admin_menu' === current_filter();
346
- $this->is_network &= current_user_can( 'manage_network_options' ) && $settings['network_wide'];
347
-
348
- // Setup the tab number.
349
- $this->admin_tab = isset( $_GET['tab'] ) ? (int)$_GET['tab'] : 0;
350
- $this->admin_tab = min( 5, max( 0, $this->admin_tab ) );
351
 
 
352
  if ( $this->is_network ) {
353
  if ( $admin_menu ) {
354
  $this->admin_tab = max( $this->admin_tab, 1 );
@@ -356,7 +396,7 @@ class IP_Geo_Block_Admin {
356
  $this->admin_tab = 0;
357
  }
358
  } else {
359
- $this->admin_tab = min( 4, $this->admin_tab ); // exclude `Sites` in multisite.
360
  }
361
 
362
  if ( $admin_menu ) {
@@ -389,17 +429,31 @@ class IP_Geo_Block_Admin {
389
  __( 'IP Geo Block', 'ip-geo-block' ),
390
  'manage_network_options',
391
  IP_Geo_Block::PLUGIN_NAME,
392
- array( $this, 'display_plugin_admin_page' ),
393
- 'dashicons-shield' // plugins_url( 'img/icon-72x72.png', __FILE__ )
394
  );
395
- /*$hook = add_submenu_page(
396
- 'settings.php',
397
- __( 'IP Geo Block', 'ip-geo-block' ),
398
  __( 'IP Geo Block', 'ip-geo-block' ),
 
399
  'manage_network_options',
400
  IP_Geo_Block::PLUGIN_NAME,
401
  array( $this, 'display_plugin_admin_page' )
402
- );*/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403
  }
404
 
405
  // If successful, load admin assets only on this page.
@@ -413,7 +467,7 @@ class IP_Geo_Block_Admin {
413
  */
414
  private function diagnose_admin_screen() {
415
  $settings = IP_Geo_Block::get_option();
416
- $adminurl = $this->dashboard_url( FALSE );
417
 
418
  // Check version and compatibility
419
  if ( version_compare( get_bloginfo( 'version' ), '3.7.0' ) < 0 )
@@ -483,7 +537,7 @@ class IP_Geo_Block_Admin {
483
  if ( defined( 'IP_GEO_BLOCK_DEBUG' ) && IP_GEO_BLOCK_DEBUG ) {
484
  // Check creation of database table
485
  if ( $settings['validation']['reclogs'] ) {
486
- if ( ( $warn = IP_Geo_Block_Logs::diag_tables() ) &&
487
  ( FALSE === IP_Geo_Block_Logs::create_tables() ) ) {
488
  self::add_admin_notice( 'notice-warning', $warn );
489
  }
@@ -527,14 +581,16 @@ class IP_Geo_Block_Admin {
527
  * Get cookie that indicates open/close section
528
  *
529
  */
530
- public function get_cookie( $name ) {
531
- $cookie = array();
532
- if ( ! empty( $_COOKIE[ $name ] ) ) {
533
- foreach ( explode( '&', $_COOKIE[ $name ] ) as $i => $v ) {
 
534
  list( $i, $v ) = explode( '=', $v );
535
  $cookie[ $i ] = str_split( $v );
536
  }
537
  }
 
538
  return $cookie;
539
  }
540
 
@@ -548,13 +604,14 @@ class IP_Geo_Block_Admin {
548
 
549
  if ( isset( $wp_settings_sections[ $page ] ) ) {
550
  $index = 0; // index of fieldset
551
- $cookie = $this->get_cookie( IP_Geo_Block::PLUGIN_NAME );
552
 
553
  foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
554
  // TRUE if open ('o') or FALSE if close ('x')
555
  $stat = empty( $cookie[ $tab ][ $index ] ) || 'x' !== $cookie[ $tab ][ $index ];
556
 
557
- echo '<fieldset id="', IP_Geo_Block::PLUGIN_NAME, '-section-', $index, '" class="', IP_Geo_Block::PLUGIN_NAME, '-field panel panel-default" data-section="', $index, '">', "\n",
 
558
  '<legend class="panel-heading"><h3 class="', IP_Geo_Block::PLUGIN_NAME, ( $stat ? '-dropdown' : '-dropup' ), '">', $section['title'],
559
  '</h3></legend>', "\n", '<div class="panel-body',
560
  ($stat ? ' ' . IP_Geo_Block::PLUGIN_NAME . '-border"' : '"'),
@@ -589,11 +646,12 @@ class IP_Geo_Block_Admin {
589
  1 => __( 'Statistics', 'ip-geo-block' ),
590
  4 => __( 'Logs', 'ip-geo-block' ),
591
  2 => __( 'Search', 'ip-geo-block' ),
592
- 5 => __( 'Sites', 'ip-geo-block' ),
593
  3 => __( 'Attribution', 'ip-geo-block' ),
594
  );
595
 
596
  $settings = IP_Geo_Block::get_option();
 
597
  $title = esc_html( get_admin_page_title() );
598
 
599
  // Target page that depends on the network multisite or not.
@@ -601,20 +659,21 @@ class IP_Geo_Block_Admin {
601
  $action = 'options.php';
602
 
603
  if ( $this->is_network ) {
604
- unset( $tabs[0], $tabs[5] ); // Settings, Sites
605
  $title .= ' <span class="ip-geo-block-title-link">';
606
- $title .= ' [ <a href="' . esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0 ), $this->dashboard_url( TRUE ) ) ) . '" target="_self">' . __( 'Settings', 'ip-geo-block' ) . '</a> ]';
607
- $title .= ' [ <a href="' . esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 5 ), $this->dashboard_url( TRUE ) ) ) . '" target="_self">' . __( 'Sites', 'ip-geo-block' ) . '</a> ]';
608
  $title .= '</span>';
609
  } else {
610
- unset( $tabs[5] ); // Sites
611
  }
612
  } else {
613
  $action = 'edit.php?action=' . IP_Geo_Block::PLUGIN_NAME;
614
 
615
  if ( $settings['network_wide'] ) {
616
  unset( $tabs[1], $tabs[4], $tabs[2], $tabs[3] ); // Statistics, Logs, Search, Attribution
617
- $title .= ' <span class="ip-geo-block-title-link">[ ' . __( 'Network', 'ip-geo-block' ) . ' ]';
 
618
  $title .= '</span>';
619
  }
620
  }
@@ -627,7 +686,16 @@ class IP_Geo_Block_Admin {
627
  echo '<a href="?page=', IP_Geo_Block::PLUGIN_NAME, '&amp;tab=', $key, '" class="nav-tab', ($tab === $key ? ' nav-tab-active' : ''), '">', $val, '</a>';
628
  } ?>
629
  </h2>
630
- <p style="text-align:left">[ <a id="ip-geo-block-toggle-sections" href="javascript:void(0)"><?php _e( 'Toggle all', 'ip-geo-block' ); ?></a> ]</p>
 
 
 
 
 
 
 
 
 
631
  <form method="post" action="<?php echo $action; ?>" id="<?php echo IP_Geo_Block::PLUGIN_NAME, '-', $tab; ?>"<?php if ( $tab ) echo " class=\"", IP_Geo_Block::PLUGIN_NAME, "-inhibit\""; ?>>
632
  <?php
633
  settings_fields( IP_Geo_Block::PLUGIN_NAME );
@@ -636,10 +704,10 @@ class IP_Geo_Block_Admin {
636
  submit_button(); // @since 3.1
637
  ?>
638
  </form>
639
- <?php if ( 2 === $tab ) { ?>
640
  <div id="ip-geo-block-whois"></div>
641
  <div id="ip-geo-block-map"></div>
642
- <?php } elseif ( 3 === $tab ) {
643
  // show attribution (higher priority order)
644
  $tab = array();
645
  foreach ( IP_Geo_Block_Provider::get_addons() as $provider ) {
@@ -648,7 +716,6 @@ class IP_Geo_Block_Admin {
648
  }
649
  }
650
  echo '<p>', implode( '<br />', $tab ), "</p>\n";
651
-
652
  echo '<p>', __( 'Thanks for providing these great services for free.', 'ip-geo-block' ), "<br />\n";
653
  echo __( '(Most browsers will redirect you to each site <a href="http://www.ipgeoblock.com/etc/referer.html" title="Referer Checker">without referrer when you click the link</a>.)', 'ip-geo-block' ), "</p>\n";
654
  } ?>
@@ -767,7 +834,7 @@ class IP_Geo_Block_Admin {
767
  echo ' data-desc="', $args['desc'][ $key ], '"';
768
  $key === $args['value'] and $desc = $args['desc'][ $key ];
769
  }
770
- echo ">$val</option>\n";
771
  }
772
  echo "</select>\n";
773
 
@@ -826,7 +893,7 @@ class IP_Geo_Block_Admin {
826
  $output = IP_Geo_Block::get_option();
827
  $default = IP_Geo_Block::get_default();
828
 
829
- // Integrate posted data into current settings because if can be a part of hole data
830
  $input = array_replace_recursive(
831
  $output = $this->preprocess_options( $output, $default ),
832
  $input
@@ -1005,6 +1072,9 @@ class IP_Geo_Block_Admin {
1005
  // 3.0.4 AS number
1006
  $output['Maxmind']['use_asn'] = FALSE;
1007
 
 
 
 
1008
  return $output;
1009
  }
1010
 
@@ -1194,12 +1264,15 @@ class IP_Geo_Block_Admin {
1194
  private function sync_multisite_option( $option ) {
1195
  global $wpdb;
1196
  $blog_ids = $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" );
 
1197
 
1198
  foreach ( $blog_ids as $id ) {
1199
  switch_to_blog( $id );
1200
- update_option( IP_Geo_Block::OPTION_NAME, $option );
1201
  restore_current_blog();
1202
  }
 
 
1203
  }
1204
 
1205
  /**
@@ -1215,6 +1288,7 @@ class IP_Geo_Block_Admin {
1215
 
1216
  require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
1217
 
 
1218
  $which = isset( $_POST['which'] ) ? $_POST['which'] : NULL;
1219
  switch ( isset( $_POST['cmd' ] ) ? $_POST['cmd' ] : NULL ) {
1220
  case 'download':
@@ -1266,7 +1340,7 @@ class IP_Geo_Block_Admin {
1266
  IP_Geo_Block_Admin_Ajax::export_logs( $which );
1267
  break;
1268
 
1269
- case 'restore':
1270
  // Get logs from MySQL DB
1271
  $res = IP_Geo_Block_Admin_Ajax::restore_logs( $which );
1272
  break;
@@ -1288,10 +1362,9 @@ class IP_Geo_Block_Admin {
1288
 
1289
  case 'gmap-error':
1290
  // Reset Google Maps API key
1291
- $which = IP_Geo_Block::get_option();
1292
- if ( $which['api_key']['GoogleMap'] === 'default' ) {
1293
- $which['api_key']['GoogleMap'] = NULL;
1294
- update_option( IP_Geo_Block::OPTION_NAME, $which );
1295
  $res = array(
1296
  'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
1297
  'tab' => 'tab=2'
@@ -1300,6 +1373,7 @@ class IP_Geo_Block_Admin {
1300
  break;
1301
 
1302
  case 'show-info':
 
1303
  $res = IP_Geo_Block_Admin_Ajax::get_wp_info();
1304
  break;
1305
 
@@ -1308,6 +1382,82 @@ class IP_Geo_Block_Admin {
1308
  $res = IP_Geo_Block_Util::get_registered_actions( TRUE );
1309
  break;
1310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1311
  case 'create-table':
1312
  case 'delete-table':
1313
  // Need to define `IP_GEO_BLOCK_DEBUG` to true
11
 
12
  class IP_Geo_Block_Admin {
13
 
14
+ /**
15
+ * Constants for admin class
16
+ *
17
+ */
18
+ const INTERVAL_LIVE_UPDATE = 5; // interval for live update [sec]
19
+ const TIMEOUT_LIVE_UPDATE = 60; // timeout of pausing live update [sec]
20
+
21
  /**
22
  * Globals in this class
23
  *
31
  * and adding a settings page and menu.
32
  */
33
  private function __construct() {
34
+ // Setup the tab number.
35
+ $this->admin_tab = isset( $_GET['tab'] ) ? (int)$_GET['tab'] : 0;
36
+ $this->admin_tab = min( 5, max( 0, $this->admin_tab ) );
37
+
38
  // Load plugin text domain and add body class
39
  add_action( 'init', array( $this, 'admin_init' ) );
40
 
67
  if ( is_multisite() ) {
68
  add_action( 'network_admin_menu', array( $this, 'setup_admin_page' ) );
69
 
 
 
 
 
70
  // validate capability instead of nonce. @since 2.0.0 && 3.0.0
71
  if ( $this->is_network = is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) )
72
  add_filter( IP_Geo_Block::PLUGIN_NAME . '-bypass-admins', array( $this, 'verify_network_redirect' ), 10, 2 );
73
+
74
+ // when a blog is created or deleted.
75
+ add_action( 'wpmu_new_blog', array( $this, 'create_blog' ), 10, 6 ); // @since MU
76
+ add_action( 'delete_blog', array( $this, 'delete_blog' ), 10, 2 ); // @since 3.0.0
77
  }
78
 
79
  // loads a plugin’s translated strings.
128
  *
129
  */
130
  public function verify_network_redirect( $queries, $settings ) {
131
+ // the request that is intended to show the page without any action follows authentication of core.
132
+ if ( 'GET' === $_SERVER['REQUEST_METHOD'] && isset( $_GET['page'] ) && empty( $_GET['action'] ) )
133
+ $queries[] = $_GET['page'];
 
 
134
 
135
  return $queries;
136
  }
152
  IP_Geo_Block_Activate::activate_blog();
153
 
154
  // Copy option from main blog.
155
+ if ( $this->is_network && $settings['network_wide'] )
156
  update_option( IP_Geo_Block::OPTION_NAME, $settings );
157
 
158
  // Restore the main blog.
160
  }
161
 
162
  public function delete_blog( $blog_id, $drop ) {
163
+ // blog is already switched to the target in wpmu_delete_blog()
164
+ $drop and IP_Geo_Block_Logs::delete_tables();
165
  }
166
 
167
  /**
175
  /**
176
  * Register and enqueue plugin-specific style sheet and JavaScript.
177
  *
178
+ * @see https://developers.google.com/maps/faq#china_ws_access
179
  */
180
  public function enqueue_admin_assets() {
181
  $footer = TRUE;
182
  $dependency = array( 'jquery' );
183
+ $version = ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ?
184
+ IP_Geo_Block::VERSION :
185
+ max(
186
+ filemtime( plugin_dir_path( __FILE__ ) . 'css/admin.css' ),
187
+ filemtime( plugin_dir_path( __FILE__ ) . 'js/admin.js' )
188
+ );
 
 
189
 
190
  switch ( $this->admin_tab ) {
191
+ case 1: /* Statistics */
192
+ case 4: /* Logs */
193
+ // css and js for DataTables
194
+ wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-datatables-css',
195
+ plugins_url( 'datatables/css/datatables-all.min.css', __FILE__ ),
196
+ array(), IP_Geo_Block::VERSION
197
+ );
198
+ wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-datatables-js',
199
+ plugins_url( 'datatables/js/datatables-all.min.js', __FILE__ ),
200
+ $dependency, IP_Geo_Block::VERSION, $footer
201
+ );
202
+ if ( 4 === $this->admin_tab )
203
+ break;
204
+
205
+ case 5: /* Site list */
206
  // js for google chart
207
  wp_register_script(
208
  $addon = IP_Geo_Block::PLUGIN_NAME . '-google-chart',
209
+ // 'https://www.google.cn/jsapi' in china
210
+ apply_filters( 'google-jsapi', 'https://www.google.com/jsapi' ), array(), NULL, $footer
211
  );
212
  wp_enqueue_script( $addon );
213
  break;
214
 
215
+ case 2: /* Search */
216
  // js for google map
217
  $settings = IP_Geo_Block::get_option();
218
  if ( $key = $settings['api_key']['GoogleMap'] ) {
223
  $dependency, IP_Geo_Block::VERSION, $footer
224
  );
225
  wp_enqueue_script( IP_Geo_Block::PLUGIN_NAME . '-google-map',
226
+ // 'http://maps.google.cn/maps/api/js' in china
227
+ apply_filters( 'google-maps', '//maps.googleapis.com/maps/api/js' ) . ( 'default' !== $key ? "?key=$key" : '' ),
228
  $dependency, IP_Geo_Block::VERSION, $footer
229
  );
230
  }
235
  $dependency, IP_Geo_Block::VERSION, $footer
236
  );
237
  break;
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
239
 
240
+ // css for option page
241
+ wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-icons',
242
+ plugins_url( ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ?
243
+ 'css/admin-icons.min.css' : 'css/admin-icons.css', __FILE__
244
+ ),
245
+ array(), IP_Geo_Block::VERSION
246
+ );
247
+ wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-styles',
248
+ plugins_url( ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ?
249
+ 'css/admin.min.css' : 'css/admin.css', __FILE__
250
+ ),
251
+ array(), $version
252
+ );
253
+
254
  // js for IP Geo Block admin page
255
  wp_register_script(
256
  $handle = IP_Geo_Block::PLUGIN_NAME . '-admin-script',
258
  'js/admin.min.js' : 'js/admin.js', __FILE__
259
  ),
260
  $dependency + ( isset( $addon ) ? array( $addon ) : array() ),
261
+ $version, $footer
 
262
  );
263
  wp_localize_script( $handle,
264
  'IP_GEO_BLOCK',
268
  'url' => admin_url( 'admin-ajax.php' ),
269
  'nonce' => IP_Geo_Block_Util::create_nonce( $this->get_ajax_action() ),
270
  'msg' => array(
271
+ /* [ 0] */ __( 'Import settings ?', 'ip-geo-block' ),
272
+ /* [ 1] */ __( 'Create table ?', 'ip-geo-block' ),
273
+ /* [ 2] */ __( 'Delete table ?', 'ip-geo-block' ),
274
+ /* [ 3] */ __( 'Clear statistics ?', 'ip-geo-block' ),
275
+ /* [ 4] */ __( 'Clear cache ?', 'ip-geo-block' ),
276
+ /* [ 5] */ __( 'Clear logs ?', 'ip-geo-block' ),
277
+ /* [ 6] */ __( 'ajax for logged-in user', 'ip-geo-block' ),
278
+ /* [ 7] */ __( 'ajax for non logged-in user', 'ip-geo-block' ),
279
+ /* [ 8] */ __( 'This feature is available with HTML5 compliant browsers.', 'ip-geo-block' ),
280
+ /* [ 9] */ __( 'The selected row cannot be found in the visible area.', 'ip-geo-block' ),
281
+ ),
282
+ 'i18n' => array(
283
+ /* [ 0] */ '<div class="ip-geo-block-loading"></div>',
284
+ /* [ 1] */ __( 'No data available in table', 'ip-geo-block' ),
285
+ /* [ 2] */ __( 'No matching records found', 'ip-geo-block' ),
286
+ /* [ 3] */ __( 'IP address', 'ip-geo-block' ),
287
+ /* [ 4] */ __( 'Code', 'ip-geo-block' ),
288
+ /* [ 5] */ __( 'ASN', 'ip-geo-block' ),
289
+ /* [ 6] */ __( 'Host name', 'ip-geo-block' ),
290
+ /* [ 7] */ __( 'Target', 'ip-geo-block' ),
291
+ /* [ 8] */ __( 'Failure / Total', 'ip-geo-block' ),
292
+ /* [ 9] */ __( 'Elapsed[sec]', 'ip-geo-block' ),
293
+ /* [10] */ __( 'Time', 'ip-geo-block' ),
294
+ /* [11] */ __( 'Result', 'ip-geo-block' ),
295
+ /* [12] */ __( 'Request', 'ip-geo-block' ),
296
+ /* [13] */ __( 'User agent', 'ip-geo-block' ),
297
+ /* [14] */ __( 'HTTP headers', 'ip-geo-block' ),
298
+ /* [15] */ __( '$_POST data', 'ip-geo-block' ),
299
  ),
300
+ 'interval' => self::INTERVAL_LIVE_UPDATE, // interval for live update [sec]
301
+ 'timeout' => self::TIMEOUT_LIVE_UPDATE, // timeout of pausing live update [sec]
302
  )
303
  );
304
  wp_enqueue_script( $handle );
310
  */
311
  public function add_plugin_meta_links( $links, $file ) {
312
  if ( $file === IP_GEO_BLOCK_BASE ) {
 
313
  array_push(
314
  $links,
315
+ '<a href="https://github.com/tokkonopapa/Wordpress-ip-geo-block" title="tokkonopapa/WordPress-IP-Geo-Block" target=_blank>' . __( 'Contribute on GitHub', 'ip-geo-block' ) . '</a>'
316
  );
317
  }
318
 
324
  *
325
  */
326
  public function add_action_links( $links ) {
327
+ // over network
328
  return array_merge(
329
+ array( 'settings' => '<a href="' . esc_url_raw( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME ), $this->dashboard_url( $this->is_network ) ) ) . '">' . __( 'Settings' ) . '</a>' ),
 
 
330
  $links
331
  );
332
  }
385
  $settings = IP_Geo_Block::get_option();
386
 
387
  // Network wide or not
388
+ $admin_menu = ( 'admin_menu' === current_filter() );
389
+ $this->is_network &= ( current_user_can( 'manage_network_options' ) && $settings['network_wide'] );
 
 
 
 
390
 
391
+ // Verify tab number
392
  if ( $this->is_network ) {
393
  if ( $admin_menu ) {
394
  $this->admin_tab = max( $this->admin_tab, 1 );
396
  $this->admin_tab = 0;
397
  }
398
  } else {
399
+ $this->admin_tab = min( 4, $this->admin_tab ); // exclude `Site List`
400
  }
401
 
402
  if ( $admin_menu ) {
429
  __( 'IP Geo Block', 'ip-geo-block' ),
430
  'manage_network_options',
431
  IP_Geo_Block::PLUGIN_NAME,
432
+ array( $this, 'display_plugin_admin_page' )
 
433
  );
434
+ add_submenu_page(
435
+ IP_Geo_Block::PLUGIN_NAME,
 
436
  __( 'IP Geo Block', 'ip-geo-block' ),
437
+ __( 'Settings', 'ip-geo-block' ),
438
  'manage_network_options',
439
  IP_Geo_Block::PLUGIN_NAME,
440
  array( $this, 'display_plugin_admin_page' )
441
+ );
442
+ add_submenu_page(
443
+ IP_Geo_Block::PLUGIN_NAME,
444
+ __( 'IP Geo Block', 'ip-geo-block' ),
445
+ __( 'Site List', 'ip-geo-block' ),
446
+ 'manage_network_options',
447
+ IP_Geo_Block::PLUGIN_NAME . '&amp;tab=5',
448
+ array( $this, 'display_plugin_admin_page' )
449
+ );
450
+
451
+ wp_enqueue_style( IP_Geo_Block::PLUGIN_NAME . '-admin-icons',
452
+ plugins_url( ! defined( 'IP_GEO_BLOCK_DEBUG' ) || ! IP_GEO_BLOCK_DEBUG ?
453
+ 'css/admin-icons.min.css' : 'css/admin-icons.css', __FILE__
454
+ ),
455
+ array(), IP_Geo_Block::VERSION
456
+ );
457
  }
458
 
459
  // If successful, load admin assets only on this page.
467
  */
468
  private function diagnose_admin_screen() {
469
  $settings = IP_Geo_Block::get_option();
470
+ $adminurl = $this->dashboard_url( $this->is_network );
471
 
472
  // Check version and compatibility
473
  if ( version_compare( get_bloginfo( 'version' ), '3.7.0' ) < 0 )
537
  if ( defined( 'IP_GEO_BLOCK_DEBUG' ) && IP_GEO_BLOCK_DEBUG ) {
538
  // Check creation of database table
539
  if ( $settings['validation']['reclogs'] ) {
540
+ if ( ( $warn = IP_Geo_Block_Logs::diag_tables() ) &&
541
  ( FALSE === IP_Geo_Block_Logs::create_tables() ) ) {
542
  self::add_admin_notice( 'notice-warning', $warn );
543
  }
581
  * Get cookie that indicates open/close section
582
  *
583
  */
584
+ public function get_cookie() {
585
+ static $cookie = array();
586
+
587
+ if ( empty( $cookie ) && ! empty( $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) ) {
588
+ foreach ( explode( '&', $_COOKIE[ IP_Geo_Block::PLUGIN_NAME ] ) as $i => $v ) {
589
  list( $i, $v ) = explode( '=', $v );
590
  $cookie[ $i ] = str_split( $v );
591
  }
592
  }
593
+
594
  return $cookie;
595
  }
596
 
604
 
605
  if ( isset( $wp_settings_sections[ $page ] ) ) {
606
  $index = 0; // index of fieldset
607
+ $cookie = $this->get_cookie();
608
 
609
  foreach ( (array) $wp_settings_sections[ $page ] as $section ) {
610
  // TRUE if open ('o') or FALSE if close ('x')
611
  $stat = empty( $cookie[ $tab ][ $index ] ) || 'x' !== $cookie[ $tab ][ $index ];
612
 
613
+ echo "\n",
614
+ '<fieldset id="', IP_Geo_Block::PLUGIN_NAME, '-section-', $index, '" class="', IP_Geo_Block::PLUGIN_NAME, '-field panel panel-default" data-section="', $index, '">', "\n",
615
  '<legend class="panel-heading"><h3 class="', IP_Geo_Block::PLUGIN_NAME, ( $stat ? '-dropdown' : '-dropup' ), '">', $section['title'],
616
  '</h3></legend>', "\n", '<div class="panel-body',
617
  ($stat ? ' ' . IP_Geo_Block::PLUGIN_NAME . '-border"' : '"'),
646
  1 => __( 'Statistics', 'ip-geo-block' ),
647
  4 => __( 'Logs', 'ip-geo-block' ),
648
  2 => __( 'Search', 'ip-geo-block' ),
649
+ 5 => __( 'Site List', 'ip-geo-block' ),
650
  3 => __( 'Attribution', 'ip-geo-block' ),
651
  );
652
 
653
  $settings = IP_Geo_Block::get_option();
654
+ $cookie = $this->get_cookie();
655
  $title = esc_html( get_admin_page_title() );
656
 
657
  // Target page that depends on the network multisite or not.
659
  $action = 'options.php';
660
 
661
  if ( $this->is_network ) {
662
+ unset( $tabs[0], $tabs[5] ); // Settings, Site List
663
  $title .= ' <span class="ip-geo-block-title-link">';
664
+ $title .= ' [ <a href="' . esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 0 ), $this->dashboard_url( TRUE ) ) ) . '" target="_self">' . __( 'Settings', 'ip-geo-block' ) . '</a> ]';
665
+ $title .= ' [ <a href="' . esc_url( add_query_arg( array( 'page' => IP_Geo_Block::PLUGIN_NAME, 'tab' => 5 ), $this->dashboard_url( TRUE ) ) ) . '" target="_self">' . __( 'Site List', 'ip-geo-block' ) . '</a> ]';
666
  $title .= '</span>';
667
  } else {
668
+ unset( $tabs[5] ); // Site List
669
  }
670
  } else {
671
  $action = 'edit.php?action=' . IP_Geo_Block::PLUGIN_NAME;
672
 
673
  if ( $settings['network_wide'] ) {
674
  unset( $tabs[1], $tabs[4], $tabs[2], $tabs[3] ); // Statistics, Logs, Search, Attribution
675
+ $title .= ' <span class="ip-geo-block-title-link">';
676
+ $title .= '[ ' . __( 'Network wide', 'ip-geo-block' ) . ' ]';
677
  $title .= '</span>';
678
  }
679
  }
686
  echo '<a href="?page=', IP_Geo_Block::PLUGIN_NAME, '&amp;tab=', $key, '" class="nav-tab', ($tab === $key ? ' nav-tab-active' : ''), '">', $val, '</a>';
687
  } ?>
688
  </h2>
689
+ <p style="text-align:left">[ <a id="ip-geo-block-toggle-sections" href="#!"><?php _e( 'Toggle all', 'ip-geo-block' ); ?></a> ]
690
+ <?php if ( 4 === $tab ) { /* Logs tab */ ?>
691
+ <input id="ip-geo-block-live-update" type="checkbox"<? checked( isset( $cookie[4][1] ) && 'o' === $cookie[4][1] ); disabled( extension_loaded( 'pdo_sqlite' ), FALSE ); ?> /><label for="ip-geo-block-live-update">
692
+ <dfn title="<?php _e( 'Independent of &#8220;Statistics and Logs settings&#8221;, you can see all the requests validated by this plugin in almost real time.', 'ip-geo-block' ); ?>"><?php _e( 'Live update', 'ip-geo-block' ); ?></dfn>
693
+ </label>
694
+ <?php } elseif (5 === $tab ) { /* Site List tab */ ?>
695
+ <input id="ip-geo-block-open-new" type="checkbox"<? checked( isset( $cookie[5][1] ) && 'o' === $cookie[5][1] );?> /><label for="ip-geo-block-open-new">
696
+ <dfn title="<?php _e( 'Open a new window on clicking the link in the chart.', 'ip-geo-block' ); ?>"><?php _e( 'Open a new window', 'ip-geo-block' ); ?></dfn>
697
+ </label>
698
+ <?php } ?></p>
699
  <form method="post" action="<?php echo $action; ?>" id="<?php echo IP_Geo_Block::PLUGIN_NAME, '-', $tab; ?>"<?php if ( $tab ) echo " class=\"", IP_Geo_Block::PLUGIN_NAME, "-inhibit\""; ?>>
700
  <?php
701
  settings_fields( IP_Geo_Block::PLUGIN_NAME );
704
  submit_button(); // @since 3.1
705
  ?>
706
  </form>
707
+ <?php if ( 2 === $tab ) { /* Search tab */ ?>
708
  <div id="ip-geo-block-whois"></div>
709
  <div id="ip-geo-block-map"></div>
710
+ <?php } elseif ( 3 === $tab ) { /* Attribute tab */
711
  // show attribution (higher priority order)
712
  $tab = array();
713
  foreach ( IP_Geo_Block_Provider::get_addons() as $provider ) {
716
  }
717
  }
718
  echo '<p>', implode( '<br />', $tab ), "</p>\n";
 
719
  echo '<p>', __( 'Thanks for providing these great services for free.', 'ip-geo-block' ), "<br />\n";
720
  echo __( '(Most browsers will redirect you to each site <a href="http://www.ipgeoblock.com/etc/referer.html" title="Referer Checker">without referrer when you click the link</a>.)', 'ip-geo-block' ), "</p>\n";
721
  } ?>
834
  echo ' data-desc="', $args['desc'][ $key ], '"';
835
  $key === $args['value'] and $desc = $args['desc'][ $key ];
836
  }
837
+ echo '>', ( NULL === $val ? __( 'Select one', 'ip-geo-block' ) : $val ), '</option>', "\n";
838
  }
839
  echo "</select>\n";
840
 
893
  $output = IP_Geo_Block::get_option();
894
  $default = IP_Geo_Block::get_default();
895
 
896
+ // Integrate posted data into current settings because it can be a part of hole data
897
  $input = array_replace_recursive(
898
  $output = $this->preprocess_options( $output, $default ),
899
  $input
1072
  // 3.0.4 AS number
1073
  $output['Maxmind']['use_asn'] = FALSE;
1074
 
1075
+ // 3.0.5 Live update
1076
+ $output['live_update']['in_memory'] = 0;
1077
+
1078
  return $output;
1079
  }
1080
 
1264
  private function sync_multisite_option( $option ) {
1265
  global $wpdb;
1266
  $blog_ids = $wpdb->get_col( "SELECT `blog_id` FROM `$wpdb->blogs`" );
1267
+ $ret = TRUE;
1268
 
1269
  foreach ( $blog_ids as $id ) {
1270
  switch_to_blog( $id );
1271
+ $ret &= update_option( IP_Geo_Block::OPTION_NAME, $option );
1272
  restore_current_blog();
1273
  }
1274
+
1275
+ return $ret;
1276
  }
1277
 
1278
  /**
1288
 
1289
  require_once IP_GEO_BLOCK_PATH . 'admin/includes/class-admin-ajax.php';
1290
 
1291
+ $settings = IP_Geo_Block::get_option();
1292
  $which = isset( $_POST['which'] ) ? $_POST['which'] : NULL;
1293
  switch ( isset( $_POST['cmd' ] ) ? $_POST['cmd' ] : NULL ) {
1294
  case 'download':
1340
  IP_Geo_Block_Admin_Ajax::export_logs( $which );
1341
  break;
1342
 
1343
+ case 'restore-logs':
1344
  // Get logs from MySQL DB
1345
  $res = IP_Geo_Block_Admin_Ajax::restore_logs( $which );
1346
  break;
1362
 
1363
  case 'gmap-error':
1364
  // Reset Google Maps API key
1365
+ if ( $settings['api_key']['GoogleMap'] === 'default' ) {
1366
+ $settings['api_key']['GoogleMap'] = NULL;
1367
+ update_option( IP_Geo_Block::OPTION_NAME, $settings );
 
1368
  $res = array(
1369
  'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
1370
  'tab' => 'tab=2'
1373
  break;
1374
 
1375
  case 'show-info':
1376
+ // Show system and debug information
1377
  $res = IP_Geo_Block_Admin_Ajax::get_wp_info();
1378
  break;
1379
 
1382
  $res = IP_Geo_Block_Util::get_registered_actions( TRUE );
1383
  break;
1384
 
1385
+ case 'restore-cache':
1386
+ // Restore cache from database and format for DataTables
1387
+ $res = IP_Geo_Block_Admin_Ajax::restore_cache( $which );
1388
+ break;
1389
+
1390
+ case 'bulk-action-remove':
1391
+ // Delete specified IP addresses from cache
1392
+ $res = IP_Geo_Block_Logs::delete_cache_entry( $which['IP'] );
1393
+ break;
1394
+
1395
+ case 'bulk-action-ip-white':
1396
+ case 'bulk-action-ip-black':
1397
+ case 'bulk-action-as-white':
1398
+ case 'bulk-action-as-black':
1399
+ // Bulk actions for registration of settings
1400
+ $src = ( FALSE !== strpos( $_POST['cmd'], '-ip-' ) ? 'IP' : 'AS' );
1401
+ $dst = ( FALSE !== strpos( $_POST['cmd'], '-white' ) ? 'white_list' : 'black_list' );
1402
+
1403
+ if ( empty( $which[ $src ] ) )
1404
+ break;
1405
+
1406
+ foreach ( array_unique( $which[ $src ] ) as $val ) {
1407
+ // replace anonymized IP address with CIDR (IPv4:256, IPv6:4096)
1408
+ $val = preg_replace(
1409
+ array( '!\.\*\*\*!', '!\*\*\*!', '![^\w\.:/]!' ),
1410
+ array( '.0/24', '000/116', '' ),
1411
+ $val
1412
+ );
1413
+ if ( FALSE === strpos( $settings['extra_ips'][ $dst ], $val ) )
1414
+ $settings['extra_ips'][ $dst ] .= "\n" . $val;
1415
+ }
1416
+
1417
+ if ( $settings['network_wide'] && is_plugin_active_for_network( IP_GEO_BLOCK_BASE ) )
1418
+ $this->sync_multisite_option( $settings );
1419
+ else
1420
+ update_option( IP_Geo_Block::OPTION_NAME, $settings );
1421
+
1422
+ $res = array(
1423
+ 'page' => 'options-general.php?page=' . IP_Geo_Block::PLUGIN_NAME,
1424
+ );
1425
+ break;
1426
+
1427
+ case 'restore-network':
1428
+ // Restore blocked per target in logs
1429
+ $res = IP_Geo_Block_Admin_Ajax::restore_network( $which, (int)$_POST['offset'], (int)$_POST['length'], FALSE );
1430
+ break;
1431
+
1432
+ case 'live-start':
1433
+ // Restore live log
1434
+ if ( ! is_wp_error( $res = IP_Geo_Block_Logs::catch_live_log() ) )
1435
+ $res = IP_Geo_Block_Admin_Ajax::restore_live_log( $which, $settings );
1436
+ else
1437
+ $res = array( 'error' => $res->get_error_message() );
1438
+ break;
1439
+
1440
+ case 'live-pause':
1441
+ // Pause live log
1442
+ if ( ! is_wp_error( $res = IP_Geo_Block_Logs::catch_live_log() ) )
1443
+ $res = array( 'data' => array() );
1444
+ else
1445
+ $res = array( 'error' => $res->get_error_message() );
1446
+ break;
1447
+
1448
+ case 'live-stop':
1449
+ // Stop live log
1450
+ if ( ! is_wp_error( $res = IP_Geo_Block_Logs::release_live_log() ) )
1451
+ $res = array( 'data' => array() );
1452
+ else
1453
+ $res = array( 'error' => $res->get_error_message() );
1454
+ break;
1455
+
1456
+ case 'reset-live':
1457
+ // Reset data source of live log
1458
+ $res = IP_Geo_Block_Admin_Ajax::reset_live_log();
1459
+ break;
1460
+
1461
  case 'create-table':
1462
  case 'delete-table':
1463
  // Need to define `IP_GEO_BLOCK_DEBUG` to true
admin/css/admin-icons.css ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! IP Geo Block admin icons */
2
+ @font-face {
3
+ font-family: 'icomoon';
4
+ src: url('fonts/icomoon.eot?9y580b');
5
+ src: url('fonts/icomoon.eot?9y580b#iefix') format('embedded-opentype'),
6
+ url('fonts/icomoon.ttf?9y580b') format('truetype'),
7
+ url('fonts/icomoon.woff?9y580b') format('woff'),
8
+ url('fonts/icomoon.svg?9y580b#icomoon') format('svg');
9
+ font-weight: normal;
10
+ font-style: normal;
11
+ }
12
+
13
+ [class^="ip-geo-block-icon-"], [class*=" ip-geo-block-icon-"] {
14
+ /* use !important to prevent issues with browser extensions that change fonts */
15
+ font-family: 'icomoon' !important;
16
+ speak: none;
17
+ font-style: normal;
18
+ font-weight: normal;
19
+ font-variant: normal;
20
+ text-transform: none;
21
+ line-height: 1;
22
+ /* Better Font Rendering =========== */
23
+ -webkit-font-smoothing: antialiased;
24
+ -moz-osx-font-smoothing: grayscale;
25
+ }
26
+
27
+ .ip-geo-block-icon-play3:before {
28
+ content: "\ea1c";
29
+ }
30
+ .ip-geo-block-icon-pause2:before {
31
+ content: "\ea1d";
32
+ }
33
+ .ip-geo-block-icon-stop2:before {
34
+ content: "\ea1e";
35
+ }
36
+
37
+ #toplevel_page_ip-geo-block .dashicons-admin-generic:before {
38
+ font-family: 'icomoon';
39
+ content: "\e9c9";
40
+ font-size: 18px;
41
+ }
admin/css/admin-icons.min.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /*! IP Geo Block admin icons */
2
+ @font-face{font-family:icomoon;src:url(fonts/icomoon.eot?9y580b);src:url(fonts/icomoon.eot?9y580b#iefix) format('embedded-opentype'),url(fonts/icomoon.ttf?9y580b) format('truetype'),url(fonts/icomoon.woff?9y580b) format('woff'),url(fonts/icomoon.svg?9y580b#icomoon) format('svg');font-weight:400;font-style:normal}[class*=" ip-geo-block-icon-"],[class^=ip-geo-block-icon-]{font-family:icomoon!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ip-geo-block-icon-play3:before{content:"\ea1c"}.ip-geo-block-icon-pause2:before{content:"\ea1d"}.ip-geo-block-icon-stop2:before{content:"\ea1e"}#toplevel_page_ip-geo-block .dashicons-admin-generic:before{font-family:icomoon;content:"\e9c9";font-size:18px}
admin/css/admin.css CHANGED
@@ -1,4 +1,8 @@
1
- /* This stylesheet is used to style the admin option form of the plugin. */
 
 
 
 
2
  dfn {
3
  cursor: help;
4
  border-bottom: 1px dotted #888;
@@ -88,13 +92,13 @@ fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
88
  }
89
  fieldset.ip-geo-block-field .ip-geo-block-dropup:before {
90
  border-left: 0.4em solid #555;
91
- left: 3px;
92
- top: 15%;
93
  }
94
  fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
95
  border-top: 0.4em solid #555;
96
- left: 0;
97
- top: 35%;
98
  }
99
  fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before {
100
  top: 0.25em;
@@ -102,13 +106,13 @@ fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before {
102
  fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before {
103
  top: 0.45em;
104
  }
105
- fieldset.ip-geo-block-field .form-table {
106
- margin: 0;
107
  width: 100%;
108
  }
109
  fieldset.ip-geo-block-field .ip-geo-block-desc {
110
  color: #666;
111
- font-size: 13px;
112
  /* font-style: italic;*/
113
  }
114
 
@@ -180,11 +184,11 @@ ul.ip-geo-block-list label {
180
  }
181
  }
182
 
183
- .ip-geo-block-loading {
 
184
  background-size: 16px 16px;
185
  background-position: center center;
186
  background-repeat: no-repeat;
187
- background-image: url(data:image/gif;base64,R0lGODlhEAAQAPIGAAAAAMLCwkJCQpKSkmJiYoKCgv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAGACwAAAAAEAAQAAADM2i63P4wyklrC0IEKgAQnAdOmGYFBLExwboQWcG2rlHEwTDQLUsUOd2mBxkUCgNKa+dIAAAh+QQJCgAGACwAAAIACgAOAAADLWgWIqHQCABEVLPe1R4MBOFFRFNsRUNsYDFewTC8iixvQ1EMyxjEvyBLODQkAAAh+QQJCgAGACwAAAAACgAOAAADLWi6IRJrCQCECoU0ag1xxeBARuEQ0UUU5DUM7fK+qTEUYR0EcM3Ev51uB7wAEwAh+QQJCgAGACwAAAAADgAKAAADLWi6URQrLiJEkSaM0eqrkLFtAVEEAgAIylAUQ5SuSqCFNZjhWG3zmB8wOJQkAAAh+QQJCgAGACwCAAAADgAKAAADK2hqMRMrLuekCnCU8gqBDCZ2glBcYkSUxIJJgQdaUVDOtAAAAr3oPN/llgAAIfkECQoABgAsBgAAAAoADgAAAytoEdauiz0Yx5BQFTvN2EMXWNgUFETZFIJQdERLiGgZtKohAIDQ7T0RrpEAACH5BAkKAAYALAYAAgAKAA4AAAMqaKoR+609Fie1K4zhZiibNRSg1XAQUXQPIQgE835voQgAIARqh+ummSUBACH5BAUKAAYALAIABgAOAAoAAAMsaLpsES2+F9mEddEgBFbBMGACAAiMOCrlGRBFWBQD2L0dYYjfUuQZEKynSAAAOw==);
188
  height: 16px;
189
  width: 16px;
190
  margin-left: 1em;
@@ -192,6 +196,9 @@ ul.ip-geo-block-list label {
192
  display: inline-block;
193
  vertical-align: middle;
194
  }
 
 
 
195
 
196
  .ip-geo-block-border {
197
  border-top: inherit;
@@ -272,140 +279,6 @@ table.ip-geo-block-table td:first-child {
272
  }
273
  }
274
 
275
- /* for footable */
276
- #ip-geo-block-4 #ip-geo-block-section-1 .panel-body,
277
- #ip-geo-block-4 #ip-geo-block-section-2 .panel-body,
278
- #ip-geo-block-4 #ip-geo-block-section-3 .panel-body,
279
- #ip-geo-block-4 #ip-geo-block-section-4 .panel-body,
280
- #ip-geo-block-4 #ip-geo-block-section-5 .panel-body {
281
- padding: 0;
282
- display: table-cell;
283
- /* border-collapse: collapse; *//* Bug of IE10, IE11 */
284
- }
285
- .ip-geo-block-log {
286
- width: 100% !important;
287
- margin: 0.5em 0;
288
- }
289
- .ip-geo-block-log * {
290
- font-size: 13px !important;
291
- line-height: 1.5em;
292
- vertical-align: middle;
293
- }
294
- .ip-geo-block-log .pagination ul {
295
- border-radius: 4px;
296
- display: inline-block;
297
- margin: 0.5em 0 0 0;
298
- padding: 0;
299
- }
300
- .ip-geo-block-log .pagination ul > li {
301
- display: inline;
302
- }
303
- .ip-geo-block-log .pagination ul > li:first-child > a,
304
- .ip-geo-block-log .pagination ul > li:first-child > span {
305
- border-bottom-left-radius: 4px;
306
- border-left-width: 1px;
307
- border-top-left-radius: 4px;
308
- }
309
- .ip-geo-block-log .pagination ul > li:last-child > a,
310
- .ip-geo-block-log .pagination ul > li:last-child > span {
311
- border-bottom-right-radius: 4px;
312
- border-top-right-radius: 4px;
313
- }
314
- .ip-geo-block-log .pagination ul > .disabled > span,
315
- .ip-geo-block-log .pagination ul > .disabled > a,
316
- .ip-geo-block-log .pagination ul > .disabled > a:hover,
317
- .ip-geo-block-log .pagination ul > .disabled > a:focus {
318
- background-color: transparent;
319
- color: #999;
320
- cursor: default;
321
- }
322
- .ip-geo-block-log .pagination ul > li > a,
323
- .ip-geo-block-log .pagination ul > li > span {
324
- border-color: #ddd;
325
- border-image: none;
326
- border-style: solid;
327
- border-width: 1px 1px 1px 0;
328
- float: left;
329
- line-height: 20px;
330
- padding: 4px;
331
- width: 20px;
332
- text-decoration: none;
333
- }
334
- .ip-geo-block-log .pagination ul > .active > a,
335
- .ip-geo-block-log .pagination ul > .active > span {
336
- color: #999;
337
- cursor: default;
338
- }
339
- .ip-geo-block-log .pagination ul > li > a:hover,
340
- .ip-geo-block-log .pagination ul > li > a:focus,
341
- .ip-geo-block-log .pagination ul > .active > a,
342
- .ip-geo-block-log .pagination ul > .active > span {
343
- background-color: #f7f7f7;
344
- }
345
- .ip-geo-block-log .pagination-centered {
346
- text-align: center;
347
- }
348
- .ip-geo-block-log.breakpoint > tbody > tr > td > span.footable-toggle {
349
- font-size: 60% !important;
350
- position: relative;
351
- top: -1px;
352
- left: 2px;
353
- }
354
- .ip-geo-block-log > thead > tr > th,
355
- .ip-geo-block-log > tbody > tr > td {
356
- padding: 4px 0;
357
- word-wrap: break-word;
358
- width: 20%;
359
- }
360
- .ip-geo-block-log > thead > tr > th:first-child,
361
- .ip-geo-block-log > tbody > tr > td:first-child {
362
- width: 25%;
363
- }
364
- .ip-geo-block-log > thead > tr > th:first-child + th,
365
- .ip-geo-block-log > tbody > tr > td:first-child + td {
366
- width: 35%;
367
- }
368
- .ip-geo-block-log > thead > tr > th:nth-child(5),
369
- .ip-geo-block-log > tbody > tr > td:nth-child(5),
370
- .ip-geo-block-log > thead > tr > th:nth-child(5) + th,
371
- .ip-geo-block-log > tbody > tr > td:nth-child(5) + td {
372
- width: 60%;
373
- text-align: left;
374
- }
375
- @media screen and (min-width: 1024px) {
376
- .ip-geo-block-log > thead > tr > th:nth-child(3),
377
- .ip-geo-block-log > tbody > tr > td:nth-child(3),
378
- .ip-geo-block-log > thead > tr > th:nth-child(3) + th,
379
- .ip-geo-block-log > tbody > tr > td:nth-child(3) + td {
380
- width: 10%;
381
- }
382
- }
383
- .ip-geo-block-log > thead > tr > th > span.footable-sort-indicator {
384
- color: #888;
385
- }
386
- .ip-geo-block-log > tbody > tr > td {
387
- text-align: center;
388
- }
389
- .ip-geo-block-log > tbody > tr > td:first-child {
390
- text-align: left;
391
- padding-left: 0.5em;
392
- }
393
- .ip-geo-block-log .footable-row-detail-row,
394
- .ip-geo-block-log .footable-row-detail-name,
395
- .ip-geo-block-log .footable-row-detail-value {
396
- display: block;
397
- }
398
- .ip-geo-block-log .footable-row-detail-value {
399
- padding: 0 1em 4px 1em;
400
- white-space: normal;
401
- word-wrap: break-word;
402
- word-break: break-all;
403
- }
404
- input#ip_geo_block_settings_filter_logs {
405
- width: 16em;
406
- padding-top: 3px;
407
- }
408
-
409
  /* Scan the country code */
410
  #ip-geo-block-scan-code {
411
  vertical-align: middle;
@@ -459,7 +332,7 @@ input#ip_geo_block_settings_filter_logs {
459
  }
460
 
461
  span.ip-geo-block-title-link {
462
- font-size: 13px;
463
  }
464
  /*span.ip-geo-block-title-link a {
465
  box-shadow: none;
@@ -468,7 +341,7 @@ span.ip-geo-block-title-link {
468
  dfn ~ .ip-geo-block-cycle,
469
  dfn ~ .ip-geo-block-lock,
470
  dfn ~ .ip-geo-block-unlock {
471
- margin-left: 0.75em;
472
  }
473
  .ip-geo-block-cycle,
474
  .ip-geo-block-lock,
@@ -505,6 +378,9 @@ dfn ~ .ip-geo-block-unlock {
505
  .ip-geo-block-unlock span {
506
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC);
507
  }
 
 
 
508
 
509
  /* https://developer.wordpress.org/resource/dashicons/ for WordPress 3.8
510
  .ip-geo-block-cycle span:before {
@@ -524,9 +400,13 @@ dfn ~ .ip-geo-block-unlock {
524
  margin:0;
525
  text-align:right;
526
  }
 
 
 
 
527
 
528
- /* embeded data for multisite */
529
- .ip-geo-block-multisite {
530
  margin-bottom: 1em;
531
  }
532
 
@@ -543,14 +423,443 @@ ol.ip-geo-block-top-list li code {
543
  background: none;
544
  }
545
 
546
- /* icon for top level menu */
547
- #toplevel_page_ip-geo-block .wp-menu-image img {
548
- height: 18px;
549
- width: 18px;
550
  }
551
 
552
  /* action for admin post */
553
  .ip-geo-block-admin-post {
554
  color: #c43322;
555
  margin-left: 0.25em;
556
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Project: WordPress IP Geo Block
3
+ * Copyright (c) 2015-2017 tokkonopapa (tokkonopapa@yahoo.com)
4
+ * This software is released under the MIT License.
5
+ */
6
  dfn {
7
  cursor: help;
8
  border-bottom: 1px dotted #888;
92
  }
93
  fieldset.ip-geo-block-field .ip-geo-block-dropup:before {
94
  border-left: 0.4em solid #555;
95
+ left: 2px;
96
+ top: 18%;
97
  }
98
  fieldset.ip-geo-block-field .ip-geo-block-dropdown:before {
99
  border-top: 0.4em solid #555;
100
+ left: -2px;
101
+ top: 38%;
102
  }
103
  fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before {
104
  top: 0.25em;
106
  fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before {
107
  top: 0.45em;
108
  }
109
+ fieldset.ip-geo-block-field table.form-table {
110
+ margin: 0 0 0.5em;
111
  width: 100%;
112
  }
113
  fieldset.ip-geo-block-field .ip-geo-block-desc {
114
  color: #666;
115
+ font-size: 13px !important;
116
  /* font-style: italic;*/
117
  }
118
 
184
  }
185
  }
186
 
187
+ .ip-geo-block-loading,
188
+ #ip-geo-block-live-loading {
189
  background-size: 16px 16px;
190
  background-position: center center;
191
  background-repeat: no-repeat;
 
192
  height: 16px;
193
  width: 16px;
194
  margin-left: 1em;
196
  display: inline-block;
197
  vertical-align: middle;
198
  }
199
+ .ip-geo-block-loading {
200
+ background-image: url(data:image/gif;base64,R0lGODlhEAAQAPIGAAAAAMLCwkJCQpKSkmJiYoKCgv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAGACwAAAAAEAAQAAADM2i63P4wyklrC0IEKgAQnAdOmGYFBLExwboQWcG2rlHEwTDQLUsUOd2mBxkUCgNKa+dIAAAh+QQJCgAGACwAAAIACgAOAAADLWgWIqHQCABEVLPe1R4MBOFFRFNsRUNsYDFewTC8iixvQ1EMyxjEvyBLODQkAAAh+QQJCgAGACwAAAAACgAOAAADLWi6IRJrCQCECoU0ag1xxeBARuEQ0UUU5DUM7fK+qTEUYR0EcM3Ev51uB7wAEwAh+QQJCgAGACwAAAAADgAKAAADLWi6URQrLiJEkSaM0eqrkLFtAVEEAgAIylAUQ5SuSqCFNZjhWG3zmB8wOJQkAAAh+QQJCgAGACwCAAAADgAKAAADK2hqMRMrLuekCnCU8gqBDCZ2glBcYkSUxIJJgQdaUVDOtAAAAr3oPN/llgAAIfkECQoABgAsBgAAAAoADgAAAytoEdauiz0Yx5BQFTvN2EMXWNgUFETZFIJQdERLiGgZtKohAIDQ7T0RrpEAACH5BAkKAAYALAYAAgAKAA4AAAMqaKoR+609Fie1K4zhZiibNRSg1XAQUXQPIQgE835voQgAIARqh+ummSUBACH5BAUKAAYALAIABgAOAAoAAAMsaLpsES2+F9mEddEgBFbBMGACAAiMOCrlGRBFWBQD2L0dYYjfUuQZEKynSAAAOw==);
201
+ }
202
 
203
  .ip-geo-block-border {
204
  border-top: inherit;
279
  }
280
  }
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  /* Scan the country code */
283
  #ip-geo-block-scan-code {
284
  vertical-align: middle;
332
  }
333
 
334
  span.ip-geo-block-title-link {
335
+ font-size: 13px !important;
336
  }
337
  /*span.ip-geo-block-title-link a {
338
  box-shadow: none;
341
  dfn ~ .ip-geo-block-cycle,
342
  dfn ~ .ip-geo-block-lock,
343
  dfn ~ .ip-geo-block-unlock {
344
+ margin-left: 0.6em;
345
  }
346
  .ip-geo-block-cycle,
347
  .ip-geo-block-lock,
378
  .ip-geo-block-unlock span {
379
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC);
380
  }
381
+ table.form-table th .ip-geo-block-cycle span {
382
+ vertical-align: text-bottom;
383
+ }
384
 
385
  /* https://developer.wordpress.org/resource/dashicons/ for WordPress 3.8
386
  .ip-geo-block-cycle span:before {
400
  margin:0;
401
  text-align:right;
402
  }
403
+ #ip-geo-block-open-new,
404
+ #ip-geo-block-live-update {
405
+ margin-left: 1em;
406
+ }
407
 
408
+ /* embeded data for network site list */
409
+ .ip-geo-block-network {
410
  margin-bottom: 1em;
411
  }
412
 
423
  background: none;
424
  }
425
 
426
+ /* icon for top level menu ... this must be included in every admin page */
427
+ #adminmenu #toplevel_page_ip-geo-block .wp-menu-image img {
428
+ height: 20px !important;
429
+ width: 20px !important;
430
  }
431
 
432
  /* action for admin post */
433
  .ip-geo-block-admin-post {
434
  color: #c43322;
435
  margin-left: 0.25em;
436
+ }
437
+
438
+ /* SVG in google chart */
439
+ svg a > text {
440
+ fill: #0073aa;
441
+ text-decoration: underline;
442
+ }
443
+ svg a:hover > text {
444
+ fill: #0096dd;
445
+ }
446
+
447
+ /*------------------------------------------------------------
448
+ * multi column for Site List
449
+ * https://caniuse.com/#search=flexbox
450
+ *------------------------------------------------------------*/
451
+ .ip-geo-block-container {
452
+ margin: 0 auto;
453
+ padding: 0 1em;
454
+ position: relative;
455
+ width: 100%;
456
+ }
457
+ .ip-geo-block-row {
458
+ display: flex;
459
+ flex-direction: column;
460
+ align-items: flex-start;
461
+ align-items: stretch; /* baseline */
462
+ padding: 0;
463
+ width: 100%;
464
+ }
465
+ .ip-geo-block-row .ip-geo-block-column {
466
+ display: block;
467
+ flex: 1 1 auto;
468
+ align-self: flex-start;
469
+ margin-left: 0;
470
+ max-width: 100%;
471
+ width: 100%;
472
+ }
473
+ .ip-geo-block-row .ip-geo-block-column.column-20 {
474
+ flex: 0 0 20%;
475
+ max-width: 20%;
476
+ }
477
+ .ip-geo-block-row .ip-geo-block-column.column-25 {
478
+ flex: 0 0 25%;
479
+ max-width: 25%;
480
+ }
481
+ .ip-geo-block-row .ip-geo-block-column.column-33 {
482
+ flex: 0 0 33.3333%;
483
+ max-width: 33.3333%;
484
+ }
485
+ .ip-geo-block-row .ip-geo-block-column.column-50 {
486
+ flex: 0 0 50%;
487
+ max-width: 50%;
488
+ }
489
+ @media (min-width: 40rem) {
490
+ .ip-geo-block-row {
491
+ flex-direction: row;
492
+ margin-left: -2em;
493
+ width: calc(100% + 2em);
494
+ }
495
+ .ip-geo-block-row .ip-geo-block-column {
496
+ margin-bottom: inherit;
497
+ padding: 0 1em;
498
+ }
499
+ }
500
+
501
+ /*------------------------------------------------------------
502
+ * Customizing based on jquery.dataTables.css
503
+ *------------------------------------------------------------*/
504
+ table.dataTable {
505
+ clear: none !important;
506
+ }
507
+ table.dataTable th,
508
+ table.dataTable td {
509
+ text-align: right;
510
+ }
511
+ table.dataTable th:nth-child(n+2),
512
+ table.dataTable td:nth-child(n+2) {
513
+ padding-left: 0 !important;
514
+ }
515
+ table.dataTable th {
516
+ white-space: nowrap;
517
+ }
518
+ table.dataTable > thead > tr {
519
+ line-height: 1.8em;
520
+ }
521
+ table.dataTable > tbody > tr {
522
+ cursor: pointer;
523
+ }
524
+ table.dataTable > thead > tr > th,
525
+ table.dataTable > thead > tr > td,
526
+ table.dataTable.no-footer {
527
+ border-bottom: 1px solid #ddd;
528
+ }
529
+ table.dataTable thead th,
530
+ table.dataTable thead td {
531
+ padding: 10px 16px;
532
+ }
533
+ /* country code */
534
+ #ip-geo-block-statistics-cache td:nth-child(3),
535
+ #ip-geo-block-validation-logs td:nth-child(4) {
536
+ min-width: 1.6em;
537
+ }
538
+
539
+ /* Scroll bar */
540
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
541
+ border-bottom: 1px solid #ddd;
542
+ }
543
+
544
+ /* Size of column */
545
+ table.dataTable.nowrap td,
546
+ table.dataTable > tbody > tr > td span {
547
+ white-space: normal !important;
548
+ word-wrap: break-word !important;
549
+ word-break: break-all !important;
550
+ }
551
+ table.dataTable > tbody > tr > td span {
552
+ display: inline-block;
553
+ }
554
+
555
+ /* Checkbox */
556
+ table.dataTable input[type="checkbox"] {
557
+ height: 16px;
558
+ width: 16px;
559
+ margin: 0;
560
+ }
561
+ table.dataTable > thead > tr > th:first-child,
562
+ table.dataTable > tbody > tr > td:first-child {
563
+ padding: 8px 4px 8px 18px;
564
+ text-align: left;
565
+ }
566
+
567
+ /* No data available in table */
568
+ table.dataTable > tbody > tr > td.dataTables_empty,
569
+ table.collapsed > tbody > tr > td.dataTables_empty:first-child::before {
570
+ border: none;
571
+ text-align: center;
572
+ }
573
+
574
+ /* Checkbox column */
575
+ table.dataTable thead > tr > th:first-child.sorting_asc {
576
+ background-image: none !important;
577
+ }
578
+ table.dataTable.display tbody tr.even > .sorting_1,
579
+ table.dataTable.display tbody tr.odd > .sorting_1,
580
+ table.dataTable.display tbody tr:hover > .sorting_1 {
581
+ background-color: inherit !important;
582
+ }
583
+
584
+ /* Collapsed */
585
+ table.dataTable.collapsed > tbody > tr > td:first-child {
586
+ padding: 8px 4px 8px 8px !important;
587
+ }
588
+ table.collapsed > tbody > tr > td:first-child::before,
589
+ table.collapsed > tbody > tr.parent > td:first-child::before {
590
+ content: '';
591
+ height: 0;
592
+ width: 0;
593
+ display: inline-block;
594
+ border-radius: 0;
595
+ border: 5px solid transparent;
596
+ box-shadow: none;
597
+ position: relative;
598
+ background-color: transparent;
599
+ }
600
+ table.collapsed > tbody > tr > td:first-child::before {
601
+ border-left: 5px solid #555;
602
+ top: 1px;
603
+ left: -2px;
604
+ }
605
+ table.collapsed > tbody > tr.parent > td:first-child::before {
606
+ border-top: 5px solid #555;
607
+ top: 4px;
608
+ left: -4px;
609
+ }
610
+ table.collapsed > tbody > tr.child > td:first-child::before {
611
+ border: none;
612
+ }
613
+ table.collapsed > tbody > tr.child > td.child > ul li {
614
+ border: none;
615
+ padding: 0;
616
+ margin: 0;
617
+ line-height: 1.8em;
618
+ }
619
+ table.collapsed > tbody > tr.child > td.child > ul li span.dtr-title,
620
+ table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
621
+ font-size: 13px !important;
622
+ display: block;
623
+ white-space: normal;
624
+ word-wrap: break-word;
625
+ word-break: break-all;
626
+ }
627
+ table.collapsed > tbody > tr.child > td.child > ul li span.dtr-data {
628
+ margin-left: 1.25em;
629
+ margin-right: 0.3em;
630
+ }
631
+
632
+ /* Pagenation */
633
+ .dataTables_wrapper .dataTables_paginate {
634
+ float: none;
635
+ text-align: center;
636
+ margin-bottom: 1em;
637
+ }
638
+ .dataTables_wrapper .dataTables_paginate span.ellipsis,
639
+ .dataTables_wrapper .dataTables_paginate a.paginate_button,
640
+ .dataTables_wrapper .dataTables_paginate a.paginate_button:hover,
641
+ .dataTables_wrapper .dataTables_paginate a.paginate_button:active,
642
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
643
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
644
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,
645
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
646
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
647
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
648
+ min-width: 2em;
649
+ background: inherit;
650
+ border-color: #ddd;
651
+ border-radius: 0;
652
+ border-image: none;
653
+ border-style: solid;
654
+ border-width: 1px 1px 1px 0;
655
+ box-shadow: none;
656
+ margin: 0.5em 0 0 0;
657
+ padding: 0.25em 0;
658
+ display: inline-block;
659
+ text-decoration: none;
660
+ }
661
+ .dataTables_wrapper .dataTables_paginate > a.paginate_button:first-child,
662
+ .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:first-child,
663
+ .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:first-child {
664
+ border-left-width: 1px;
665
+ border-bottom-left-radius: 4px;
666
+ border-top-left-radius: 4px;
667
+ }
668
+ .dataTables_wrapper .dataTables_paginate > a.paginate_button:last-child,
669
+ .dataTables_wrapper .dataTables_paginate:hover > a.paginate_button:last-child,
670
+ .dataTables_wrapper .dataTables_paginate:active > a.paginate_button:last-child {
671
+ border-bottom-right-radius: 4px;
672
+ border-top-right-radius: 4px;
673
+ }
674
+ .dataTables_wrapper .dataTables_paginate a.paginate_button {
675
+ color: #0073aa !important;
676
+ }
677
+ .dataTables_wrapper .dataTables_paginate a.paginate_button:hover {
678
+ color: #0096dd !important;
679
+ background-color: #fff;
680
+ }
681
+ .dataTables_wrapper .dataTables_paginate span.ellipsis,
682
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,
683
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,
684
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active {
685
+ cursor: default;
686
+ color: #999 !important;
687
+ background-color: transparent;
688
+ }
689
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current,
690
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,
691
+ .dataTables_wrapper .dataTables_paginate a.paginate_button.current:active {
692
+ cursor: default;
693
+ color: #444 !important;
694
+ background-color: #fff !important;
695
+ }
696
+
697
+ /* Alignment of table */
698
+ #ip-geo-block-1 #ip-geo-block-section-2 .panel-body,
699
+ #ip-geo-block-4 #ip-geo-block-section-0 .panel-body {
700
+ padding: 0;
701
+ }
702
+ #ip-geo-block-1 #ip-geo-block-section-2 table.form-table,
703
+ #ip-geo-block-4 #ip-geo-block-section-0 table.form-table {
704
+ margin-left: 1em;
705
+ max-width: 95%;
706
+ }
707
+
708
+ /* Select target / Period to extract */
709
+ ul#ip-geo-block-select-target,
710
+ ul#ip-geo-block-select-layout,
711
+ ul#ip-geo-block-select-duration {
712
+ margin: 0;
713
+ }
714
+ ul#ip-geo-block-select-target li,
715
+ ul#ip-geo-block-select-layout li,
716
+ ul#ip-geo-block-select-duration li {
717
+ float: left;
718
+ margin-right: 1.5em;
719
+ }
720
+ ul#ip-geo-block-select-target li label,
721
+ ul#ip-geo-block-select-duration li label {
722
+ cursor: pointer;
723
+ }
724
+
725
+ /* Filter */
726
+ input#ip_geo_block_settings_search_filter {
727
+ width: 16em;
728
+ padding-top: 3px;
729
+ }
730
+
731
+ /* Transition for new row */
732
+ table.dataTable.display tbody tr.ip-geo-block-passed {
733
+ background-color: #edf6ff !important;
734
+ }
735
+ table.dataTable.display tbody tr.ip-geo-block-blocked {
736
+ background-color: #ffefef !important;
737
+ }
738
+ .ip-geo-block-new-passed {
739
+ animation: ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running;
740
+ }
741
+ .ip-geo-block-new-blocked {
742
+ animation: ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running;
743
+ }
744
+ @keyframes ip-geo-block-flash-passed {
745
+ 0% { background-color: #ffd700; }
746
+ 100% { background-color: #edf6ff; }
747
+ }
748
+ @keyframes ip-geo-block-flash-blocked {
749
+ 0% { background-color: #ffd700; }
750
+ 100% { background-color: #ffefef; }
751
+ }
752
+
753
+ /* Mark.js */
754
+ mark {
755
+ padding: 0;
756
+ background: #ffd700; // Gold
757
+ }
758
+
759
+ /* Live update log */
760
+ ul#ip-geo-block-live-log {
761
+ margin: 0;
762
+ }
763
+ ul#ip-geo-block-live-log li {
764
+ float: left;
765
+ margin-right: 3em;
766
+ }
767
+ ul#ip-geo-block-live-log li:last-child {
768
+ margin-right: 0;
769
+ }
770
+ ul#ip-geo-block-live-log li input[type=radio] {
771
+ display: none;
772
+ }
773
+ ul#ip-geo-block-live-log li input[type=radio] + label {
774
+ display:inline-block;
775
+ margin:-2px;
776
+ padding: 4px 12px;
777
+ margin-bottom: 0;
778
+ font-size: 14px;
779
+ line-height: 20px;
780
+ color: #333;
781
+ text-align: center;
782
+ text-shadow: 0 1px 1px rgba(255,255,255,0.75);
783
+ vertical-align: middle;
784
+ cursor: pointer;
785
+ background-color: #f5f5f5;
786
+ background-image: -moz-linear-gradient(top,#fff,#e6e6e6);
787
+ background-image: -webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));
788
+ background-image: -webkit-linear-gradient(top,#fff,#e6e6e6);
789
+ background-image: -o-linear-gradient(top,#fff,#e6e6e6);
790
+ background-image: linear-gradient(to bottom,#fff,#e6e6e6);
791
+ background-repeat: repeat-x;
792
+ border: 1px solid #ccc;
793
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
794
+ border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
795
+ border-bottom-color: #b3b3b3;
796
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);
797
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
798
+ -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
799
+ -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
800
+ box-shadow: inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);
801
+ }
802
+ ul#ip-geo-block-live-log li input[type=radio]:checked + label {
803
+ background-image: none;
804
+ outline: 0;
805
+ -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
806
+ -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
807
+ box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
808
+ background-color: #e0e0e0;
809
+ }
810
+
811
+ /*----------------------------------------------------------------------
812
+ * Timer animation based on https://codepen.io/paulobrien/pen/joptI
813
+ *----------------------------------------------------------------------*/
814
+ .ip-geo-block-live-timer {
815
+ height: 1em;
816
+ width: 1em;
817
+ position: relative;
818
+ top: -0.1em;
819
+ margin: 0;
820
+ }
821
+ .ip-geo-block-live-timer:before {
822
+ content: "";
823
+ display: block;
824
+ height: 1em;
825
+ width: 1em;
826
+ background: radial-gradient(#0073aa, #72777c);
827
+ position: absolute;
828
+ border-radius: 50%;
829
+ top: 0;
830
+ left: 0;
831
+ }
832
+ .ip-geo-block-live-timer:after {
833
+ display: none
834
+ }
835
+ .ip-geo-block-live-timer > div {
836
+ position: absolute;
837
+ width: 1em;
838
+ height: 1em;
839
+ clip: rect(0, 1em, 1em, .5em);
840
+ }
841
+ .ip-geo-block-live-timer > div:before {
842
+ content: " ";
843
+ position: absolute;
844
+ width: 1em;
845
+ height: 1em;
846
+ border-radius: .5em;
847
+ clip: rect(0, .5em, 1em, 0);
848
+ background-color: #f1f1f1;
849
+ transform: rotate(0deg);
850
+ }
851
+ .ip-geo-block-live-timer > div:first-child:before {
852
+ animation: 30s spin-timer linear forwards;
853
+ }
854
+ .ip-geo-block-live-timer > div:last-child {
855
+ transform: rotate(180deg);
856
+ }
857
+ .ip-geo-block-live-timer > div:last-child:before {
858
+ /* older webkit seems buggy with zero so use 0.00001 */
859
+ transform: rotate(0.00001deg);
860
+ animation: 30s spin-timer linear 30s forwards;
861
+ }
862
+ @keyframes spin-timer {
863
+ 0% {transform: rotate( 0deg);}
864
+ 100% {transform: rotate(180deg);}
865
+ }
admin/css/admin.min.css CHANGED
@@ -1,2 +1,6 @@
1
- /* This stylesheet is used to style the admin option form of the plugin. */
2
- #ip-geo-block-scan-code,.ip-geo-block-loading,.ip-geo-block-log *{vertical-align:middle}dfn{cursor:help;border-bottom:1px dotted #888}fieldset,legend{padding:0;margin:0;border:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}fieldset{min-width:0}legend{display:block;line-height:inherit;width:100%}.panel-body,label{display:inline-block}label{max-width:100%}.panel{border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);-moz-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);background:#f5f5f5}.panel-heading{float:left!important;background:#fff}.panel-default>.panel-heading{border-color:inherit}.panel-body{width:100%;padding:0 1em;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.panel-body:after,.panel-body:before{content:" ";display:table}.panel-body:after{clear:both}fieldset.ip-geo-block-field{margin:1em 0}fieldset.ip-geo-block-field h2,fieldset.ip-geo-block-field h3{padding:0;margin:0;font-size:14px!important}fieldset.ip-geo-block-field legend.panel-heading{padding:10px}fieldset.ip-geo-block-field .ip-geo-block-dropdown,fieldset.ip-geo-block-field .ip-geo-block-dropup{cursor:pointer;position:relative;padding-left:1em}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before,fieldset.ip-geo-block-field .ip-geo-block-dropup:before{content:'';height:0;width:0;border:.4em solid transparent;position:absolute}fieldset.ip-geo-block-field .ip-geo-block-dropup:before{border-left:.4em solid #555;left:3px;top:15%}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before{border-top:.4em solid #555;left:0;top:35%}fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before{top:.25em}fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before{top:.45em}fieldset.ip-geo-block-field .form-table{margin:0;width:100%}fieldset.ip-geo-block-field .ip-geo-block-desc{color:#666;font-size:13px}textarea.regular-text{width:25em}ul.ip-geo-block-settings-folding{margin:.5em 0}ul.ip-geo-block-settings-folding ul{margin-bottom:0}ul.ip-geo-block-settings-folding li:first-child{margin-top:.5em}.folding-disable{pointer-events:none;opacity:.5}.folding-inactive{opacity:.5;font-style:oblique!important}ul.ip-geo-block-float li{display:inline-block;width:18em}ul#ip-geo-block-actions dfn{border:none}ul#ip-geo-block-actions span.dashicons{font-size:14px}.ip-geo-block-checked{list-style-type:disc}.ip-geo-block-ip-addr{display:inline-block;padding-top:5px}.ip-geo-block-hide{display:none}.ip-geo-block-result,.ip-geo-block-sup,.ip-geo-block-title,ul.ip-geo-block-list label{display:inline-block}.ip-geo-block-sup{margin-left:.2em}ul.ip-geo-block-note{margin-top:1em;list-style:disc inside}ul.ip-geo-block-list{margin-top:.25em;margin-bottom:.25em}@media screen and (min-width:782px){ul.ip-geo-block-list .code{width:15em}}.ip-geo-block-loading{background-size:16px 16px;background-position:center center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAAQAPIGAAAAAMLCwkJCQpKSkmJiYoKCgv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAGACwAAAAAEAAQAAADM2i63P4wyklrC0IEKgAQnAdOmGYFBLExwboQWcG2rlHEwTDQLUsUOd2mBxkUCgNKa+dIAAAh+QQJCgAGACwAAAIACgAOAAADLWgWIqHQCABEVLPe1R4MBOFFRFNsRUNsYDFewTC8iixvQ1EMyxjEvyBLODQkAAAh+QQJCgAGACwAAAAACgAOAAADLWi6IRJrCQCECoU0ag1xxeBARuEQ0UUU5DUM7fK+qTEUYR0EcM3Ev51uB7wAEwAh+QQJCgAGACwAAAAADgAKAAADLWi6URQrLiJEkSaM0eqrkLFtAVEEAgAIylAUQ5SuSqCFNZjhWG3zmB8wOJQkAAAh+QQJCgAGACwCAAAADgAKAAADK2hqMRMrLuekCnCU8gqBDCZ2glBcYkSUxIJJgQdaUVDOtAAAAr3oPN/llgAAIfkECQoABgAsBgAAAAoADgAAAytoEdauiz0Yx5BQFTvN2EMXWNgUFETZFIJQdERLiGgZtKohAIDQ7T0RrpEAACH5BAkKAAYALAYAAgAKAA4AAAMqaKoR+609Fie1K4zhZiibNRSg1XAQUXQPIQgE835voQgAIARqh+ummSUBACH5BAUKAAYALAIABgAOAAoAAAMsaLpsES2+F9mEddEgBFbBMGACAAiMOCrlGRBFWBQD2L0dYYjfUuQZEKynSAAAOw==);height:16px;width:16px;margin-left:1em;margin-top:.2em;display:inline-block}.ip-geo-block-border{border-top:inherit}.ip-geo-block-notice{color:#dd3d36}.ip-geo-block-title{width:100px}.ip-geo-block-result{color:#2786C2}#ip-geo-block-map{height:400px;margin:1em auto}.gm-style-iw{width:18em;height:auto!important;height:100%;min-height:100%:}.gm-style-iw ul{margin:.1em}.gm-style-iw li{margin:.2em}ul.ip-geo-block-statistics-countries li{width:12em;float:left;text-align:right;padding:.2em}table.ip-geo-block-statistics-table{float:right}table.ip-geo-block-statistics-table td,table.ip-geo-block-statistics-table th{width:12em;margin:0;padding:.2em;text-align:right;line-height:1.5em;word-wrap:break-word}table.ip-geo-block-statistics-table tr:nth-child(even){background-color:#eee}table.ip-geo-block-table{margin:1em 0;white-space:normal;word-wrap:break-word;word-break:break-all}table.ip-geo-block-table td:first-child{min-width:4.3em}@media screen and (max-width:782px){#ip-geo-block-whois .panel-body{padding:0 .5em}}#ip-geo-block-4 #ip-geo-block-section-1 .panel-body,#ip-geo-block-4 #ip-geo-block-section-2 .panel-body,#ip-geo-block-4 #ip-geo-block-section-3 .panel-body,#ip-geo-block-4 #ip-geo-block-section-4 .panel-body,#ip-geo-block-4 #ip-geo-block-section-5 .panel-body{padding:0;display:table-cell}.ip-geo-block-log{width:100%!important;margin:.5em 0}.ip-geo-block-log *{font-size:13px!important;line-height:1.5em}.ip-geo-block-log .pagination ul{border-radius:4px;display:inline-block;margin:.5em 0 0;padding:0}.ip-geo-block-log .pagination ul>li{display:inline}.ip-geo-block-log .pagination ul>li:first-child>a,.ip-geo-block-log .pagination ul>li:first-child>span{border-bottom-left-radius:4px;border-left-width:1px;border-top-left-radius:4px}.ip-geo-block-log .pagination ul>li:last-child>a,.ip-geo-block-log .pagination ul>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.ip-geo-block-log .pagination ul>.disabled>a,.ip-geo-block-log .pagination ul>.disabled>a:focus,.ip-geo-block-log .pagination ul>.disabled>a:hover,.ip-geo-block-log .pagination ul>.disabled>span{background-color:transparent;color:#999;cursor:default}.ip-geo-block-log .pagination ul>li>a,.ip-geo-block-log .pagination ul>li>span{border-color:#ddd;border-image:none;border-style:solid;border-width:1px 1px 1px 0;float:left;line-height:20px;padding:4px;width:20px;text-decoration:none}.ip-geo-block-log .pagination ul>.active>a,.ip-geo-block-log .pagination ul>.active>span{color:#999;cursor:default}.ip-geo-block-log .pagination ul>.active>a,.ip-geo-block-log .pagination ul>.active>span,.ip-geo-block-log .pagination ul>li>a:focus,.ip-geo-block-log .pagination ul>li>a:hover{background-color:#f7f7f7}.ip-geo-block-log .pagination-centered{text-align:center}.ip-geo-block-log.breakpoint>tbody>tr>td>span.footable-toggle{font-size:60%!important;position:relative;top:-1px;left:2px}.ip-geo-block-log>tbody>tr>td,.ip-geo-block-log>thead>tr>th{padding:4px 0;word-wrap:break-word;width:20%}.ip-geo-block-log>tbody>tr>td:first-child,.ip-geo-block-log>thead>tr>th:first-child{width:25%}.ip-geo-block-log>tbody>tr>td:first-child+td,.ip-geo-block-log>thead>tr>th:first-child+th{width:35%}.ip-geo-block-log>tbody>tr>td:nth-child(5),.ip-geo-block-log>tbody>tr>td:nth-child(5)+td,.ip-geo-block-log>thead>tr>th:nth-child(5),.ip-geo-block-log>thead>tr>th:nth-child(5)+th{width:60%;text-align:left}@media screen and (min-width:1024px){.ip-geo-block-log>tbody>tr>td:nth-child(3),.ip-geo-block-log>tbody>tr>td:nth-child(3)+td,.ip-geo-block-log>thead>tr>th:nth-child(3),.ip-geo-block-log>thead>tr>th:nth-child(3)+th{width:10%}}.ip-geo-block-log>thead>tr>th>span.footable-sort-indicator{color:#888}.ip-geo-block-log>tbody>tr>td{text-align:center}.ip-geo-block-log>tbody>tr>td:first-child{text-align:left;padding-left:.5em}.ip-geo-block-log .footable-row-detail-name,.ip-geo-block-log .footable-row-detail-row,.ip-geo-block-log .footable-row-detail-value{display:block}.ip-geo-block-log .footable-row-detail-value{padding:0 1em 4px;white-space:normal;word-wrap:break-word;word-break:break-all}input#ip_geo_block_settings_filter_logs{width:16em;padding-top:3px}#ip-geo-block-code-list{display:none;margin-bottom:0}#ip-geo-block-chart-countries{height:200px}#ip-geo-block-chart-daily{height:240px}#ip_geo_block_settings_validation_mimetype+label{padding-top:.25em}#ip_geo_block_settings_validation_mimetype+label+ul,#ip_geo_block_settings_validation_plugins,#ip_geo_block_settings_validation_themes{margin-top:.7em}#ip_geo_block_settings_create_user{margin-bottom:.5em}#ip-geo-block-back-to-top a,#ip-geo-block-toggle-sections{box-shadow:none}#ip-geo-block-wp-info textarea{margin-top:.5em;overflow:auto;width:100%;word-wrap:normal;word-break:normal;white-space:pre}#ip-geo-block-preferred{color:#fff;background:#00838f!important;border-color:#00707a!important;text-shadow:none}#ip-geo-block-preferred:hover{background-color:#00919e!important;border-color:#00525a!important}span.ip-geo-block-title-link{font-size:13px}dfn~.ip-geo-block-cycle,dfn~.ip-geo-block-lock,dfn~.ip-geo-block-unlock{margin-left:.75em}.ip-geo-block-cycle,.ip-geo-block-lock,.ip-geo-block-unlock{cursor:pointer;box-shadow:none;text-decoration:none}.ip-geo-block-cycle:active,.ip-geo-block-lock:active,.ip-geo-block-unlock:active{position:relative;top:1px}.ip-geo-block-cycle span,.ip-geo-block-lock span,.ip-geo-block-unlock span{height:16px;width:16px;margin:0;border:none;display:inline-block;vertical-align:middle;background-size:16px 16px;background-position:center center;background-repeat:no-repeat}.ip-geo-block-cycle span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC)}.ip-geo-block-lock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==)}.ip-geo-block-unlock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC)}#ip-geo-block-back-to-top{margin:0;text-align:right}.ip-geo-block-multisite{margin-bottom:1em}ol.ip-geo-block-top-list{display:inline-table;list-style-position:outside;margin:0 2em .5em 1.75em}ol.ip-geo-block-top-list h4{margin:1em 0}ol.ip-geo-block-top-list li code{background:0 0}#toplevel_page_ip-geo-block .wp-menu-image img{height:18px;width:18px}.ip-geo-block-admin-post{color:#c43322;margin-left:.25em}
 
 
 
 
1
+ /*
2
+ Project: WordPress IP Geo Block
3
+ Copyright (c) 2015-2017 tokkonopapa (tokkonopapa@yahoo.com)
4
+ This software is released under the MIT License.
5
+ */
6
+ dfn{cursor:help;border-bottom:1px dotted #888}fieldset,legend{padding:0;margin:0;border:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}fieldset{min-width:0}legend{display:block;line-height:inherit;width:100%}.panel-body,label{display:inline-block}label{max-width:100%}.panel{border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.04);-moz-box-shadow:0 1px 1px rgba(0,0,0,.04);box-shadow:0 1px 1px rgba(0,0,0,.04);background:#f5f5f5}.panel-heading{float:left!important;background:#fff}.panel-default>.panel-heading{border-color:inherit}.panel-body{width:100%;padding:0 1em;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.panel-body:after,.panel-body:before{content:" ";display:table}.panel-body:after{clear:both}fieldset.ip-geo-block-field{margin:1em 0}fieldset.ip-geo-block-field h2,fieldset.ip-geo-block-field h3{padding:0;margin:0;font-size:14px!important}fieldset.ip-geo-block-field legend.panel-heading{padding:10px}fieldset.ip-geo-block-field .ip-geo-block-dropdown,fieldset.ip-geo-block-field .ip-geo-block-dropup{cursor:pointer;position:relative;padding-left:1em}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before,fieldset.ip-geo-block-field .ip-geo-block-dropup:before{content:'';height:0;width:0;border:.4em solid transparent;position:absolute}fieldset.ip-geo-block-field .ip-geo-block-dropup:before{border-left:.4em solid #555;left:2px;top:18%}fieldset.ip-geo-block-field .ip-geo-block-dropdown:before{border-top:.4em solid #555;left:-2px;top:38%}fieldset.ip-geo-block-field ul.ip-geo-block-dropup:before{top:.25em}fieldset.ip-geo-block-field ul.ip-geo-block-dropdown:before{top:.45em}fieldset.ip-geo-block-field table.form-table{margin:0 0 .5em;width:100%}fieldset.ip-geo-block-field .ip-geo-block-desc{color:#666;font-size:13px!important}textarea.regular-text{width:25em}ul.ip-geo-block-settings-folding{margin:.5em 0}ul.ip-geo-block-settings-folding ul{margin-bottom:0}ul.ip-geo-block-settings-folding li:first-child{margin-top:.5em}.folding-disable{pointer-events:none;opacity:.5}.folding-inactive{opacity:.5;font-style:oblique!important}ul.ip-geo-block-float li{display:inline-block;width:18em}ul#ip-geo-block-actions dfn{border:none}ul#ip-geo-block-actions span.dashicons{font-size:14px}.ip-geo-block-checked{list-style-type:disc}.ip-geo-block-ip-addr{display:inline-block;padding-top:5px}.ip-geo-block-hide{display:none}.ip-geo-block-result,.ip-geo-block-sup,.ip-geo-block-title,ul.ip-geo-block-list label{display:inline-block}.ip-geo-block-sup{margin-left:.2em}ul.ip-geo-block-note{margin-top:1em;list-style:disc inside}ul.ip-geo-block-list{margin-top:.25em;margin-bottom:.25em}@media screen and (min-width:782px){ul.ip-geo-block-list .code{width:15em}}#ip-geo-block-live-loading,.ip-geo-block-loading{background-size:16px 16px;background-position:center center;background-repeat:no-repeat;height:16px;width:16px;margin-left:1em;margin-top:.2em;display:inline-block;vertical-align:middle}.ip-geo-block-loading{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPIGAAAAAMLCwkJCQpKSkmJiYoKCgv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQJCgAGACwAAAAAEAAQAAADM2i63P4wyklrC0IEKgAQnAdOmGYFBLExwboQWcG2rlHEwTDQLUsUOd2mBxkUCgNKa+dIAAAh+QQJCgAGACwAAAIACgAOAAADLWgWIqHQCABEVLPe1R4MBOFFRFNsRUNsYDFewTC8iixvQ1EMyxjEvyBLODQkAAAh+QQJCgAGACwAAAAACgAOAAADLWi6IRJrCQCECoU0ag1xxeBARuEQ0UUU5DUM7fK+qTEUYR0EcM3Ev51uB7wAEwAh+QQJCgAGACwAAAAADgAKAAADLWi6URQrLiJEkSaM0eqrkLFtAVEEAgAIylAUQ5SuSqCFNZjhWG3zmB8wOJQkAAAh+QQJCgAGACwCAAAADgAKAAADK2hqMRMrLuekCnCU8gqBDCZ2glBcYkSUxIJJgQdaUVDOtAAAAr3oPN/llgAAIfkECQoABgAsBgAAAAoADgAAAytoEdauiz0Yx5BQFTvN2EMXWNgUFETZFIJQdERLiGgZtKohAIDQ7T0RrpEAACH5BAkKAAYALAYAAgAKAA4AAAMqaKoR+609Fie1K4zhZiibNRSg1XAQUXQPIQgE835voQgAIARqh+ummSUBACH5BAUKAAYALAIABgAOAAoAAAMsaLpsES2+F9mEddEgBFbBMGACAAiMOCrlGRBFWBQD2L0dYYjfUuQZEKynSAAAOw==)}.ip-geo-block-border{border-top:inherit}.ip-geo-block-notice{color:#dd3d36}.ip-geo-block-title{width:100px}.ip-geo-block-result{color:#2786C2}#ip-geo-block-map{height:400px;margin:1em auto}.gm-style-iw{width:18em;height:auto!important;height:100%;min-height:100%:}.gm-style-iw ul{margin:.1em}.gm-style-iw li{margin:.2em}ul.ip-geo-block-statistics-countries li{width:12em;float:left;text-align:right;padding:.2em}table.ip-geo-block-statistics-table{float:right}table.ip-geo-block-statistics-table td,table.ip-geo-block-statistics-table th{width:12em;margin:0;padding:.2em;text-align:right;line-height:1.5em;word-wrap:break-word}table.ip-geo-block-statistics-table tr:nth-child(even){background-color:#eee}table.ip-geo-block-table{margin:1em 0;white-space:normal;word-wrap:break-word;word-break:break-all}table.ip-geo-block-table td:first-child{min-width:4.3em}@media screen and (max-width:782px){#ip-geo-block-whois .panel-body{padding:0 .5em}}#ip-geo-block-scan-code{vertical-align:middle}#ip-geo-block-code-list{display:none;margin-bottom:0}#ip-geo-block-chart-countries{height:200px}#ip-geo-block-chart-daily{height:240px}#ip_geo_block_settings_validation_mimetype+label{padding-top:.25em}#ip_geo_block_settings_validation_mimetype+label+ul,#ip_geo_block_settings_validation_plugins,#ip_geo_block_settings_validation_themes{margin-top:.7em}#ip_geo_block_settings_create_user{margin-bottom:.5em}#ip-geo-block-back-to-top a,#ip-geo-block-toggle-sections{box-shadow:none}#ip-geo-block-wp-info textarea{margin-top:.5em;overflow:auto;width:100%;word-wrap:normal;word-break:normal;white-space:pre}#ip-geo-block-preferred{color:#fff;background:#00838f!important;border-color:#00707a!important;text-shadow:none}#ip-geo-block-preferred:hover{background-color:#00919e!important;border-color:#00525a!important}span.ip-geo-block-title-link{font-size:13px!important}dfn~.ip-geo-block-cycle,dfn~.ip-geo-block-lock,dfn~.ip-geo-block-unlock{margin-left:.6em}.ip-geo-block-cycle,.ip-geo-block-lock,.ip-geo-block-unlock{cursor:pointer;box-shadow:none;text-decoration:none}.ip-geo-block-cycle:active,.ip-geo-block-lock:active,.ip-geo-block-unlock:active{position:relative;top:1px}.ip-geo-block-cycle span,.ip-geo-block-lock span,.ip-geo-block-unlock span{height:16px;width:16px;margin:0;border:none;display:inline-block;vertical-align:middle;background-size:16px 16px;background-position:center center;background-repeat:no-repeat}.dataTables_wrapper.no-footer .dataTables_scrollBody,table.dataTable.no-footer,table.dataTable>thead>tr>td,table.dataTable>thead>tr>th{border-bottom:1px solid #ddd}.ip-geo-block-cycle span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAh1BMVEUAda2otLp+rsSHprWHr8IBd7EpfKRGhaNajqeUqrRymKuKoq5yo7prlKgAcqoVe6w8gqQmgq5Tj6wIdqsVdKIshrEMea1Uhp+Anqw0hawDdq4gfKhljqE7hqoLdKYbgbM4jLQygKUGeK8CdawQd6gVeKcad6NKkrSerrZAj7UAc6sAc6rc3NySrVGQAAAALXRSTlP//////////////////////////////////////////////////////////wCl7wv9AAACOklEQVR4Ae2W15rzKgxF9xTZzhTX9B7S/gN6/9ebYqzzGZsw/S7LV3FZgCSIwD/kQ8FVcBU8xatZUczy8luC/ABNOn0DSHEsvyZ4PgLatNCYR3efFxyhTQ8g+qQgJxgv2JefERzJXATRh4LHOUwAHD4S7OGEztRJaN86hAUxtaNWDUf/bRdDBbQMWVDAO8jn89WUhag1MeyCAh6hHofyrliLgZKggDMYgzF3eVAwFq0uCZq5KY0TezjIHDDzC0qqmkwe2ctGDOQVLMkgu+F3/rGXwb4xIPcJ6P3JgkM8wFjmfcFAWfeKQywaAz33BJVuHsUcAt09gVbuLDThAJkdR687ggLmf4gDJLIGV7BydtB8yn3u+fbtuj/LS7G9wZAd1AKK+yxJ1x+aBmibTtgCcEHGHsh0wdbOgNLek4L7lI5BigY8nWuZUQ3qGEXes9JzOKGJztPaGtLslu3lIXJirdxCWkASHGDTMqg7V1DKPplygDG61YJukLHjEErGSXqCSos6xNSOgzP3BDmsQBcchNwkoV8oiNnPA78zIefUgCdJeGIfE7LmFWXsFTCFdzTJ/RlfEMRiSGnFXXbkC7AIeqcKDu4ynseozeouKJiSEYBDwkJyIC1nRUjgblkNWp/e/1vXc2gjoAoLksYgjrrFMi0oDgjEEIDij1scBXMJSH6DAj6RNl7o8MkuLak8Co15/Pk+MRmT0xilQJV/sdWNKg2kTaeroudvNNsDjmejYjSL+e6v2/2r4Cp4BXNajr0H7hRfAAAAAElFTkSuQmCC)}.ip-geo-block-lock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3Ny3y9Zzq8dRmb7M1dlXnsIFdK0AcawAcqwphrYAcKvZ29wAb6oJd680jrqlw9MBcqxmo8MUfbJLl75eoMI7kbzX2ttqp8VSmL1YnL8NeK+Tu89DlL1ImMEOebBNmL4OkqMoAAAAAXRSTlMAQObYZgAAAPlJREFUeAG9kAWyhTAQBIPOsCzufv9TPnf4Ll0CSbpmxXwNy3Yc23rz2fV8kPA99433AIQIiGDTCD0lojiOQPXCDSFJIbF16CMWItkQMkF+inZzSLYhFKLl+a9UKTZaqJTZJYtarZuo40chrv9CqJTN+behVi+Cm7RdDgRld6AMgLxrE/dxBz0BEjwBEmD/uIsWPAOAF9A+CE56ufSryr8oqfOYcBbQJ8YkES7COkFOYzTypqCDOTDo2wljaEw4vp1APYyWKd8WMBozylvCpcvmXeHQ5fCegHia4s1FgZcIVeVFeFx1M4MvYG4eBHdYWufC+addBtf8E3vdjBNhWnVQqAAAAABJRU5ErkJggg==)}.ip-geo-block-unlock span{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAYFBMVEXc3NyzydRzq8dRmb7I09hYnsEFdK0AcawAcqzP1toqhrYAcKvZ29wAb6oMeK8zjbqrxtQBcazBz9Zko8MVfbLF0thMmL07kbtpp8WjwtJSmL1YnL+Tu89DlL1JmMEPebBFV++UAAAAAXRSTlMAQObYZgAAAONJREFUeAG9kAWChDAMAIMmJaTFXf7/ynXflvMbnE5j8DU8Pwh8D1yEUYxEGEchWFEJEjEflESBhTQSQm2MRpIotQhZTmgKgMIg5ZlFKBmrGg7UFXJpEQKW8qIKN7YeikJdBJI2BTtXwfyx0L3XoPphvBEliNU49OoxqEa6g4cTST/OYshvi3hV8+FxSNfluG3jqxG8C6h7gF6jU+AODnTsFGSCA5O4I8wpQDq7I5CUAKWQW+AZYOYtoQPoGDeECWDaioBmWQxeBduoWURso+5WpBdw7R4ENTVDcGE435tJwT+xB+vMEnZRNB0YAAAAAElFTkSuQmCC)}table.form-table th .ip-geo-block-cycle span{vertical-align:text-bottom}#ip-geo-block-back-to-top{margin:0;text-align:right}#ip-geo-block-live-update,#ip-geo-block-open-new{margin-left:1em}.ip-geo-block-network{margin-bottom:1em}ol.ip-geo-block-top-list{display:inline-table;list-style-position:outside;margin:0 2em .5em 1.75em}ol.ip-geo-block-top-list h4{margin:1em 0}ol.ip-geo-block-top-list li code{background:0 0}#adminmenu #toplevel_page_ip-geo-block .wp-menu-image img{height:20px!important;width:20px!important}.ip-geo-block-admin-post{color:#c43322;margin-left:.25em}svg a>text{fill:#0073aa;text-decoration:underline}svg a:hover>text{fill:#0096dd}.ip-geo-block-container{margin:0 auto;padding:0 1em;position:relative;width:100%}.ip-geo-block-row{display:flex;flex-direction:column;align-items:flex-start;align-items:stretch;padding:0;width:100%}.ip-geo-block-row .ip-geo-block-column{display:block;flex:1 1 auto;align-self:flex-start;margin-left:0;max-width:100%;width:100%}.ip-geo-block-row .ip-geo-block-column.column-20{flex:0 0 20%;max-width:20%}.ip-geo-block-row .ip-geo-block-column.column-25{flex:0 0 25%;max-width:25%}.ip-geo-block-row .ip-geo-block-column.column-33{flex:0 0 33.3333%;max-width:33.3333%}.ip-geo-block-row .ip-geo-block-column.column-50{flex:0 0 50%;max-width:50%}@media (min-width:40rem){.ip-geo-block-row{flex-direction:row;margin-left:-2em;width:calc(100% + 2em)}.ip-geo-block-row .ip-geo-block-column{margin-bottom:inherit;padding:0 1em}}table.dataTable{clear:none!important}table.dataTable td,table.dataTable th{text-align:right}table.dataTable td:nth-child(n+2),table.dataTable th:nth-child(n+2){padding-left:0!important}table.dataTable th{white-space:nowrap}table.dataTable>thead>tr{line-height:1.8em}table.dataTable>tbody>tr{cursor:pointer}table.dataTable thead td,table.dataTable thead th{padding:10px 16px}#ip-geo-block-statistics-cache td:nth-child(3),#ip-geo-block-validation-logs td:nth-child(4){min-width:1.6em}table.dataTable.nowrap td,table.dataTable>tbody>tr>td span{white-space:normal!important;word-wrap:break-word!important;word-break:break-all!important}table.dataTable>tbody>tr>td span{display:inline-block}table.dataTable input[type=checkbox]{height:16px;width:16px;margin:0}table.dataTable>tbody>tr>td:first-child,table.dataTable>thead>tr>th:first-child{padding:8px 4px 8px 18px;text-align:left}table.collapsed>tbody>tr>td.dataTables_empty:first-child::before,table.dataTable>tbody>tr>td.dataTables_empty{border:none;text-align:center}table.dataTable thead>tr>th:first-child.sorting_asc{background-image:none!important}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.display tbody tr:hover>.sorting_1{background-color:inherit!important}table.dataTable.collapsed>tbody>tr>td:first-child{padding:8px 4px 8px 8px!important}table.collapsed>tbody>tr.parent>td:first-child::before,table.collapsed>tbody>tr>td:first-child::before{content:'';height:0;width:0;display:inline-block;border-radius:0;border:5px solid transparent;box-shadow:none;position:relative;background-color:transparent}table.collapsed>tbody>tr>td:first-child::before{border-left:5px solid #555;top:1px;left:-2px}table.collapsed>tbody>tr.parent>td:first-child::before{border-top:5px solid #555;top:4px;left:-4px}table.collapsed>tbody>tr.child>td:first-child::before{border:none}table.collapsed>tbody>tr.child>td.child>ul li{border:none;padding:0;margin:0;line-height:1.8em}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data,table.collapsed>tbody>tr.child>td.child>ul li span.dtr-title{font-size:13px!important;display:block;white-space:normal;word-wrap:break-word;word-break:break-all}table.collapsed>tbody>tr.child>td.child>ul li span.dtr-data{margin-left:1.25em;margin-right:.3em}.dataTables_wrapper .dataTables_paginate{float:none;text-align:center;margin-bottom:1em}.dataTables_wrapper .dataTables_paginate a.paginate_button,.dataTables_wrapper .dataTables_paginate a.paginate_button.current,.dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,.dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover,.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate a.paginate_button:active,.dataTables_wrapper .dataTables_paginate a.paginate_button:hover,.dataTables_wrapper .dataTables_paginate span.ellipsis{min-width:2em;background:inherit;border-color:#ddd;border-radius:0;border-image:none;border-style:solid;border-width:1px 1px 1px 0;box-shadow:none;margin:.5em 0 0;padding:.25em 0;display:inline-block;text-decoration:none}#ip-geo-block-1 #ip-geo-block-section-2 .panel-body,#ip-geo-block-4 #ip-geo-block-section-0 .panel-body,mark{padding:0}.dataTables_wrapper .dataTables_paginate:active>a.paginate_button:first-child,.dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:first-child,.dataTables_wrapper .dataTables_paginate>a.paginate_button:first-child{border-left-width:1px;border-bottom-left-radius:4px;border-top-left-radius:4px}.dataTables_wrapper .dataTables_paginate:active>a.paginate_button:last-child,.dataTables_wrapper .dataTables_paginate:hover>a.paginate_button:last-child,.dataTables_wrapper .dataTables_paginate>a.paginate_button:last-child{border-bottom-right-radius:4px;border-top-right-radius:4px}.dataTables_wrapper .dataTables_paginate a.paginate_button{color:#0073aa!important}.dataTables_wrapper .dataTables_paginate a.paginate_button:hover{color:#0096dd!important;background-color:#fff}.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled,.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:active,.dataTables_wrapper .dataTables_paginate a.paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate span.ellipsis{cursor:default;color:#999!important;background-color:transparent}.dataTables_wrapper .dataTables_paginate a.paginate_button.current,.dataTables_wrapper .dataTables_paginate a.paginate_button.current:active,.dataTables_wrapper .dataTables_paginate a.paginate_button.current:hover{cursor:default;color:#444!important;background-color:#fff!important}#ip-geo-block-1 #ip-geo-block-section-2 table.form-table,#ip-geo-block-4 #ip-geo-block-section-0 table.form-table{margin-left:1em;max-width:95%}ul#ip-geo-block-live-log,ul#ip-geo-block-select-duration,ul#ip-geo-block-select-layout,ul#ip-geo-block-select-target{margin:0}ul#ip-geo-block-select-duration li,ul#ip-geo-block-select-layout li,ul#ip-geo-block-select-target li{float:left;margin-right:1.5em}ul#ip-geo-block-select-duration li label,ul#ip-geo-block-select-target li label{cursor:pointer}input#ip_geo_block_settings_search_filter{width:16em;padding-top:3px}table.dataTable.display tbody tr.ip-geo-block-passed{background-color:#edf6ff!important}table.dataTable.display tbody tr.ip-geo-block-blocked{background-color:#ffefef!important}.ip-geo-block-new-passed{animation:ip-geo-block-flash-passed 1s ease-out 0s 1 normal both running}.ip-geo-block-new-blocked{animation:ip-geo-block-flash-blocked 1s ease-out 0s 1 normal both running}@keyframes ip-geo-block-flash-passed{0%{background-color:gold}100%{background-color:#edf6ff}}@keyframes ip-geo-block-flash-blocked{0%{background-color:gold}100%{background-color:#ffefef}}mark{background:gold}ul#ip-geo-block-live-log li{float:left;margin-right:3em}ul#ip-geo-block-live-log li:last-child{margin-right:0}ul#ip-geo-block-live-log li input[type=radio]{display:none}ul#ip-geo-block-live-log li input[type=radio]+label{display:inline-block;margin:-2px -2px 0;padding:4px 12px;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);border-bottom-color:#b3b3b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}ul#ip-geo-block-live-log li input[type=radio]:checked+label{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05);background-color:#e0e0e0}.ip-geo-block-live-timer{height:1em;width:1em;position:relative;top:-.1em;margin:0}.ip-geo-block-live-timer:before{content:"";display:block;height:1em;width:1em;background:radial-gradient(#0073aa,#72777c);position:absolute;border-radius:50%;top:0;left:0}.ip-geo-block-live-timer:after{display:none}.ip-geo-block-live-timer>div{position:absolute;width:1em;height:1em;clip:rect(0,1em,1em,.5em)}.ip-geo-block-live-timer>div:before{content:" ";position:absolute;width:1em;height:1em;border-radius:.5em;clip:rect(0,.5em,1em,0);background-color:#f1f1f1;transform:rotate(0)}.ip-geo-block-live-timer>div:first-child:before{animation:30s spin-timer linear forwards}.ip-geo-block-live-timer>div:last-child{transform:rotate(180deg)}.ip-geo-block-live-timer>div:last-child:before{transform:rotate(.00001deg);animation:30s spin-timer linear 30s forwards}@keyframes spin-timer{0%{transform:rotate(0)}100%{transform:rotate(180deg)}}
admin/css/fonts/icomoon.eot ADDED
Binary file
admin/css/fonts/icomoon.svg ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Generated by IcoMoon</metadata>
5
+ <defs>
6
+ <font id="icomoon" horiz-adv-x="1024">
7
+ <font-face units-per-em="1024" ascent="960" descent="-64" />
8
+ <missing-glyph horiz-adv-x="1024" />
9
+ <glyph unicode="&#x20;" horiz-adv-x="512" d="" />
10
+ <glyph unicode="&#xe933;" glyph-name="folder-download" d="M576 704l-128 128h-448v-832h1024v704h-448zM512 96l-224 224h160v256h128v-256h160l-224-224z" />
11
+ <glyph unicode="&#xe948;" glyph-name="location2" d="M512 960c-176.732 0-320-143.268-320-320 0-320 320-704 320-704s320 384 320 704c0 176.732-143.27 320-320 320zM512 444c-108.248 0-196 87.752-196 196s87.752 196 196 196 196-87.752 196-196-87.752-196-196-196zM388 640c0 68.483 55.517 124 124 124s124-55.517 124-124c0-68.483-55.517-124-124-124s-124 55.517-124 124z" />
12
+ <glyph unicode="&#xe94b;" glyph-name="map" d="M0 768l320 128v-768l-320-128zM384 928l320-192v-736l-320 160zM768 736l256 192v-768l-256-192z" />
13
+ <glyph unicode="&#xe964;" glyph-name="database" d="M512 960c-282.77 0-512-71.634-512-160v-128c0-88.366 229.23-160 512-160s512 71.634 512 160v128c0 88.366-229.23 160-512 160zM512 416c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160zM512 128c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160z" />
14
+ <glyph unicode="&#xe97b;" glyph-name="spinner2" d="M1024 448c-1.278 66.862-15.784 133.516-42.576 194.462-26.704 61-65.462 116.258-113.042 161.92-47.552 45.696-103.944 81.82-164.984 105.652-61.004 23.924-126.596 35.352-191.398 33.966-64.81-1.282-129.332-15.374-188.334-41.356-59.048-25.896-112.542-63.47-156.734-109.576-44.224-46.082-79.16-100.708-102.186-159.798-23.114-59.062-34.128-122.52-32.746-185.27 1.286-62.76 14.964-125.148 40.134-182.206 25.088-57.1 61.476-108.828 106.11-151.548 44.61-42.754 97.472-76.504 154.614-98.72 57.118-22.304 118.446-32.902 179.142-31.526 60.708 1.29 120.962 14.554 176.076 38.914 55.15 24.282 105.116 59.48 146.366 102.644 41.282 43.14 73.844 94.236 95.254 149.43 13.034 33.458 21.88 68.4 26.542 103.798 1.246-0.072 2.498-0.12 3.762-0.12 35.346 0 64 28.652 64 64 0 1.796-0.094 3.572-0.238 5.332h0.238zM922.306 278.052c-23.472-53.202-57.484-101.4-99.178-141.18-41.67-39.81-91-71.186-144.244-91.79-53.228-20.678-110.29-30.452-166.884-29.082-56.604 1.298-112.596 13.736-163.82 36.474-51.25 22.666-97.684 55.49-135.994 95.712-38.338 40.198-68.528 87.764-88.322 139.058-19.87 51.284-29.228 106.214-27.864 160.756 1.302 54.552 13.328 108.412 35.254 157.69 21.858 49.3 53.498 93.97 92.246 130.81 38.73 36.868 84.53 65.87 133.874 84.856 49.338 19.060 102.136 28.006 154.626 26.644 52.5-1.306 104.228-12.918 151.562-34.034 47.352-21.050 90.256-51.502 125.624-88.782 35.396-37.258 63.21-81.294 81.39-128.688 18.248-47.392 26.782-98.058 25.424-148.496h0.238c-0.144-1.76-0.238-3.536-0.238-5.332 0-33.012 24.992-60.174 57.086-63.624-6.224-34.822-16.53-68.818-30.78-100.992z" />
15
+ <glyph unicode="&#xe985;" glyph-name="binoculars" d="M64 960h384v-64h-384zM576 960h384v-64h-384zM952 640h-56v256h-256v-256h-256v256h-256v-256h-56c-39.6 0-72-32.4-72-72v-560c0-39.6 32.4-72 72-72h304c39.6 0 72 32.4 72 72v376h128v-376c0-39.6 32.4-72 72-72h304c39.6 0 72 32.4 72 72v560c0 39.6-32.4 72-72 72zM348 0h-248c-19.8 0-36 14.4-36 32s16.2 32 36 32h248c19.8 0 36-14.4 36-32s-16.2-32-36-32zM544 448h-64c-17.6 0-32 14.4-32 32s14.4 32 32 32h64c17.6 0 32-14.4 32-32s-14.4-32-32-32zM924 0h-248c-19.8 0-36 14.4-36 32s16.2 32 36 32h248c19.8 0 36-14.4 36-32s-16.2-32-36-32z" />
16
+ <glyph unicode="&#xe986;" glyph-name="search" d="M992.262 88.604l-242.552 206.294c-25.074 22.566-51.89 32.926-73.552 31.926 57.256 67.068 91.842 154.078 91.842 249.176 0 212.078-171.922 384-384 384-212.076 0-384-171.922-384-384s171.922-384 384-384c95.098 0 182.108 34.586 249.176 91.844-1-21.662 9.36-48.478 31.926-73.552l206.294-242.552c35.322-39.246 93.022-42.554 128.22-7.356s31.892 92.898-7.354 128.22zM384 320c-141.384 0-256 114.616-256 256s114.616 256 256 256 256-114.616 256-256-114.614-256-256-256z" />
17
+ <glyph unicode="&#xe98d;" glyph-name="key" d="M704 960c-176.73 0-320-143.268-320-320 0-20.026 1.858-39.616 5.376-58.624l-389.376-389.376v-192c0-35.346 28.654-64 64-64h64v64h128v128h128v128h128l83.042 83.042c34.010-12.316 70.696-19.042 108.958-19.042 176.73 0 320 143.268 320 320s-143.27 320-320 320zM799.874 639.874c-53.020 0-96 42.98-96 96s42.98 96 96 96 96-42.98 96-96-42.98-96-96-96z" />
18
+ <glyph unicode="&#xe98f;" glyph-name="lock" d="M592 512h-16v192c0 105.87-86.13 192-192 192h-128c-105.87 0-192-86.13-192-192v-192h-16c-26.4 0-48-21.6-48-48v-480c0-26.4 21.6-48 48-48h544c26.4 0 48 21.6 48 48v480c0 26.4-21.6 48-48 48zM192 704c0 35.29 28.71 64 64 64h128c35.29 0 64-28.71 64-64v-192h-256v192z" />
19
+ <glyph unicode="&#xe990;" glyph-name="unlocked" d="M768 896c105.87 0 192-86.13 192-192v-192h-128v192c0 35.29-28.71 64-64 64h-128c-35.29 0-64-28.71-64-64v-192h16c26.4 0 48-21.6 48-48v-480c0-26.4-21.6-48-48-48h-544c-26.4 0-48 21.6-48 48v480c0 26.4 21.6 48 48 48h400v192c0 105.87 86.13 192 192 192h128z" />
20
+ <glyph unicode="&#xe995;" glyph-name="cogs" d="M363.722 237.948l41.298 57.816-45.254 45.256-57.818-41.296c-10.722 5.994-22.204 10.774-34.266 14.192l-11.682 70.084h-64l-11.68-70.086c-12.062-3.418-23.544-8.198-34.266-14.192l-57.818 41.298-45.256-45.256 41.298-57.816c-5.994-10.72-10.774-22.206-14.192-34.266l-70.086-11.682v-64l70.086-11.682c3.418-12.060 8.198-23.544 14.192-34.266l-41.298-57.816 45.254-45.256 57.818 41.296c10.722-5.994 22.204-10.774 34.266-14.192l11.682-70.084h64l11.68 70.086c12.062 3.418 23.544 8.198 34.266 14.192l57.818-41.296 45.254 45.256-41.298 57.816c5.994 10.72 10.774 22.206 14.192 34.266l70.088 11.68v64l-70.086 11.682c-3.418 12.060-8.198 23.544-14.192 34.266zM224 96c-35.348 0-64 28.654-64 64s28.652 64 64 64 64-28.654 64-64-28.652-64-64-64zM1024 576v64l-67.382 12.25c-1.242 8.046-2.832 15.978-4.724 23.79l57.558 37.1-24.492 59.128-66.944-14.468c-4.214 6.91-8.726 13.62-13.492 20.13l39.006 56.342-45.256 45.254-56.342-39.006c-6.512 4.766-13.22 9.276-20.13 13.494l14.468 66.944-59.128 24.494-37.1-57.558c-7.812 1.892-15.744 3.482-23.79 4.724l-12.252 67.382h-64l-12.252-67.382c-8.046-1.242-15.976-2.832-23.79-4.724l-37.098 57.558-59.128-24.492 14.468-66.944c-6.91-4.216-13.62-8.728-20.13-13.494l-56.342 39.006-45.254-45.254 39.006-56.342c-4.766-6.51-9.278-13.22-13.494-20.13l-66.944 14.468-24.492-59.128 57.558-37.1c-1.892-7.812-3.482-15.742-4.724-23.79l-67.384-12.252v-64l67.382-12.25c1.242-8.046 2.832-15.978 4.724-23.79l-57.558-37.1 24.492-59.128 66.944 14.468c4.216-6.91 8.728-13.618 13.494-20.13l-39.006-56.342 45.254-45.256 56.342 39.006c6.51-4.766 13.22-9.276 20.13-13.492l-14.468-66.944 59.128-24.492 37.102 57.558c7.81-1.892 15.742-3.482 23.788-4.724l12.252-67.384h64l12.252 67.382c8.044 1.242 15.976 2.832 23.79 4.724l37.1-57.558 59.128 24.492-14.468 66.944c6.91 4.216 13.62 8.726 20.13 13.492l56.342-39.006 45.256 45.256-39.006 56.342c4.766 6.512 9.276 13.22 13.492 20.13l66.944-14.468 24.492 59.13-57.558 37.1c1.892 7.812 3.482 15.742 4.724 23.79l67.382 12.25zM672 468.8c-76.878 0-139.2 62.322-139.2 139.2s62.32 139.2 139.2 139.2 139.2-62.322 139.2-139.2c0-76.878-62.32-139.2-139.2-139.2z" />
21
+ <glyph unicode="&#xe99a;" glyph-name="pie-chart" d="M448 384v448c-247.424 0-448-200.576-448-448s200.576-448 448-448 448 200.576 448 448c0 72.034-17.028 140.084-47.236 200.382l-400.764-200.382zM912.764 712.382c-73.552 146.816-225.374 247.618-400.764 247.618v-448l400.764 200.382z" />
22
+ <glyph unicode="&#xe99b;" glyph-name="stats-dots" d="M128 64h896v-128h-1024v1024h128zM288 128c-53.020 0-96 42.98-96 96s42.98 96 96 96c2.828 0 5.622-0.148 8.388-0.386l103.192 171.986c-9.84 15.070-15.58 33.062-15.58 52.402 0 53.020 42.98 96 96 96s96-42.98 96-96c0-19.342-5.74-37.332-15.58-52.402l103.192-171.986c2.766 0.238 5.56 0.386 8.388 0.386 2.136 0 4.248-0.094 6.35-0.23l170.356 298.122c-10.536 15.408-16.706 34.036-16.706 54.11 0 53.020 42.98 96 96 96s96-42.98 96-96c0-53.020-42.98-96-96-96-2.14 0-4.248 0.094-6.35 0.232l-170.356-298.124c10.536-15.406 16.706-34.036 16.706-54.11 0-53.020-42.98-96-96-96s-96 42.98-96 96c0 19.34 5.74 37.332 15.578 52.402l-103.19 171.984c-2.766-0.238-5.56-0.386-8.388-0.386s-5.622 0.146-8.388 0.386l-103.192-171.986c9.84-15.068 15.58-33.060 15.58-52.4 0-53.020-42.98-96-96-96z" />
23
+ <glyph unicode="&#xe99c;" glyph-name="stats-bars" d="M0 128h1024v-128h-1024zM128 384h128v-192h-128zM320 640h128v-448h-128zM512 448h128v-256h-128zM704 832h128v-640h-128z" />
24
+ <glyph unicode="&#xe99d;" glyph-name="stats-bars2" d="M288 576h-192c-17.6 0-32-14.4-32-32v-576c0-17.6 14.4-32 32-32h192c17.6 0 32 14.4 32 32v576c0 17.6-14.4 32-32 32zM288 0h-192v256h192v-256zM608 704h-192c-17.6 0-32-14.4-32-32v-704c0-17.6 14.4-32 32-32h192c17.6 0 32 14.4 32 32v704c0 17.6-14.4 32-32 32zM608 0h-192v320h192v-320zM928 832h-192c-17.6 0-32-14.4-32-32v-832c0-17.6 14.4-32 32-32h192c17.6 0 32 14.4 32 32v832c0 17.6-14.4 32-32 32zM928 0h-192v384h192v-384z" />
25
+ <glyph unicode="&#xe9b4;" glyph-name="shield" d="M960 960l-448-128-448 128c0 0-4.5-51.698 0-128l448-140.090 448 140.090c4.498 76.302 0 128 0 128zM72.19 764.894c23.986-250.696 113.49-672.234 439.81-828.894 326.32 156.66 415.824 578.198 439.81 828.894l-439.81-165.358-439.81 165.358z" />
26
+ <glyph unicode="&#xe9b6;" glyph-name="switch" d="M640 813.412v-135.958c36.206-15.804 69.5-38.408 98.274-67.18 60.442-60.44 93.726-140.8 93.726-226.274s-33.286-165.834-93.726-226.274c-60.44-60.44-140.798-93.726-226.274-93.726s-165.834 33.286-226.274 93.726c-60.44 60.44-93.726 140.8-93.726 226.274s33.286 165.834 93.726 226.274c28.774 28.774 62.068 51.378 98.274 67.182v135.956c-185.048-55.080-320-226.472-320-429.412 0-247.424 200.578-448 448-448 247.424 0 448 200.576 448 448 0 202.94-134.95 374.332-320 429.412zM448 960h128v-512h-128z" />
27
+ <glyph unicode="&#xe9b7;" glyph-name="power-cord" d="M1024 677.5l-90.506 90.5-178.746-178.752-101.5 101.502 178.75 178.75-90.5 90.5-178.75-178.75-114.748 114.75-86.626-86.624 512.002-512 86.624 86.622-114.752 114.752 178.752 178.75zM794.040 286.21l-443.824 443.824c-95.818-114.904-204.52-292.454-129.396-445.216l-132.248-132.248c-31.112-31.114-31.112-82.024 0-113.136l14.858-14.858c31.114-31.114 82.026-31.114 113.138 0l132.246 132.244c152.764-75.132 330.318 33.566 445.226 129.39z" />
28
+ <glyph unicode="&#xe9c9;" glyph-name="sphere" d="M480 896c-265.096 0-480-214.904-480-480 0-265.098 214.904-480 480-480 265.098 0 480 214.902 480 480 0 265.096-214.902 480-480 480zM751.59 256c8.58 40.454 13.996 83.392 15.758 128h127.446c-3.336-44.196-13.624-87.114-30.68-128h-112.524zM208.41 576c-8.58-40.454-13.996-83.392-15.758-128h-127.444c3.336 44.194 13.622 87.114 30.678 128h112.524zM686.036 576c9.614-40.962 15.398-83.854 17.28-128h-191.316v128h174.036zM512 640v187.338c14.59-4.246 29.044-11.37 43.228-21.37 26.582-18.74 52.012-47.608 73.54-83.486 14.882-24.802 27.752-52.416 38.496-82.484h-155.264zM331.232 722.484c21.528 35.878 46.956 64.748 73.54 83.486 14.182 10 28.638 17.124 43.228 21.37v-187.34h-155.264c10.746 30.066 23.616 57.68 38.496 82.484zM448 576v-128h-191.314c1.88 44.146 7.666 87.038 17.278 128h174.036zM95.888 256c-17.056 40.886-27.342 83.804-30.678 128h127.444c1.762-44.608 7.178-87.546 15.758-128h-112.524zM256.686 384h191.314v-128h-174.036c-9.612 40.96-15.398 83.854-17.278 128zM448 192v-187.34c-14.588 4.246-29.044 11.372-43.228 21.37-26.584 18.74-52.014 47.61-73.54 83.486-14.882 24.804-27.75 52.418-38.498 82.484h155.266zM628.768 109.516c-21.528-35.876-46.958-64.746-73.54-83.486-14.184-9.998-28.638-17.124-43.228-21.37v187.34h155.266c-10.746-30.066-23.616-57.68-38.498-82.484zM512 256v128h191.314c-1.88-44.146-7.666-87.040-17.28-128h-174.034zM767.348 448c-1.762 44.608-7.178 87.546-15.758 128h112.524c17.056-40.886 27.344-83.806 30.68-128h-127.446zM830.658 640h-95.9c-18.638 58.762-44.376 110.294-75.316 151.428 42.536-20.34 81.058-47.616 114.714-81.272 21.48-21.478 40.362-44.938 56.502-70.156zM185.844 710.156c33.658 33.658 72.18 60.932 114.714 81.272-30.942-41.134-56.676-92.666-75.316-151.428h-95.898c16.138 25.218 35.022 48.678 56.5 70.156zM129.344 192h95.898c18.64-58.762 44.376-110.294 75.318-151.43-42.536 20.34-81.058 47.616-114.714 81.274-21.48 21.478-40.364 44.938-56.502 70.156zM774.156 121.844c-33.656-33.658-72.18-60.934-114.714-81.274 30.942 41.134 56.678 92.668 75.316 151.43h95.9c-16.14-25.218-35.022-48.678-56.502-70.156z" />
29
+ <glyph unicode="&#xe9ca;" glyph-name="earth" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512-0.002c-62.958 0-122.872 13.012-177.23 36.452l233.148 262.29c5.206 5.858 8.082 13.422 8.082 21.26v96c0 17.674-14.326 32-32 32-112.99 0-232.204 117.462-233.374 118.626-6 6.002-14.14 9.374-22.626 9.374h-128c-17.672 0-32-14.328-32-32v-192c0-12.122 6.848-23.202 17.69-28.622l110.31-55.156v-187.886c-116.052 80.956-192 215.432-192 367.664 0 68.714 15.49 133.806 43.138 192h116.862c8.488 0 16.626 3.372 22.628 9.372l128 128c6 6.002 9.372 14.14 9.372 22.628v77.412c40.562 12.074 83.518 18.588 128 18.588 70.406 0 137.004-16.26 196.282-45.2-4.144-3.502-8.176-7.164-12.046-11.036-36.266-36.264-56.236-84.478-56.236-135.764s19.97-99.5 56.236-135.764c36.434-36.432 85.218-56.264 135.634-56.26 3.166 0 6.342 0.080 9.518 0.236 13.814-51.802 38.752-186.656-8.404-372.334-0.444-1.744-0.696-3.488-0.842-5.224-81.324-83.080-194.7-134.656-320.142-134.656z" />
30
+ <glyph unicode="&#xea1c;" glyph-name="play3" d="M192 832l640-384-640-384z" />
31
+ <glyph unicode="&#xea1d;" glyph-name="pause2" d="M128 832h320v-768h-320zM576 832h320v-768h-320z" />
32
+ <glyph unicode="&#xea1e;" glyph-name="stop2" d="M128 832h768v-768h-768z" />
33
+ <glyph unicode="&#xea25;" glyph-name="eject" d="M0 192h1024v-128h-1024zM512 832l512-512h-1024z" />
34
+ <glyph unicode="&#xea7e;" glyph-name="new-tab" d="M192 896v-768h768v768h-768zM896 192h-640v640h640v-640zM128 64v672l-64 64v-800h800l-64 64h-672zM352 704l160-160-192-192 96-96 192 192 160-160v416z" />
35
+ </font></defs></svg>
admin/css/fonts/icomoon.ttf ADDED
Binary file
admin/css/fonts/icomoon.woff ADDED
Binary file
admin/datatables/css/datatables-all.css ADDED
@@ -0,0 +1,642 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.16
2
+ * 2008-2017 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ table.dataTable {
6
+ width: 100%;
7
+ margin: 0 auto;
8
+ clear: both;
9
+ border-collapse: separate;
10
+ border-spacing: 0;
11
+ /*
12
+ * Header and footer styles
13
+ */
14
+ /*
15
+ * Body styles
16
+ */
17
+ }
18
+ table.dataTable thead th,
19
+ table.dataTable tfoot th {
20
+ font-weight: bold;
21
+ }
22
+ table.dataTable thead th,
23
+ table.dataTable thead td {
24
+ padding: 10px 18px;
25
+ border-bottom: 1px solid #111;
26
+ }
27
+ table.dataTable thead th:active,
28
+ table.dataTable thead td:active {
29
+ outline: none;
30
+ }
31
+ table.dataTable tfoot th,
32
+ table.dataTable tfoot td {
33
+ padding: 10px 18px 6px 18px;
34
+ border-top: 1px solid #111;
35
+ }
36
+ table.dataTable thead .sorting,
37
+ table.dataTable thead .sorting_asc,
38
+ table.dataTable thead .sorting_desc,
39
+ table.dataTable thead .sorting_asc_disabled,
40
+ table.dataTable thead .sorting_desc_disabled {
41
+ cursor: pointer;
42
+ *cursor: hand;
43
+ background-repeat: no-repeat;
44
+ background-position: center right;
45
+ }
46
+ table.dataTable thead .sorting {
47
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAAN0lEQVR4AWO4c+cORZhmBvyH4QEx4D86pqsB/3Fjwgb8J4RpaQBhPES8gE/z0ElI9M9MA1+gAAD5jWGc4eZ87AAAAABJRU5ErkJggg==); /*url("../images/sort_both.png");*/
48
+ }
49
+ table.dataTable thead .sorting_asc {
50
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAIAAAAWBRqYAAAABnRSTlMA3ADcANwpVcdiAAAAdUlEQVR4AWO4QyKgWMONG3eWrrh76xbRGtZvulPTdHfzVuI0nDl7p7XrblXD3Y7eu+fPE6FhwWKgaihasuIuAQ2Hj95pbENoqG+9e/QYbg3Xr9+ZPB2iFIGmzrp78yYODdt3gvxa24yCgCK79pAcD8NEw6gGAPv5+lejjyPQAAAAAElFTkSuQmCC); /*url("../images/sort_asc.png");*/
51
+ }
52
+ table.dataTable thead .sorting_desc {
53
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAIAAAAWBRqYAAAABnRSTlMA3ADcANwpVcdiAAAAcklEQVR4AWO4QyIY2hpGNezac6em6W5tMwoCimzfiUPDzZt3ps66W9WAgiZPv3v9Om4nHT12p74Vobqx7e7ho4T8sGQFQsOCxXcJe/r8+TsdvSDVrV13z5wlLpQ2bwX5fv0mooP11q07S1fcvXFjACMOAM7v+leNDkNAAAAAAElFTkSuQmCC); /*url("../images/sort_desc.png");*/
54
+ }
55
+ table.dataTable thead .sorting_asc_disabled {
56
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAALklEQVR4AWO4c+cORZhmBvyH4QEx4D86pqsB/3Fjwgb8J4RpZsDAJ6RRA0YNAAAd2DjFaOCLnQAAAABJRU5ErkJggg==); /*url("../images/sort_asc_disabled.png");*/
57
+ }
58
+ table.dataTable thead .sorting_desc_disabled {
59
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAALUlEQVR4AWO4c+cORZjqBowaMGrAf0KYlgYQNoToMMClma4GMKBrpqsB9E9IAFTzOMWpD7f6AAAAAElFTkSuQmCC); /*url("../images/sort_desc_disabled.png");*/
60
+ }
61
+ table.dataTable tbody tr {
62
+ background-color: #ffffff;
63
+ }
64
+ table.dataTable tbody tr.selected {
65
+ background-color: #B0BED9;
66
+ }
67
+ table.dataTable tbody th,
68
+ table.dataTable tbody td {
69
+ padding: 8px 10px;
70
+ }
71
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
72
+ border-top: 1px solid #ddd;
73
+ }
74
+ table.dataTable.row-border tbody tr:first-child th,
75
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
76
+ table.dataTable.display tbody tr:first-child td {
77
+ border-top: none;
78
+ }
79
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
80
+ border-top: 1px solid #ddd;
81
+ border-right: 1px solid #ddd;
82
+ }
83
+ table.dataTable.cell-border tbody tr th:first-child,
84
+ table.dataTable.cell-border tbody tr td:first-child {
85
+ border-left: 1px solid #ddd;
86
+ }
87
+ table.dataTable.cell-border tbody tr:first-child th,
88
+ table.dataTable.cell-border tbody tr:first-child td {
89
+ border-top: none;
90
+ }
91
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
92
+ background-color: #f9f9f9;
93
+ }
94
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
95
+ background-color: #acbad4;
96
+ }
97
+ table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
98
+ background-color: #f6f6f6;
99
+ }
100
+ table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
101
+ background-color: #aab7d1;
102
+ }
103
+ table.dataTable.order-column tbody tr > .sorting_1,
104
+ table.dataTable.order-column tbody tr > .sorting_2,
105
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
106
+ table.dataTable.display tbody tr > .sorting_2,
107
+ table.dataTable.display tbody tr > .sorting_3 {
108
+ background-color: #fafafa;
109
+ }
110
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
111
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
112
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
113
+ table.dataTable.display tbody tr.selected > .sorting_2,
114
+ table.dataTable.display tbody tr.selected > .sorting_3 {
115
+ background-color: #acbad5;
116
+ }
117
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
118
+ background-color: #f1f1f1;
119
+ }
120
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
121
+ background-color: #f3f3f3;
122
+ }
123
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
124
+ background-color: whitesmoke;
125
+ }
126
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
127
+ background-color: #a6b4cd;
128
+ }
129
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
130
+ background-color: #a8b5cf;
131
+ }
132
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
133
+ background-color: #a9b7d1;
134
+ }
135
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
136
+ background-color: #fafafa;
137
+ }
138
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
139
+ background-color: #fcfcfc;
140
+ }
141
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
142
+ background-color: #fefefe;
143
+ }
144
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
145
+ background-color: #acbad5;
146
+ }
147
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
148
+ background-color: #aebcd6;
149
+ }
150
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
151
+ background-color: #afbdd8;
152
+ }
153
+ table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
154
+ background-color: #eaeaea;
155
+ }
156
+ table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
157
+ background-color: #ececec;
158
+ }
159
+ table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
160
+ background-color: #efefef;
161
+ }
162
+ table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
163
+ background-color: #a2aec7;
164
+ }
165
+ table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
166
+ background-color: #a3b0c9;
167
+ }
168
+ table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
169
+ background-color: #a5b2cb;
170
+ }
171
+ table.dataTable.no-footer {
172
+ border-bottom: 1px solid #111;
173
+ }
174
+ table.dataTable.nowrap th, table.dataTable.nowrap td {
175
+ white-space: nowrap;
176
+ }
177
+ table.dataTable.compact thead th,
178
+ table.dataTable.compact thead td {
179
+ padding: 4px 17px 4px 4px;
180
+ }
181
+ table.dataTable.compact tfoot th,
182
+ table.dataTable.compact tfoot td {
183
+ padding: 4px;
184
+ }
185
+ table.dataTable.compact tbody th,
186
+ table.dataTable.compact tbody td {
187
+ padding: 4px;
188
+ }
189
+ table.dataTable th.dt-left,
190
+ table.dataTable td.dt-left {
191
+ text-align: left;
192
+ }
193
+ table.dataTable th.dt-center,
194
+ table.dataTable td.dt-center,
195
+ table.dataTable td.dataTables_empty {
196
+ text-align: center;
197
+ }
198
+ table.dataTable th.dt-right,
199
+ table.dataTable td.dt-right {
200
+ text-align: right;
201
+ }
202
+ table.dataTable th.dt-justify,
203
+ table.dataTable td.dt-justify {
204
+ text-align: justify;
205
+ }
206
+ table.dataTable th.dt-nowrap,
207
+ table.dataTable td.dt-nowrap {
208
+ white-space: nowrap;
209
+ }
210
+ table.dataTable thead th.dt-head-left,
211
+ table.dataTable thead td.dt-head-left,
212
+ table.dataTable tfoot th.dt-head-left,
213
+ table.dataTable tfoot td.dt-head-left {
214
+ text-align: left;
215
+ }
216
+ table.dataTable thead th.dt-head-center,
217
+ table.dataTable thead td.dt-head-center,
218
+ table.dataTable tfoot th.dt-head-center,
219
+ table.dataTable tfoot td.dt-head-center {
220
+ text-align: center;
221
+ }
222
+ table.dataTable thead th.dt-head-right,
223
+ table.dataTable thead td.dt-head-right,
224
+ table.dataTable tfoot th.dt-head-right,
225
+ table.dataTable tfoot td.dt-head-right {
226
+ text-align: right;
227
+ }
228
+ table.dataTable thead th.dt-head-justify,
229
+ table.dataTable thead td.dt-head-justify,
230
+ table.dataTable tfoot th.dt-head-justify,
231
+ table.dataTable tfoot td.dt-head-justify {
232
+ text-align: justify;
233
+ }
234
+ table.dataTable thead th.dt-head-nowrap,
235
+ table.dataTable thead td.dt-head-nowrap,
236
+ table.dataTable tfoot th.dt-head-nowrap,
237
+ table.dataTable tfoot td.dt-head-nowrap {
238
+ white-space: nowrap;
239
+ }
240
+ table.dataTable tbody th.dt-body-left,
241
+ table.dataTable tbody td.dt-body-left {
242
+ text-align: left;
243
+ }
244
+ table.dataTable tbody th.dt-body-center,
245
+ table.dataTable tbody td.dt-body-center {
246
+ text-align: center;
247
+ }
248
+ table.dataTable tbody th.dt-body-right,
249
+ table.dataTable tbody td.dt-body-right {
250
+ text-align: right;
251
+ }
252
+ table.dataTable tbody th.dt-body-justify,
253
+ table.dataTable tbody td.dt-body-justify {
254
+ text-align: justify;
255
+ }
256
+ table.dataTable tbody th.dt-body-nowrap,
257
+ table.dataTable tbody td.dt-body-nowrap {
258
+ white-space: nowrap;
259
+ }
260
+
261
+ table.dataTable,
262
+ table.dataTable th,
263
+ table.dataTable td {
264
+ box-sizing: content-box;
265
+ }
266
+
267
+ /*
268
+ * Control feature layout
269
+ */
270
+ .dataTables_wrapper {
271
+ position: relative;
272
+ clear: both;
273
+ *zoom: 1;
274
+ zoom: 1;
275
+ }
276
+ .dataTables_wrapper .dataTables_length {
277
+ float: left;
278
+ }
279
+ .dataTables_wrapper .dataTables_filter {
280
+ float: right;
281
+ text-align: right;
282
+ }
283
+ .dataTables_wrapper .dataTables_filter input {
284
+ margin-left: 0.5em;
285
+ }
286
+ .dataTables_wrapper .dataTables_info {
287
+ clear: both;
288
+ float: left;
289
+ padding-top: 0.755em;
290
+ }
291
+ .dataTables_wrapper .dataTables_paginate {
292
+ float: right;
293
+ text-align: right;
294
+ padding-top: 0.25em;
295
+ }
296
+ .dataTables_wrapper .dataTables_paginate .paginate_button {
297
+ box-sizing: border-box;
298
+ display: inline-block;
299
+ min-width: 1.5em;
300
+ padding: 0.5em 1em;
301
+ margin-left: 2px;
302
+ text-align: center;
303
+ text-decoration: none !important;
304
+ cursor: pointer;
305
+ *cursor: hand;
306
+ color: #333 !important;
307
+ border: 1px solid transparent;
308
+ border-radius: 2px;
309
+ }
310
+ .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
311
+ color: #333 !important;
312
+ border: 1px solid #979797;
313
+ background-color: white;
314
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
315
+ /* Chrome,Safari4+ */
316
+ background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
317
+ /* Chrome10+,Safari5.1+ */
318
+ background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
319
+ /* FF3.6+ */
320
+ background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
321
+ /* IE10+ */
322
+ background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
323
+ /* Opera 11.10+ */
324
+ background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
325
+ /* W3C */
326
+ }
327
+ .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
328
+ cursor: default;
329
+ color: #666 !important;
330
+ border: 1px solid transparent;
331
+ background: transparent;
332
+ box-shadow: none;
333
+ }
334
+ .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
335
+ color: white !important;
336
+ border: 1px solid #111;
337
+ background-color: #585858;
338
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
339
+ /* Chrome,Safari4+ */
340
+ background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
341
+ /* Chrome10+,Safari5.1+ */
342
+ background: -moz-linear-gradient(top, #585858 0%, #111 100%);
343
+ /* FF3.6+ */
344
+ background: -ms-linear-gradient(top, #585858 0%, #111 100%);
345
+ /* IE10+ */
346
+ background: -o-linear-gradient(top, #585858 0%, #111 100%);
347
+ /* Opera 11.10+ */
348
+ background: linear-gradient(to bottom, #585858 0%, #111 100%);
349
+ /* W3C */
350
+ }
351
+ .dataTables_wrapper .dataTables_paginate .paginate_button:active {
352
+ outline: none;
353
+ background-color: #2b2b2b;
354
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
355
+ /* Chrome,Safari4+ */
356
+ background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
357
+ /* Chrome10+,Safari5.1+ */
358
+ background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
359
+ /* FF3.6+ */
360
+ background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
361
+ /* IE10+ */
362
+ background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
363
+ /* Opera 11.10+ */
364
+ background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
365
+ /* W3C */
366
+ box-shadow: inset 0 0 3px #111;
367
+ }
368
+ .dataTables_wrapper .dataTables_paginate .ellipsis {
369
+ padding: 0 1em;
370
+ }
371
+ .dataTables_wrapper .dataTables_processing {
372
+ position: absolute;
373
+ top: 50%;
374
+ left: 50%;
375
+ width: 100%;
376
+ height: 40px;
377
+ margin-left: -50%;
378
+ margin-top: -25px;
379
+ padding-top: 20px;
380
+ text-align: center;
381
+ font-size: 1.2em;
382
+ background-color: white;
383
+ 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)));
384
+ 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%);
385
+ 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%);
386
+ 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%);
387
+ 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%);
388
+ 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%);
389
+ }
390
+ .dataTables_wrapper .dataTables_length,
391
+ .dataTables_wrapper .dataTables_filter,
392
+ .dataTables_wrapper .dataTables_info,
393
+ .dataTables_wrapper .dataTables_processing,
394
+ .dataTables_wrapper .dataTables_paginate {
395
+ color: #333;
396
+ }
397
+ .dataTables_wrapper .dataTables_scroll {
398
+ clear: both;
399
+ }
400
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
401
+ *margin-top: -1px;
402
+ -webkit-overflow-scrolling: touch;
403
+ }
404
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {
405
+ vertical-align: middle;
406
+ }
407
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,
408
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,
409
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {
410
+ height: 0;
411
+ overflow: hidden;
412
+ margin: 0 !important;
413
+ padding: 0 !important;
414
+ }
415
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
416
+ border-bottom: 1px solid #111;
417
+ }
418
+ .dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,
419
+ .dataTables_wrapper.no-footer div.dataTables_scrollBody > table {
420
+ border-bottom: none;
421
+ }
422
+ .dataTables_wrapper:after {
423
+ visibility: hidden;
424
+ display: block;
425
+ content: "";
426
+ clear: both;
427
+ height: 0;
428
+ }
429
+
430
+ @media screen and (max-width: 767px) {
431
+ .dataTables_wrapper .dataTables_info,
432
+ .dataTables_wrapper .dataTables_paginate {
433
+ float: none;
434
+ text-align: center;
435
+ }
436
+ .dataTables_wrapper .dataTables_paginate {
437
+ margin-top: 0.5em;
438
+ }
439
+ }
440
+ @media screen and (max-width: 640px) {
441
+ .dataTables_wrapper .dataTables_length,
442
+ .dataTables_wrapper .dataTables_filter {
443
+ float: none;
444
+ text-align: center;
445
+ }
446
+ .dataTables_wrapper .dataTables_filter {
447
+ margin-top: 0.5em;
448
+ }
449
+ }
450
+
451
+ /*! Responsive 2.1.1
452
+ * 2014-2016 SpryMedia Ltd - datatables.net/license
453
+ */
454
+
455
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
456
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
457
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
458
+ cursor: default !important;
459
+ }
460
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
461
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
462
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
463
+ display: none !important;
464
+ }
465
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child,
466
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child {
467
+ position: relative;
468
+ padding-left: 30px;
469
+ cursor: pointer;
470
+ }
471
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before,
472
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before {
473
+ top: 9px;
474
+ left: 4px;
475
+ height: 14px;
476
+ width: 14px;
477
+ display: block;
478
+ position: absolute;
479
+ color: white;
480
+ border: 2px solid white;
481
+ border-radius: 14px;
482
+ box-shadow: 0 0 3px #444;
483
+ box-sizing: content-box;
484
+ text-align: center;
485
+ font-family: 'Courier New', Courier, monospace;
486
+ line-height: 14px;
487
+ content: '+';
488
+ background-color: #31b131;
489
+ }
490
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
491
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
492
+ content: '-';
493
+ background-color: #d33333;
494
+ }
495
+ table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before {
496
+ display: none;
497
+ }
498
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
499
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
500
+ padding-left: 27px;
501
+ }
502
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,
503
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {
504
+ top: 5px;
505
+ left: 4px;
506
+ height: 14px;
507
+ width: 14px;
508
+ border-radius: 14px;
509
+ line-height: 14px;
510
+ text-indent: 3px;
511
+ }
512
+ table.dataTable.dtr-column > tbody > tr > td.control,
513
+ table.dataTable.dtr-column > tbody > tr > th.control {
514
+ position: relative;
515
+ cursor: pointer;
516
+ }
517
+ table.dataTable.dtr-column > tbody > tr > td.control:before,
518
+ table.dataTable.dtr-column > tbody > tr > th.control:before {
519
+ top: 50%;
520
+ left: 50%;
521
+ height: 16px;
522
+ width: 16px;
523
+ margin-top: -10px;
524
+ margin-left: -10px;
525
+ display: block;
526
+ position: absolute;
527
+ color: white;
528
+ border: 2px solid white;
529
+ border-radius: 14px;
530
+ box-shadow: 0 0 3px #444;
531
+ box-sizing: content-box;
532
+ text-align: center;
533
+ font-family: 'Courier New', Courier, monospace;
534
+ line-height: 14px;
535
+ content: '+';
536
+ background-color: #31b131;
537
+ }
538
+ table.dataTable.dtr-column > tbody > tr.parent td.control:before,
539
+ table.dataTable.dtr-column > tbody > tr.parent th.control:before {
540
+ content: '-';
541
+ background-color: #d33333;
542
+ }
543
+ table.dataTable > tbody > tr.child {
544
+ padding: 0.5em 1em;
545
+ }
546
+ table.dataTable > tbody > tr.child:hover {
547
+ background: transparent !important;
548
+ }
549
+ table.dataTable > tbody > tr.child ul.dtr-details {
550
+ display: inline-block;
551
+ list-style-type: none;
552
+ margin: 0;
553
+ padding: 0;
554
+ }
555
+ table.dataTable > tbody > tr.child ul.dtr-details li {
556
+ border-bottom: 1px solid #efefef;
557
+ padding: 0.5em 0;
558
+ }
559
+ table.dataTable > tbody > tr.child ul.dtr-details li:first-child {
560
+ padding-top: 0;
561
+ }
562
+ table.dataTable > tbody > tr.child ul.dtr-details li:last-child {
563
+ border-bottom: none;
564
+ }
565
+ table.dataTable > tbody > tr.child span.dtr-title {
566
+ display: inline-block;
567
+ min-width: 75px;
568
+ font-weight: bold;
569
+ }
570
+
571
+ div.dtr-modal {
572
+ position: fixed;
573
+ box-sizing: border-box;
574
+ top: 0;
575
+ left: 0;
576
+ height: 100%;
577
+ width: 100%;
578
+ z-index: 100;
579
+ padding: 10em 1em;
580
+ }
581
+ div.dtr-modal div.dtr-modal-display {
582
+ position: absolute;
583
+ top: 0;
584
+ left: 0;
585
+ bottom: 0;
586
+ right: 0;
587
+ width: 50%;
588
+ height: 50%;
589
+ overflow: auto;
590
+ margin: auto;
591
+ z-index: 102;
592
+ overflow: auto;
593
+ background-color: #f5f5f7;
594
+ border: 1px solid black;
595
+ border-radius: 0.5em;
596
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
597
+ }
598
+ div.dtr-modal div.dtr-modal-content {
599
+ position: relative;
600
+ padding: 1em;
601
+ }
602
+ div.dtr-modal div.dtr-modal-close {
603
+ position: absolute;
604
+ top: 6px;
605
+ right: 6px;
606
+ width: 22px;
607
+ height: 22px;
608
+ border: 1px solid #eaeaea;
609
+ background-color: #f9f9f9;
610
+ text-align: center;
611
+ border-radius: 3px;
612
+ cursor: pointer;
613
+ z-index: 12;
614
+ }
615
+ div.dtr-modal div.dtr-modal-close:hover {
616
+ background-color: #eaeaea;
617
+ }
618
+ div.dtr-modal div.dtr-modal-background {
619
+ position: fixed;
620
+ top: 0;
621
+ left: 0;
622
+ right: 0;
623
+ bottom: 0;
624
+ z-index: 101;
625
+ background: rgba(0, 0, 0, 0.6);
626
+ }
627
+
628
+ @media screen and (max-width: 767px) {
629
+ div.dtr-modal div.dtr-modal-display {
630
+ width: 95%;
631
+ }
632
+ }
633
+
634
+ /*! datatables.mark.js v2.0.1
635
+ * Copyright (c) 2016-2017 Julian Motz
636
+ * https://github.com/julmot/datatables.mark.js/blob/master/LICENSE
637
+ */
638
+
639
+ mark {
640
+ background: orange;
641
+ color: black;
642
+ }
admin/datatables/css/datatables-all.min.css ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.16
2
+ * 2008-2017 SpryMedia Ltd - datatables.net/license
3
+ */
4
+ table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAAN0lEQVR4AWO4c+cORZhmBvyH4QEx4D86pqsB/3Fjwgb8J4RpaQBhPES8gE/z0ElI9M9MA1+gAAD5jWGc4eZ87AAAAABJRU5ErkJggg==)}table.dataTable thead .sorting_asc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAIAAAAWBRqYAAAABnRSTlMA3ADcANwpVcdiAAAAdUlEQVR4AWO4QyKgWMONG3eWrrh76xbRGtZvulPTdHfzVuI0nDl7p7XrblXD3Y7eu+fPE6FhwWKgaihasuIuAQ2Hj95pbENoqG+9e/QYbg3Xr9+ZPB2iFIGmzrp78yYODdt3gvxa24yCgCK79pAcD8NEw6gGAPv5+lejjyPQAAAAAElFTkSuQmCC)}table.dataTable thead .sorting_desc{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAIAAAAWBRqYAAAABnRSTlMA3ADcANwpVcdiAAAAcklEQVR4AWO4QyIY2hpGNezac6em6W5tMwoCimzfiUPDzZt3ps66W9WAgiZPv3v9Om4nHT12p74Vobqx7e7ho4T8sGQFQsOCxXcJe/r8+TsdvSDVrV13z5wlLpQ2bwX5fv0mooP11q07S1fcvXFjACMOAM7v+leNDkNAAAAAAElFTkSuQmCC)}table.dataTable thead .sorting_asc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAALklEQVR4AWO4c+cORZhmBvyH4QEx4D86pqsB/3Fjwgb8J4RpZsDAJ6RRA0YNAAAd2DjFaOCLnQAAAABJRU5ErkJggg==)}table.dataTable thead .sorting_desc_disabled{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAATCAYAAACZZ43PAAAALUlEQVR4AWO4c+cORZjqBowaMGrAf0KYlgYQNoToMMClma4GMKBrpqsB9E9IAFTzOMWpD7f6AAAAAElFTkSuQmCC)}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;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)));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%);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%);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%);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%);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%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
5
+ /*! Responsive 2.1.1
6
+ * 2014-2016 SpryMedia Ltd - datatables.net/license
7
+ */
8
+ table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}
9
+ /*! datatables.mark.js v2.0.1
10
+ * Copyright (c) 2016-2017 Julian Motz
11
+ * https://github.com/julmot/datatables.mark.js/blob/master/LICENSE
12
+ */
13
+ mark{background:orange;color:black;}
admin/datatables/css/datatables.mark.css ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ /*! datatables.mark.js v2.0.1
2
+ * Copyright (c) 2016–2017 Julian Motz
3
+ * https://github.com/julmot/datatables.mark.js/blob/master/LICENSE
4
+ */
5
+
6
+ mark {
7
+ background: orange;
8
+ color: black;
9
+ }
admin/datatables/css/datatables.mark.min.css ADDED
@@ -0,0 +1 @@
 
1
+ mark{background:orange;color:black;}
admin/datatables/css/jquery.dataTables.css ADDED
@@ -0,0 +1,449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.16
2
+ * 2008-2017 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ table.dataTable {
6
+ width: 100%;
7
+ margin: 0 auto;
8
+ clear: both;
9
+ border-collapse: separate;
10
+ border-spacing: 0;
11
+ /*
12
+ * Header and footer styles
13
+ */
14
+ /*
15
+ * Body styles
16
+ */
17
+ }
18
+ table.dataTable thead th,
19
+ table.dataTable tfoot th {
20
+ font-weight: bold;
21
+ }
22
+ table.dataTable thead th,
23
+ table.dataTable thead td {
24
+ padding: 10px 18px;
25
+ border-bottom: 1px solid #111;
26
+ }
27
+ table.dataTable thead th:active,
28
+ table.dataTable thead td:active {
29
+ outline: none;
30
+ }
31
+ table.dataTable tfoot th,
32
+ table.dataTable tfoot td {
33
+ padding: 10px 18px 6px 18px;
34
+ border-top: 1px solid #111;
35
+ }
36
+ table.dataTable thead .sorting,
37
+ table.dataTable thead .sorting_asc,
38
+ table.dataTable thead .sorting_desc,
39
+ table.dataTable thead .sorting_asc_disabled,
40
+ table.dataTable thead .sorting_desc_disabled {
41
+ cursor: pointer;
42
+ *cursor: hand;
43
+ background-repeat: no-repeat;
44
+ background-position: center right;
45
+ }
46
+ table.dataTable thead .sorting {
47
+ background-image: url("../images/sort_both.png");
48
+ }
49
+ table.dataTable thead .sorting_asc {
50
+ background-image: url("../images/sort_asc.png");
51
+ }
52
+ table.dataTable thead .sorting_desc {
53
+ background-image: url("../images/sort_desc.png");
54
+ }
55
+ table.dataTable thead .sorting_asc_disabled {
56
+ background-image: url("../images/sort_asc_disabled.png");
57
+ }
58
+ table.dataTable thead .sorting_desc_disabled {
59
+ background-image: url("../images/sort_desc_disabled.png");
60
+ }
61
+ table.dataTable tbody tr {
62
+ background-color: #ffffff;
63
+ }
64
+ table.dataTable tbody tr.selected {
65
+ background-color: #B0BED9;
66
+ }
67
+ table.dataTable tbody th,
68
+ table.dataTable tbody td {
69
+ padding: 8px 10px;
70
+ }
71
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
72
+ border-top: 1px solid #ddd;
73
+ }
74
+ table.dataTable.row-border tbody tr:first-child th,
75
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
76
+ table.dataTable.display tbody tr:first-child td {
77
+ border-top: none;
78
+ }
79
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
80
+ border-top: 1px solid #ddd;
81
+ border-right: 1px solid #ddd;
82
+ }
83
+ table.dataTable.cell-border tbody tr th:first-child,
84
+ table.dataTable.cell-border tbody tr td:first-child {
85
+ border-left: 1px solid #ddd;
86
+ }
87
+ table.dataTable.cell-border tbody tr:first-child th,
88
+ table.dataTable.cell-border tbody tr:first-child td {
89
+ border-top: none;
90
+ }
91
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
92
+ background-color: #f9f9f9;
93
+ }
94
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
95
+ background-color: #acbad4;
96
+ }
97
+ table.dataTable.hover tbody tr:hover, table.dataTable.display tbody tr:hover {
98
+ background-color: #f6f6f6;
99
+ }
100
+ table.dataTable.hover tbody tr:hover.selected, table.dataTable.display tbody tr:hover.selected {
101
+ background-color: #aab7d1;
102
+ }
103
+ table.dataTable.order-column tbody tr > .sorting_1,
104
+ table.dataTable.order-column tbody tr > .sorting_2,
105
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
106
+ table.dataTable.display tbody tr > .sorting_2,
107
+ table.dataTable.display tbody tr > .sorting_3 {
108
+ background-color: #fafafa;
109
+ }
110
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
111
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
112
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
113
+ table.dataTable.display tbody tr.selected > .sorting_2,
114
+ table.dataTable.display tbody tr.selected > .sorting_3 {
115
+ background-color: #acbad5;
116
+ }
117
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
118
+ background-color: #f1f1f1;
119
+ }
120
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
121
+ background-color: #f3f3f3;
122
+ }
123
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
124
+ background-color: whitesmoke;
125
+ }
126
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
127
+ background-color: #a6b4cd;
128
+ }
129
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
130
+ background-color: #a8b5cf;
131
+ }
132
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
133
+ background-color: #a9b7d1;
134
+ }
135
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
136
+ background-color: #fafafa;
137
+ }
138
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
139
+ background-color: #fcfcfc;
140
+ }
141
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
142
+ background-color: #fefefe;
143
+ }
144
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
145
+ background-color: #acbad5;
146
+ }
147
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
148
+ background-color: #aebcd6;
149
+ }
150
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
151
+ background-color: #afbdd8;
152
+ }
153
+ table.dataTable.display tbody tr:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1 {
154
+ background-color: #eaeaea;
155
+ }
156
+ table.dataTable.display tbody tr:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2 {
157
+ background-color: #ececec;
158
+ }
159
+ table.dataTable.display tbody tr:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3 {
160
+ background-color: #efefef;
161
+ }
162
+ table.dataTable.display tbody tr:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1 {
163
+ background-color: #a2aec7;
164
+ }
165
+ table.dataTable.display tbody tr:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2 {
166
+ background-color: #a3b0c9;
167
+ }
168
+ table.dataTable.display tbody tr:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3 {
169
+ background-color: #a5b2cb;
170
+ }
171
+ table.dataTable.no-footer {
172
+ border-bottom: 1px solid #111;
173
+ }
174
+ table.dataTable.nowrap th, table.dataTable.nowrap td {
175
+ white-space: nowrap;
176
+ }
177
+ table.dataTable.compact thead th,
178
+ table.dataTable.compact thead td {
179
+ padding: 4px 17px 4px 4px;
180
+ }
181
+ table.dataTable.compact tfoot th,
182
+ table.dataTable.compact tfoot td {
183
+ padding: 4px;
184
+ }
185
+ table.dataTable.compact tbody th,
186
+ table.dataTable.compact tbody td {
187
+ padding: 4px;
188
+ }
189
+ table.dataTable th.dt-left,
190
+ table.dataTable td.dt-left {
191
+ text-align: left;
192
+ }
193
+ table.dataTable th.dt-center,
194
+ table.dataTable td.dt-center,
195
+ table.dataTable td.dataTables_empty {
196
+ text-align: center;
197
+ }
198
+ table.dataTable th.dt-right,
199
+ table.dataTable td.dt-right {
200
+ text-align: right;
201
+ }
202
+ table.dataTable th.dt-justify,
203
+ table.dataTable td.dt-justify {
204
+ text-align: justify;
205
+ }
206
+ table.dataTable th.dt-nowrap,
207
+ table.dataTable td.dt-nowrap {
208
+ white-space: nowrap;
209
+ }
210
+ table.dataTable thead th.dt-head-left,
211
+ table.dataTable thead td.dt-head-left,
212
+ table.dataTable tfoot th.dt-head-left,
213
+ table.dataTable tfoot td.dt-head-left {
214
+ text-align: left;
215
+ }
216
+ table.dataTable thead th.dt-head-center,
217
+ table.dataTable thead td.dt-head-center,
218
+ table.dataTable tfoot th.dt-head-center,
219
+ table.dataTable tfoot td.dt-head-center {
220
+ text-align: center;
221
+ }
222
+ table.dataTable thead th.dt-head-right,
223
+ table.dataTable thead td.dt-head-right,
224
+ table.dataTable tfoot th.dt-head-right,
225
+ table.dataTable tfoot td.dt-head-right {
226
+ text-align: right;
227
+ }
228
+ table.dataTable thead th.dt-head-justify,
229
+ table.dataTable thead td.dt-head-justify,
230
+ table.dataTable tfoot th.dt-head-justify,
231
+ table.dataTable tfoot td.dt-head-justify {
232
+ text-align: justify;
233
+ }
234
+ table.dataTable thead th.dt-head-nowrap,
235
+ table.dataTable thead td.dt-head-nowrap,
236
+ table.dataTable tfoot th.dt-head-nowrap,
237
+ table.dataTable tfoot td.dt-head-nowrap {
238
+ white-space: nowrap;
239
+ }
240
+ table.dataTable tbody th.dt-body-left,
241
+ table.dataTable tbody td.dt-body-left {
242
+ text-align: left;
243
+ }
244
+ table.dataTable tbody th.dt-body-center,
245
+ table.dataTable tbody td.dt-body-center {
246
+ text-align: center;
247
+ }
248
+ table.dataTable tbody th.dt-body-right,
249
+ table.dataTable tbody td.dt-body-right {
250
+ text-align: right;
251
+ }
252
+ table.dataTable tbody th.dt-body-justify,
253
+ table.dataTable tbody td.dt-body-justify {
254
+ text-align: justify;
255
+ }
256
+ table.dataTable tbody th.dt-body-nowrap,
257
+ table.dataTable tbody td.dt-body-nowrap {
258
+ white-space: nowrap;
259
+ }
260
+
261
+ table.dataTable,
262
+ table.dataTable th,
263
+ table.dataTable td {
264
+ box-sizing: content-box;
265
+ }
266
+
267
+ /*
268
+ * Control feature layout
269
+ */
270
+ .dataTables_wrapper {
271
+ position: relative;
272
+ clear: both;
273
+ *zoom: 1;
274
+ zoom: 1;
275
+ }
276
+ .dataTables_wrapper .dataTables_length {
277
+ float: left;
278
+ }
279
+ .dataTables_wrapper .dataTables_filter {
280
+ float: right;
281
+ text-align: right;
282
+ }
283
+ .dataTables_wrapper .dataTables_filter input {
284
+ margin-left: 0.5em;
285
+ }
286
+ .dataTables_wrapper .dataTables_info {
287
+ clear: both;
288
+ float: left;
289
+ padding-top: 0.755em;
290
+ }
291
+ .dataTables_wrapper .dataTables_paginate {
292
+ float: right;
293
+ text-align: right;
294
+ padding-top: 0.25em;
295
+ }
296
+ .dataTables_wrapper .dataTables_paginate .paginate_button {
297
+ box-sizing: border-box;
298
+ display: inline-block;
299
+ min-width: 1.5em;
300
+ padding: 0.5em 1em;
301
+ margin-left: 2px;
302
+ text-align: center;
303
+ text-decoration: none !important;
304
+ cursor: pointer;
305
+ *cursor: hand;
306
+ color: #333 !important;
307
+ border: 1px solid transparent;
308
+ border-radius: 2px;
309
+ }
310
+ .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
311
+ color: #333 !important;
312
+ border: 1px solid #979797;
313
+ background-color: white;
314
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, #dcdcdc));
315
+ /* Chrome,Safari4+ */
316
+ background: -webkit-linear-gradient(top, white 0%, #dcdcdc 100%);
317
+ /* Chrome10+,Safari5.1+ */
318
+ background: -moz-linear-gradient(top, white 0%, #dcdcdc 100%);
319
+ /* FF3.6+ */
320
+ background: -ms-linear-gradient(top, white 0%, #dcdcdc 100%);
321
+ /* IE10+ */
322
+ background: -o-linear-gradient(top, white 0%, #dcdcdc 100%);
323
+ /* Opera 11.10+ */
324
+ background: linear-gradient(to bottom, white 0%, #dcdcdc 100%);
325
+ /* W3C */
326
+ }
327
+ .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
328
+ cursor: default;
329
+ color: #666 !important;
330
+ border: 1px solid transparent;
331
+ background: transparent;
332
+ box-shadow: none;
333
+ }
334
+ .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
335
+ color: white !important;
336
+ border: 1px solid #111;
337
+ background-color: #585858;
338
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));
339
+ /* Chrome,Safari4+ */
340
+ background: -webkit-linear-gradient(top, #585858 0%, #111 100%);
341
+ /* Chrome10+,Safari5.1+ */
342
+ background: -moz-linear-gradient(top, #585858 0%, #111 100%);
343
+ /* FF3.6+ */
344
+ background: -ms-linear-gradient(top, #585858 0%, #111 100%);
345
+ /* IE10+ */
346
+ background: -o-linear-gradient(top, #585858 0%, #111 100%);
347
+ /* Opera 11.10+ */
348
+ background: linear-gradient(to bottom, #585858 0%, #111 100%);
349
+ /* W3C */
350
+ }
351
+ .dataTables_wrapper .dataTables_paginate .paginate_button:active {
352
+ outline: none;
353
+ background-color: #2b2b2b;
354
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
355
+ /* Chrome,Safari4+ */
356
+ background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
357
+ /* Chrome10+,Safari5.1+ */
358
+ background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
359
+ /* FF3.6+ */
360
+ background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
361
+ /* IE10+ */
362
+ background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
363
+ /* Opera 11.10+ */
364
+ background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
365
+ /* W3C */
366
+ box-shadow: inset 0 0 3px #111;
367
+ }
368
+ .dataTables_wrapper .dataTables_paginate .ellipsis {
369
+ padding: 0 1em;
370
+ }
371
+ .dataTables_wrapper .dataTables_processing {
372
+ position: absolute;
373
+ top: 50%;
374
+ left: 50%;
375
+ width: 100%;
376
+ height: 40px;
377
+ margin-left: -50%;
378
+ margin-top: -25px;
379
+ padding-top: 20px;
380
+ text-align: center;
381
+ font-size: 1.2em;
382
+ background-color: white;
383
+ 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)));
384
+ 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%);
385
+ 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%);
386
+ 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%);
387
+ 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%);
388
+ 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%);
389
+ }
390
+ .dataTables_wrapper .dataTables_length,
391
+ .dataTables_wrapper .dataTables_filter,
392
+ .dataTables_wrapper .dataTables_info,
393
+ .dataTables_wrapper .dataTables_processing,
394
+ .dataTables_wrapper .dataTables_paginate {
395
+ color: #333;
396
+ }
397
+ .dataTables_wrapper .dataTables_scroll {
398
+ clear: both;
399
+ }
400
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
401
+ *margin-top: -1px;
402
+ -webkit-overflow-scrolling: touch;
403
+ }
404
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td {
405
+ vertical-align: middle;
406
+ }
407
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > th > div.dataTables_sizing,
408
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > thead > tr > td > div.dataTables_sizing, .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > th > div.dataTables_sizing,
409
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody > table > tbody > tr > td > div.dataTables_sizing {
410
+ height: 0;
411
+ overflow: hidden;
412
+ margin: 0 !important;
413
+ padding: 0 !important;
414
+ }
415
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
416
+ border-bottom: 1px solid #111;
417
+ }
418
+ .dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,
419
+ .dataTables_wrapper.no-footer div.dataTables_scrollBody > table {
420
+ border-bottom: none;
421
+ }
422
+ .dataTables_wrapper:after {
423
+ visibility: hidden;
424
+ display: block;
425
+ content: "";
426
+ clear: both;
427
+ height: 0;
428
+ }
429
+
430
+ @media screen and (max-width: 767px) {
431
+ .dataTables_wrapper .dataTables_info,
432
+ .dataTables_wrapper .dataTables_paginate {
433
+ float: none;
434
+ text-align: center;
435
+ }
436
+ .dataTables_wrapper .dataTables_paginate {
437
+ margin-top: 0.5em;
438
+ }
439
+ }
440
+ @media screen and (max-width: 640px) {
441
+ .dataTables_wrapper .dataTables_length,
442
+ .dataTables_wrapper .dataTables_filter {
443
+ float: none;
444
+ text-align: center;
445
+ }
446
+ .dataTables_wrapper .dataTables_filter {
447
+ margin-top: 0.5em;
448
+ }
449
+ }
admin/datatables/css/jquery.dataTables.min.css ADDED
@@ -0,0 +1 @@
 
1
+ table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{cursor:pointer;*cursor:hand;background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#ffffff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#acbad4}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f6f6f6}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#aab7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#fafafa}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad5}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:whitesmoke}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#fafafa}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fcfcfc}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fefefe}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ececec}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#efefef}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a5b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent;border-radius:2px}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #979797;background-color:white;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;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)));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%);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%);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%);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%);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%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td{vertical-align:middle}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>thead>tr>td>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody>table>tbody>tr>td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table.dataTable,.dataTables_wrapper.no-footer div.dataTables_scrollBody>table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
admin/datatables/css/responsive.dataTables.css ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! Responsive 2.1.1
2
+ * 2014-2016 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child,
6
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child,
7
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty {
8
+ cursor: default !important;
9
+ }
10
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.child:before,
11
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th.child:before,
12
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td.dataTables_empty:before {
13
+ display: none !important;
14
+ }
15
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child,
16
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child {
17
+ position: relative;
18
+ padding-left: 30px;
19
+ cursor: pointer;
20
+ }
21
+ table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before,
22
+ table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before {
23
+ top: 9px;
24
+ left: 4px;
25
+ height: 14px;
26
+ width: 14px;
27
+ display: block;
28
+ position: absolute;
29
+ color: white;
30
+ border: 2px solid white;
31
+ border-radius: 14px;
32
+ box-shadow: 0 0 3px #444;
33
+ box-sizing: content-box;
34
+ text-align: center;
35
+ font-family: 'Courier New', Courier, monospace;
36
+ line-height: 14px;
37
+ content: '+';
38
+ background-color: #31b131;
39
+ }
40
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
41
+ table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
42
+ content: '-';
43
+ background-color: #d33333;
44
+ }
45
+ table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before {
46
+ display: none;
47
+ }
48
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
49
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
50
+ padding-left: 27px;
51
+ }
52
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,
53
+ table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {
54
+ top: 5px;
55
+ left: 4px;
56
+ height: 14px;
57
+ width: 14px;
58
+ border-radius: 14px;
59
+ line-height: 14px;
60
+ text-indent: 3px;
61
+ }
62
+ table.dataTable.dtr-column > tbody > tr > td.control,
63
+ table.dataTable.dtr-column > tbody > tr > th.control {
64
+ position: relative;
65
+ cursor: pointer;
66
+ }
67
+ table.dataTable.dtr-column > tbody > tr > td.control:before,
68
+ table.dataTable.dtr-column > tbody > tr > th.control:before {
69
+ top: 50%;
70
+ left: 50%;
71
+ height: 16px;
72
+ width: 16px;
73
+ margin-top: -10px;
74
+ margin-left: -10px;
75
+ display: block;
76
+ position: absolute;
77
+ color: white;
78
+ border: 2px solid white;
79
+ border-radius: 14px;
80
+ box-shadow: 0 0 3px #444;
81
+ box-sizing: content-box;
82
+ text-align: center;
83
+ font-family: 'Courier New', Courier, monospace;
84
+ line-height: 14px;
85
+ content: '+';
86
+ background-color: #31b131;
87
+ }
88
+ table.dataTable.dtr-column > tbody > tr.parent td.control:before,
89
+ table.dataTable.dtr-column > tbody > tr.parent th.control:before {
90
+ content: '-';
91
+ background-color: #d33333;
92
+ }
93
+ table.dataTable > tbody > tr.child {
94
+ padding: 0.5em 1em;
95
+ }
96
+ table.dataTable > tbody > tr.child:hover {
97
+ background: transparent !important;
98
+ }
99
+ table.dataTable > tbody > tr.child ul.dtr-details {
100
+ display: inline-block;
101
+ list-style-type: none;
102
+ margin: 0;
103
+ padding: 0;
104
+ }
105
+ table.dataTable > tbody > tr.child ul.dtr-details li {
106
+ border-bottom: 1px solid #efefef;
107
+ padding: 0.5em 0;
108
+ }
109
+ table.dataTable > tbody > tr.child ul.dtr-details li:first-child {
110
+ padding-top: 0;
111
+ }
112
+ table.dataTable > tbody > tr.child ul.dtr-details li:last-child {
113
+ border-bottom: none;
114
+ }
115
+ table.dataTable > tbody > tr.child span.dtr-title {
116
+ display: inline-block;
117
+ min-width: 75px;
118
+ font-weight: bold;
119
+ }
120
+
121
+ div.dtr-modal {
122
+ position: fixed;
123
+ box-sizing: border-box;
124
+ top: 0;
125
+ left: 0;
126
+ height: 100%;
127
+ width: 100%;
128
+ z-index: 100;
129
+ padding: 10em 1em;
130
+ }
131
+ div.dtr-modal div.dtr-modal-display {
132
+ position: absolute;
133
+ top: 0;
134
+ left: 0;
135
+ bottom: 0;
136
+ right: 0;
137
+ width: 50%;
138
+ height: 50%;
139
+ overflow: auto;
140
+ margin: auto;
141
+ z-index: 102;
142
+ overflow: auto;
143
+ background-color: #f5f5f7;
144
+ border: 1px solid black;
145
+ border-radius: 0.5em;
146
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.6);
147
+ }
148
+ div.dtr-modal div.dtr-modal-content {
149
+ position: relative;
150
+ padding: 1em;
151
+ }
152
+ div.dtr-modal div.dtr-modal-close {
153
+ position: absolute;
154
+ top: 6px;
155
+ right: 6px;
156
+ width: 22px;
157
+ height: 22px;
158
+ border: 1px solid #eaeaea;
159
+ background-color: #f9f9f9;
160
+ text-align: center;
161
+ border-radius: 3px;
162
+ cursor: pointer;
163
+ z-index: 12;
164
+ }
165
+ div.dtr-modal div.dtr-modal-close:hover {
166
+ background-color: #eaeaea;
167
+ }
168
+ div.dtr-modal div.dtr-modal-background {
169
+ position: fixed;
170
+ top: 0;
171
+ left: 0;
172
+ right: 0;
173
+ bottom: 0;
174
+ z-index: 101;
175
+ background: rgba(0, 0, 0, 0.6);
176
+ }
177
+
178
+ @media screen and (max-width: 767px) {
179
+ div.dtr-modal div.dtr-modal-display {
180
+ width: 95%;
181
+ }
182
+ }
admin/datatables/css/responsive.dataTables.min.css ADDED
@@ -0,0 +1 @@
 
1
+ table.dataTable.dtr-inline.collapsed>tbody>tr>td.child,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty{cursor:default !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th.child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>td.dataTables_empty:before{display:none !important}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr>th:first-child:before{top:9px;left:4px;height:14px;width:14px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before,table.dataTable.dtr-inline.collapsed>tbody>tr.parent>th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-inline.collapsed>tbody>tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child{padding-left:27px}table.dataTable.dtr-inline.collapsed.compact>tbody>tr>td:first-child:before,table.dataTable.dtr-inline.collapsed.compact>tbody>tr>th:first-child:before{top:5px;left:4px;height:14px;width:14px;border-radius:14px;line-height:14px;text-indent:3px}table.dataTable.dtr-column>tbody>tr>td.control,table.dataTable.dtr-column>tbody>tr>th.control{position:relative;cursor:pointer}table.dataTable.dtr-column>tbody>tr>td.control:before,table.dataTable.dtr-column>tbody>tr>th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:white;border:2px solid white;border-radius:14px;box-shadow:0 0 3px #444;box-sizing:content-box;text-align:center;font-family:'Courier New', Courier, monospace;line-height:14px;content:'+';background-color:#31b131}table.dataTable.dtr-column>tbody>tr.parent td.control:before,table.dataTable.dtr-column>tbody>tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable>tbody>tr.child{padding:0.5em 1em}table.dataTable>tbody>tr.child:hover{background:transparent !important}table.dataTable>tbody>tr.child ul.dtr-details{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable>tbody>tr.child ul.dtr-details li{border-bottom:1px solid #efefef;padding:0.5em 0}table.dataTable>tbody>tr.child ul.dtr-details li:first-child{padding-top:0}table.dataTable>tbody>tr.child ul.dtr-details li:last-child{border-bottom:none}table.dataTable>tbody>tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:bold}div.dtr-modal{position:fixed;box-sizing:border-box;top:0;left:0;height:100%;width:100%;z-index:100;padding:10em 1em}div.dtr-modal div.dtr-modal-display{position:absolute;top:0;left:0;bottom:0;right:0;width:50%;height:50%;overflow:auto;margin:auto;z-index:102;overflow:auto;background-color:#f5f5f7;border:1px solid black;border-radius:0.5em;box-shadow:0 12px 30px rgba(0,0,0,0.6)}div.dtr-modal div.dtr-modal-content{position:relative;padding:1em}div.dtr-modal div.dtr-modal-close{position:absolute;top:6px;right:6px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:12}div.dtr-modal div.dtr-modal-close:hover{background-color:#eaeaea}div.dtr-modal div.dtr-modal-background{position:fixed;top:0;left:0;right:0;bottom:0;z-index:101;background:rgba(0,0,0,0.6)}@media screen and (max-width: 767px){div.dtr-modal div.dtr-modal-display{width:95%}}
admin/datatables/images/Sorting icons.psd ADDED
Binary file
admin/datatables/images/favicon.ico ADDED
Binary file
admin/datatables/images/sort_asc.png ADDED
Binary file
admin/datatables/images/sort_asc_disabled.png ADDED
Binary file
admin/datatables/images/sort_both.png ADDED
Binary file
admin/datatables/images/sort_desc.png ADDED
Binary file
admin/datatables/images/sort_desc_disabled.png ADDED
Binary file
admin/datatables/js/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016–2017 Julian Motz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
admin/datatables/js/dataTables.responsive.js ADDED
@@ -0,0 +1,1255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! Responsive 2.1.1
2
+ * 2014-2016 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary Responsive
7
+ * @description Responsive tables plug-in for DataTables
8
+ * @version 2.1.1
9
+ * @file dataTables.responsive.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2014-2016 SpryMedia Ltd.
13
+ *
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license/mit
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
+ (function( factory ){
24
+ if ( typeof define === 'function' && define.amd ) {
25
+ // AMD
26
+ define( ['jquery', 'datatables.net'], function ( $ ) {
27
+ return factory( $, window, document );
28
+ } );
29
+ }
30
+ else if ( typeof exports === 'object' ) {
31
+ // CommonJS
32
+ module.exports = function (root, $) {
33
+ if ( ! root ) {
34
+ root = window;
35
+ }
36
+
37
+ if ( ! $ || ! $.fn.dataTable ) {
38
+ $ = require('datatables.net')(root, $).$;
39
+ }
40
+
41
+ return factory( $, root, root.document );
42
+ };
43
+ }
44
+ else {
45
+ // Browser
46
+ factory( jQuery, window, document );
47
+ }
48
+ }(function( $, window, document, undefined ) {
49
+ 'use strict';
50
+ var DataTable = $.fn.dataTable;
51
+
52
+
53
+ /**
54
+ * Responsive is a plug-in for the DataTables library that makes use of
55
+ * DataTables' ability to change the visibility of columns, changing the
56
+ * visibility of columns so the displayed columns fit into the table container.
57
+ * The end result is that complex tables will be dynamically adjusted to fit
58
+ * into the viewport, be it on a desktop, tablet or mobile browser.
59
+ *
60
+ * Responsive for DataTables has two modes of operation, which can used
61
+ * individually or combined:
62
+ *
63
+ * * Class name based control - columns assigned class names that match the
64
+ * breakpoint logic can be shown / hidden as required for each breakpoint.
65
+ * * Automatic control - columns are automatically hidden when there is no
66
+ * room left to display them. Columns removed from the right.
67
+ *
68
+ * In additional to column visibility control, Responsive also has built into
69
+ * options to use DataTables' child row display to show / hide the information
70
+ * from the table that has been hidden. There are also two modes of operation
71
+ * for this child row display:
72
+ *
73
+ * * Inline - when the control element that the user can use to show / hide
74
+ * child rows is displayed inside the first column of the table.
75
+ * * Column - where a whole column is dedicated to be the show / hide control.
76
+ *
77
+ * Initialisation of Responsive is performed by:
78
+ *
79
+ * * Adding the class `responsive` or `dt-responsive` to the table. In this case
80
+ * Responsive will automatically be initialised with the default configuration
81
+ * options when the DataTable is created.
82
+ * * Using the `responsive` option in the DataTables configuration options. This
83
+ * can also be used to specify the configuration options, or simply set to
84
+ * `true` to use the defaults.
85
+ *
86
+ * @class
87
+ * @param {object} settings DataTables settings object for the host table
88
+ * @param {object} [opts] Configuration options
89
+ * @requires jQuery 1.7+
90
+ * @requires DataTables 1.10.3+
91
+ *
92
+ * @example
93
+ * $('#example').DataTable( {
94
+ * responsive: true
95
+ * } );
96
+ * } );
97
+ */
98
+ var Responsive = function ( settings, opts ) {
99
+ // Sanity check that we are using DataTables 1.10 or newer
100
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
101
+ throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
102
+ }
103
+
104
+ this.s = {
105
+ dt: new DataTable.Api( settings ),
106
+ columns: [],
107
+ current: []
108
+ };
109
+
110
+ // Check if responsive has already been initialised on this table
111
+ if ( this.s.dt.settings()[0].responsive ) {
112
+ return;
113
+ }
114
+
115
+ // details is an object, but for simplicity the user can give it as a string
116
+ // or a boolean
117
+ if ( opts && typeof opts.details === 'string' ) {
118
+ opts.details = { type: opts.details };
119
+ }
120
+ else if ( opts && opts.details === false ) {
121
+ opts.details = { type: false };
122
+ }
123
+ else if ( opts && opts.details === true ) {
124
+ opts.details = { type: 'inline' };
125
+ }
126
+
127
+ this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
128
+ settings.responsive = this;
129
+ this._constructor();
130
+ };
131
+
132
+ $.extend( Responsive.prototype, {
133
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
134
+ * Constructor
135
+ */
136
+
137
+ /**
138
+ * Initialise the Responsive instance
139
+ *
140
+ * @private
141
+ */
142
+ _constructor: function ()
143
+ {
144
+ var that = this;
145
+ var dt = this.s.dt;
146
+ var dtPrivateSettings = dt.settings()[0];
147
+ var oldWindowWidth = $(window).width();
148
+
149
+ dt.settings()[0]._responsive = this;
150
+
151
+ // Use DataTables' throttle function to avoid processor thrashing on
152
+ // resize
153
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
154
+ // iOS has a bug whereby resize can fire when only scrolling
155
+ // See: http://stackoverflow.com/questions/8898412
156
+ var width = $(window).width();
157
+
158
+ if ( width !== oldWindowWidth ) {
159
+ that._resize();
160
+ oldWindowWidth = width;
161
+ }
162
+ } ) );
163
+
164
+ // DataTables doesn't currently trigger an event when a row is added, so
165
+ // we need to hook into its private API to enforce the hidden rows when
166
+ // new data is added
167
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
168
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
169
+ $('>td, >th', tr).each( function ( i ) {
170
+ var idx = dt.column.index( 'toData', i );
171
+
172
+ if ( that.s.current[idx] === false ) {
173
+ $(this).css('display', 'none');
174
+ }
175
+ } );
176
+ }
177
+ } );
178
+
179
+ // Destroy event handler
180
+ dt.on( 'destroy.dtr', function () {
181
+ dt.off( '.dtr' );
182
+ $( dt.table().body() ).off( '.dtr' );
183
+ $(window).off( 'resize.dtr orientationchange.dtr' );
184
+
185
+ // Restore the columns that we've hidden
186
+ $.each( that.s.current, function ( i, val ) {
187
+ if ( val === false ) {
188
+ that._setColumnVis( i, true );
189
+ }
190
+ } );
191
+ } );
192
+
193
+ // Reorder the breakpoints array here in case they have been added out
194
+ // of order
195
+ this.c.breakpoints.sort( function (a, b) {
196
+ return a.width < b.width ? 1 :
197
+ a.width > b.width ? -1 : 0;
198
+ } );
199
+
200
+ this._classLogic();
201
+ this._resizeAuto();
202
+
203
+ // Details handler
204
+ var details = this.c.details;
205
+
206
+ if ( details.type !== false ) {
207
+ that._detailsInit();
208
+
209
+ // DataTables will trigger this event on every column it shows and
210
+ // hides individually
211
+ dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
212
+ that._classLogic();
213
+ that._resizeAuto();
214
+ that._resize();
215
+ } );
216
+
217
+ // Redraw the details box on each draw which will happen if the data
218
+ // has changed. This is used until DataTables implements a native
219
+ // `updated` event for rows
220
+ dt.on( 'draw.dtr', function () {
221
+ that._redrawChildren();
222
+ } );
223
+
224
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
225
+ }
226
+
227
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
228
+ that._classLogic();
229
+ that._resizeAuto();
230
+ that._resize();
231
+ } );
232
+
233
+ // Change in column sizes means we need to calc
234
+ dt.on( 'column-sizing.dtr', function () {
235
+ that._resizeAuto();
236
+ that._resize();
237
+ });
238
+
239
+ // On Ajax reload we want to reopen any child rows which are displayed
240
+ // by responsive
241
+ dt.on( 'preXhr.dtr', function () {
242
+ var rowIds = [];
243
+ dt.rows().every( function () {
244
+ if ( this.child.isShown() ) {
245
+ rowIds.push( this.id(true) );
246
+ }
247
+ } );
248
+
249
+ dt.one( 'draw.dtr', function () {
250
+ dt.rows( rowIds ).every( function () {
251
+ that._detailsDisplay( this, false );
252
+ } );
253
+ } );
254
+ });
255
+
256
+ dt.on( 'init.dtr', function (e, settings, details) {
257
+ that._resizeAuto();
258
+ that._resize();
259
+
260
+ // If columns were hidden, then DataTables needs to adjust the
261
+ // column sizing
262
+ if ( $.inArray( false, that.s.current ) ) {
263
+ dt.columns.adjust();
264
+ }
265
+ } );
266
+
267
+ // First pass - draw the table for the current viewport size
268
+ this._resize();
269
+ },
270
+
271
+
272
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
273
+ * Private methods
274
+ */
275
+
276
+ /**
277
+ * Calculate the visibility for the columns in a table for a given
278
+ * breakpoint. The result is pre-determined based on the class logic if
279
+ * class names are used to control all columns, but the width of the table
280
+ * is also used if there are columns which are to be automatically shown
281
+ * and hidden.
282
+ *
283
+ * @param {string} breakpoint Breakpoint name to use for the calculation
284
+ * @return {array} Array of boolean values initiating the visibility of each
285
+ * column.
286
+ * @private
287
+ */
288
+ _columnsVisiblity: function ( breakpoint )
289
+ {
290
+ var dt = this.s.dt;
291
+ var columns = this.s.columns;
292
+ var i, ien;
293
+
294
+ // Create an array that defines the column ordering based first on the
295
+ // column's priority, and secondly the column index. This allows the
296
+ // columns to be removed from the right if the priority matches
297
+ var order = columns
298
+ .map( function ( col, idx ) {
299
+ return {
300
+ columnIdx: idx,
301
+ priority: col.priority
302
+ };
303
+ } )
304
+ .sort( function ( a, b ) {
305
+ if ( a.priority !== b.priority ) {
306
+ return a.priority - b.priority;
307
+ }
308
+ return a.columnIdx - b.columnIdx;
309
+ } );
310
+
311
+ // Class logic - determine which columns are in this breakpoint based
312
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
313
+ // to indicate this to the rest of the function
314
+ var display = $.map( columns, function ( col ) {
315
+ return col.auto && col.minWidth === null ?
316
+ false :
317
+ col.auto === true ?
318
+ '-' :
319
+ $.inArray( breakpoint, col.includeIn ) !== -1;
320
+ } );
321
+
322
+ // Auto column control - first pass: how much width is taken by the
323
+ // ones that must be included from the non-auto columns
324
+ var requiredWidth = 0;
325
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
326
+ if ( display[i] === true ) {
327
+ requiredWidth += columns[i].minWidth;
328
+ }
329
+ }
330
+
331
+ // Second pass, use up any remaining width for other columns. For
332
+ // scrolling tables we need to subtract the width of the scrollbar. It
333
+ // may not be requires which makes this sub-optimal, but it would
334
+ // require another full redraw to make complete use of those extra few
335
+ // pixels
336
+ var scrolling = dt.settings()[0].oScroll;
337
+ var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
338
+ var widthAvailable = dt.table().container().offsetWidth - bar;
339
+ var usedWidth = widthAvailable - requiredWidth;
340
+
341
+ // Control column needs to always be included. This makes it sub-
342
+ // optimal in terms of using the available with, but to stop layout
343
+ // thrashing or overflow. Also we need to account for the control column
344
+ // width first so we know how much width is available for the other
345
+ // columns, since the control column might not be the first one shown
346
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
347
+ if ( columns[i].control ) {
348
+ usedWidth -= columns[i].minWidth;
349
+ }
350
+ }
351
+
352
+ // Allow columns to be shown (counting by priority and then right to
353
+ // left) until we run out of room
354
+ var empty = false;
355
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
356
+ var colIdx = order[i].columnIdx;
357
+
358
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
359
+ // Once we've found a column that won't fit we don't let any
360
+ // others display either, or columns might disappear in the
361
+ // middle of the table
362
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
363
+ empty = true;
364
+ display[colIdx] = false;
365
+ }
366
+ else {
367
+ display[colIdx] = true;
368
+ }
369
+
370
+ usedWidth -= columns[colIdx].minWidth;
371
+ }
372
+ }
373
+
374
+ // Determine if the 'control' column should be shown (if there is one).
375
+ // This is the case when there is a hidden column (that is not the
376
+ // control column). The two loops look inefficient here, but they are
377
+ // trivial and will fly through. We need to know the outcome from the
378
+ // first , before the action in the second can be taken
379
+ var showControl = false;
380
+
381
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
382
+ if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
383
+ showControl = true;
384
+ break;
385
+ }
386
+ }
387
+
388
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
389
+ if ( columns[i].control ) {
390
+ display[i] = showControl;
391
+ }
392
+ }
393
+
394
+ // Finally we need to make sure that there is at least one column that
395
+ // is visible
396
+ if ( $.inArray( true, display ) === -1 ) {
397
+ display[0] = true;
398
+ }
399
+
400
+ return display;
401
+ },
402
+
403
+
404
+ /**
405
+ * Create the internal `columns` array with information about the columns
406
+ * for the table. This includes determining which breakpoints the column
407
+ * will appear in, based upon class names in the column, which makes up the
408
+ * vast majority of this method.
409
+ *
410
+ * @private
411
+ */
412
+ _classLogic: function ()
413
+ {
414
+ var that = this;
415
+ var calc = {};
416
+ var breakpoints = this.c.breakpoints;
417
+ var dt = this.s.dt;
418
+ var columns = dt.columns().eq(0).map( function (i) {
419
+ var column = this.column(i);
420
+ var className = column.header().className;
421
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
422
+
423
+ if ( priority === undefined ) {
424
+ var dataPriority = $(column.header()).data('priority');
425
+
426
+ priority = dataPriority !== undefined ?
427
+ dataPriority * 1 :
428
+ 10000;
429
+ }
430
+
431
+ return {
432
+ className: className,
433
+ includeIn: [],
434
+ auto: false,
435
+ control: false,
436
+ never: className.match(/\bnever\b/) ? true : false,
437
+ priority: priority
438
+ };
439
+ } );
440
+
441
+ // Simply add a breakpoint to `includeIn` array, ensuring that there are
442
+ // no duplicates
443
+ var add = function ( colIdx, name ) {
444
+ var includeIn = columns[ colIdx ].includeIn;
445
+
446
+ if ( $.inArray( name, includeIn ) === -1 ) {
447
+ includeIn.push( name );
448
+ }
449
+ };
450
+
451
+ var column = function ( colIdx, name, operator, matched ) {
452
+ var size, i, ien;
453
+
454
+ if ( ! operator ) {
455
+ columns[ colIdx ].includeIn.push( name );
456
+ }
457
+ else if ( operator === 'max-' ) {
458
+ // Add this breakpoint and all smaller
459
+ size = that._find( name ).width;
460
+
461
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
462
+ if ( breakpoints[i].width <= size ) {
463
+ add( colIdx, breakpoints[i].name );
464
+ }
465
+ }
466
+ }
467
+ else if ( operator === 'min-' ) {
468
+ // Add this breakpoint and all larger
469
+ size = that._find( name ).width;
470
+
471
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
472
+ if ( breakpoints[i].width >= size ) {
473
+ add( colIdx, breakpoints[i].name );
474
+ }
475
+ }
476
+ }
477
+ else if ( operator === 'not-' ) {
478
+ // Add all but this breakpoint
479
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
480
+ if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
481
+ add( colIdx, breakpoints[i].name );
482
+ }
483
+ }
484
+ }
485
+ };
486
+
487
+ // Loop over each column and determine if it has a responsive control
488
+ // class
489
+ columns.each( function ( col, i ) {
490
+ var classNames = col.className.split(' ');
491
+ var hasClass = false;
492
+
493
+ // Split the class name up so multiple rules can be applied if needed
494
+ for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
495
+ var className = $.trim( classNames[k] );
496
+
497
+ if ( className === 'all' ) {
498
+ // Include in all
499
+ hasClass = true;
500
+ col.includeIn = $.map( breakpoints, function (a) {
501
+ return a.name;
502
+ } );
503
+ return;
504
+ }
505
+ else if ( className === 'none' || col.never ) {
506
+ // Include in none (default) and no auto
507
+ hasClass = true;
508
+ return;
509
+ }
510
+ else if ( className === 'control' ) {
511
+ // Special column that is only visible, when one of the other
512
+ // columns is hidden. This is used for the details control
513
+ hasClass = true;
514
+ col.control = true;
515
+ return;
516
+ }
517
+
518
+ $.each( breakpoints, function ( j, breakpoint ) {
519
+ // Does this column have a class that matches this breakpoint?
520
+ var brokenPoint = breakpoint.name.split('-');
521
+ var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
522
+ var match = className.match( re );
523
+
524
+ if ( match ) {
525
+ hasClass = true;
526
+
527
+ if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
528
+ // Class name matches breakpoint name fully
529
+ column( i, breakpoint.name, match[1], match[2]+match[3] );
530
+ }
531
+ else if ( match[2] === brokenPoint[0] && ! match[3] ) {
532
+ // Class name matched primary breakpoint name with no qualifier
533
+ column( i, breakpoint.name, match[1], match[2] );
534
+ }
535
+ }
536
+ } );
537
+ }
538
+
539
+ // If there was no control class, then automatic sizing is used
540
+ if ( ! hasClass ) {
541
+ col.auto = true;
542
+ }
543
+ } );
544
+
545
+ this.s.columns = columns;
546
+ },
547
+
548
+
549
+ /**
550
+ * Show the details for the child row
551
+ *
552
+ * @param {DataTables.Api} row API instance for the row
553
+ * @param {boolean} update Update flag
554
+ * @private
555
+ */
556
+ _detailsDisplay: function ( row, update )
557
+ {
558
+ var that = this;
559
+ var dt = this.s.dt;
560
+ var details = this.c.details;
561
+
562
+ if ( details && details.type !== false ) {
563
+ var res = details.display( row, update, function () {
564
+ return details.renderer(
565
+ dt, row[0], that._detailsObj(row[0])
566
+ );
567
+ } );
568
+
569
+ if ( res === true || res === false ) {
570
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
571
+ }
572
+ }
573
+ },
574
+
575
+
576
+ /**
577
+ * Initialisation for the details handler
578
+ *
579
+ * @private
580
+ */
581
+ _detailsInit: function ()
582
+ {
583
+ var that = this;
584
+ var dt = this.s.dt;
585
+ var details = this.c.details;
586
+
587
+ // The inline type always uses the first child as the target
588
+ if ( details.type === 'inline' ) {
589
+ details.target = 'td:first-child, th:first-child';
590
+ }
591
+
592
+ // Keyboard accessibility
593
+ dt.on( 'draw.dtr', function () {
594
+ that._tabIndexes();
595
+ } );
596
+ that._tabIndexes(); // Initial draw has already happened
597
+
598
+ $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
599
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
600
+ $(this).click();
601
+ }
602
+ } );
603
+
604
+ // type.target can be a string jQuery selector or a column index
605
+ var target = details.target;
606
+ var selector = typeof target === 'string' ? target : 'td, th';
607
+
608
+ // Click handler to show / hide the details rows when they are available
609
+ $( dt.table().body() )
610
+ .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
611
+ // If the table is not collapsed (i.e. there is no hidden columns)
612
+ // then take no action
613
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
614
+ return;
615
+ }
616
+
617
+ // Check that the row is actually a DataTable's controlled node
618
+ if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
619
+ return;
620
+ }
621
+
622
+ // For column index, we determine if we should act or not in the
623
+ // handler - otherwise it is already okay
624
+ if ( typeof target === 'number' ) {
625
+ var targetIdx = target < 0 ?
626
+ dt.columns().eq(0).length + target :
627
+ target;
628
+
629
+ if ( dt.cell( this ).index().column !== targetIdx ) {
630
+ return;
631
+ }
632
+ }
633
+
634
+ // $().closest() includes itself in its check
635
+ var row = dt.row( $(this).closest('tr') );
636
+
637
+ // Check event type to do an action
638
+ if ( e.type === 'click' ) {
639
+ // The renderer is given as a function so the caller can execute it
640
+ // only when they need (i.e. if hiding there is no point is running
641
+ // the renderer)
642
+ that._detailsDisplay( row, false );
643
+ }
644
+ else if ( e.type === 'mousedown' ) {
645
+ // For mouse users, prevent the focus ring from showing
646
+ $(this).css('outline', 'none');
647
+ }
648
+ else if ( e.type === 'mouseup' ) {
649
+ // And then re-allow at the end of the click
650
+ $(this).blur().css('outline', '');
651
+ }
652
+ } );
653
+ },
654
+
655
+
656
+ /**
657
+ * Get the details to pass to a renderer for a row
658
+ * @param {int} rowIdx Row index
659
+ * @private
660
+ */
661
+ _detailsObj: function ( rowIdx )
662
+ {
663
+ var that = this;
664
+ var dt = this.s.dt;
665
+
666
+ return $.map( this.s.columns, function( col, i ) {
667
+ // Never and control columns should not be passed to the renderer
668
+ if ( col.never || col.control ) {
669
+ return;
670
+ }
671
+
672
+ return {
673
+ title: dt.settings()[0].aoColumns[ i ].sTitle,
674
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
675
+ hidden: dt.column( i ).visible() && !that.s.current[ i ],
676
+ columnIndex: i,
677
+ rowIndex: rowIdx
678
+ };
679
+ } );
680
+ },
681
+
682
+
683
+ /**
684
+ * Find a breakpoint object from a name
685
+ *
686
+ * @param {string} name Breakpoint name to find
687
+ * @return {object} Breakpoint description object
688
+ * @private
689
+ */
690
+ _find: function ( name )
691
+ {
692
+ var breakpoints = this.c.breakpoints;
693
+
694
+ for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
695
+ if ( breakpoints[i].name === name ) {
696
+ return breakpoints[i];
697
+ }
698
+ }
699
+ },
700
+
701
+
702
+ /**
703
+ * Re-create the contents of the child rows as the display has changed in
704
+ * some way.
705
+ *
706
+ * @private
707
+ */
708
+ _redrawChildren: function ()
709
+ {
710
+ var that = this;
711
+ var dt = this.s.dt;
712
+
713
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
714
+ var row = dt.row( idx );
715
+
716
+ that._detailsDisplay( dt.row( idx ), true );
717
+ } );
718
+ },
719
+
720
+
721
+ /**
722
+ * Alter the table display for a resized viewport. This involves first
723
+ * determining what breakpoint the window currently is in, getting the
724
+ * column visibilities to apply and then setting them.
725
+ *
726
+ * @private
727
+ */
728
+ _resize: function ()
729
+ {
730
+ var that = this;
731
+ var dt = this.s.dt;
732
+ var width = $(window).width();
733
+ var breakpoints = this.c.breakpoints;
734
+ var breakpoint = breakpoints[0].name;
735
+ var columns = this.s.columns;
736
+ var i, ien;
737
+ var oldVis = this.s.current.slice();
738
+
739
+ // Determine what breakpoint we are currently at
740
+ for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
741
+ if ( width <= breakpoints[i].width ) {
742
+ breakpoint = breakpoints[i].name;
743
+ break;
744
+ }
745
+ }
746
+
747
+ // Show the columns for that break point
748
+ var columnsVis = this._columnsVisiblity( breakpoint );
749
+ this.s.current = columnsVis;
750
+
751
+ // Set the class before the column visibility is changed so event
752
+ // listeners know what the state is. Need to determine if there are
753
+ // any columns that are not visible but can be shown
754
+ var collapsedClass = false;
755
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
756
+ if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
757
+ collapsedClass = true;
758
+ break;
759
+ }
760
+ }
761
+
762
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
763
+
764
+ var changed = false;
765
+
766
+ dt.columns().eq(0).each( function ( colIdx, i ) {
767
+ if ( columnsVis[i] !== oldVis[i] ) {
768
+ changed = true;
769
+ that._setColumnVis( colIdx, columnsVis[i] );
770
+ }
771
+ } );
772
+
773
+ if ( changed ) {
774
+ this._redrawChildren();
775
+
776
+ // Inform listeners of the change
777
+ $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
778
+ }
779
+ },
780
+
781
+
782
+ /**
783
+ * Determine the width of each column in the table so the auto column hiding
784
+ * has that information to work with. This method is never going to be 100%
785
+ * perfect since column widths can change slightly per page, but without
786
+ * seriously compromising performance this is quite effective.
787
+ *
788
+ * @private
789
+ */
790
+ _resizeAuto: function ()
791
+ {
792
+ var dt = this.s.dt;
793
+ var columns = this.s.columns;
794
+
795
+ // Are we allowed to do auto sizing?
796
+ if ( ! this.c.auto ) {
797
+ return;
798
+ }
799
+
800
+ // Are there any columns that actually need auto-sizing, or do they all
801
+ // have classes defined
802
+ if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
803
+ return;
804
+ }
805
+
806
+ // Clone the table with the current data in it
807
+ var tableWidth = dt.table().node().offsetWidth;
808
+ var columnWidths = dt.columns;
809
+ var clonedTable = dt.table().node().cloneNode( false );
810
+ var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
811
+ var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
812
+
813
+ // Header
814
+ var headerCells = dt.columns()
815
+ .header()
816
+ .filter( function (idx) {
817
+ return dt.column(idx).visible();
818
+ } )
819
+ .to$()
820
+ .clone( false )
821
+ .css( 'display', 'table-cell' );
822
+
823
+ // Body rows - we don't need to take account of DataTables' column
824
+ // visibility since we implement our own here (hence the `display` set)
825
+ $(clonedBody)
826
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
827
+ .find( 'th, td' ).css( 'display', '' );
828
+
829
+ // Footer
830
+ var footer = dt.table().footer();
831
+ if ( footer ) {
832
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
833
+ var footerCells = dt.columns()
834
+ .footer()
835
+ .filter( function (idx) {
836
+ return dt.column(idx).visible();
837
+ } )
838
+ .to$()
839
+ .clone( false )
840
+ .css( 'display', 'table-cell' );
841
+
842
+ $('<tr/>')
843
+ .append( footerCells )
844
+ .appendTo( clonedFooter );
845
+ }
846
+
847
+ $('<tr/>')
848
+ .append( headerCells )
849
+ .appendTo( clonedHeader );
850
+
851
+ // In the inline case extra padding is applied to the first column to
852
+ // give space for the show / hide icon. We need to use this in the
853
+ // calculation
854
+ if ( this.c.details.type === 'inline' ) {
855
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
856
+ }
857
+
858
+ // It is unsafe to insert elements with the same name into the DOM
859
+ // multiple times. For example, cloning and inserting a checked radio
860
+ // clears the chcecked state of the original radio.
861
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
862
+
863
+ var inserted = $('<div/>')
864
+ .css( {
865
+ width: 1,
866
+ height: 1,
867
+ overflow: 'hidden'
868
+ } )
869
+ .append( clonedTable );
870
+
871
+ inserted.insertBefore( dt.table().node() );
872
+
873
+ // The cloned header now contains the smallest that each column can be
874
+ headerCells.each( function (i) {
875
+ var idx = dt.column.index( 'fromVisible', i );
876
+ columns[ idx ].minWidth = this.offsetWidth || 0;
877
+ } );
878
+
879
+ inserted.remove();
880
+ },
881
+
882
+ /**
883
+ * Set a column's visibility.
884
+ *
885
+ * We don't use DataTables' column visibility controls in order to ensure
886
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
887
+ * supported (and all evergreen browsers of course) the control of the
888
+ * display attribute works well.
889
+ *
890
+ * @param {integer} col Column index
891
+ * @param {boolean} showHide Show or hide (true or false)
892
+ * @private
893
+ */
894
+ _setColumnVis: function ( col, showHide )
895
+ {
896
+ var dt = this.s.dt;
897
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
898
+
899
+ $( dt.column( col ).header() ).css( 'display', display );
900
+ $( dt.column( col ).footer() ).css( 'display', display );
901
+ dt.column( col ).nodes().to$().css( 'display', display );
902
+ },
903
+
904
+
905
+ /**
906
+ * Update the cell tab indexes for keyboard accessibility. This is called on
907
+ * every table draw - that is potentially inefficient, but also the least
908
+ * complex option given that column visibility can change on the fly. Its a
909
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
910
+ * issue with a single CSS statement.
911
+ *
912
+ * @private
913
+ */
914
+ _tabIndexes: function ()
915
+ {
916
+ var dt = this.s.dt;
917
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
918
+ var ctx = dt.settings()[0];
919
+ var target = this.c.details.target;
920
+
921
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
922
+
923
+ var selector = typeof target === 'number' ?
924
+ ':eq('+target+')' :
925
+ target;
926
+
927
+ // This is a bit of a hack - we need to limit the selected nodes to just
928
+ // those of this table
929
+ if ( selector === 'td:first-child, th:first-child' ) {
930
+ selector = '>td:first-child, >th:first-child';
931
+ }
932
+
933
+ $( selector, dt.rows( { page: 'current' } ).nodes() )
934
+ .attr( 'tabIndex', ctx.iTabIndex )
935
+ .data( 'dtr-keyboard', 1 );
936
+ }
937
+ } );
938
+
939
+
940
+ /**
941
+ * List of default breakpoints. Each item in the array is an object with two
942
+ * properties:
943
+ *
944
+ * * `name` - the breakpoint name.
945
+ * * `width` - the breakpoint width
946
+ *
947
+ * @name Responsive.breakpoints
948
+ * @static
949
+ */
950
+ Responsive.breakpoints = [
951
+ { name: 'desktop', width: Infinity },
952
+ { name: 'tablet-l', width: 1024 },
953
+ { name: 'tablet-p', width: 768 },
954
+ { name: 'mobile-l', width: 480 },
955
+ { name: 'mobile-p', width: 320 }
956
+ ];
957
+
958
+
959
+ /**
960
+ * Display methods - functions which define how the hidden data should be shown
961
+ * in the table.
962
+ *
963
+ * @namespace
964
+ * @name Responsive.defaults
965
+ * @static
966
+ */
967
+ Responsive.display = {
968
+ childRow: function ( row, update, render ) {
969
+ if ( update ) {
970
+ if ( $(row.node()).hasClass('parent') ) {
971
+ row.child( render(), 'child' ).show();
972
+
973
+ return true;
974
+ }
975
+ }
976
+ else {
977
+ if ( ! row.child.isShown() ) {
978
+ row.child( render(), 'child' ).show();
979
+ $( row.node() ).addClass( 'parent' );
980
+
981
+ return true;
982
+ }
983
+ else {
984
+ row.child( false );
985
+ $( row.node() ).removeClass( 'parent' );
986
+
987
+ return false;
988
+ }
989
+ }
990
+ },
991
+
992
+ childRowImmediate: function ( row, update, render ) {
993
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
994
+ // User interaction and the row is show, or nothing to show
995
+ row.child( false );
996
+ $( row.node() ).removeClass( 'parent' );
997
+
998
+ return false;
999
+ }
1000
+ else {
1001
+ // Display
1002
+ row.child( render(), 'child' ).show();
1003
+ $( row.node() ).addClass( 'parent' );
1004
+
1005
+ return true;
1006
+ }
1007
+ },
1008
+
1009
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
1010
+ // have options passed into them. This specific one doesn't need to be a
1011
+ // function but it is for consistency in the `modal` name
1012
+ modal: function ( options ) {
1013
+ return function ( row, update, render ) {
1014
+ if ( ! update ) {
1015
+ // Show a modal
1016
+ var close = function () {
1017
+ modal.remove(); // will tidy events for us
1018
+ $(document).off( 'keypress.dtr' );
1019
+ };
1020
+
1021
+ var modal = $('<div class="dtr-modal"/>')
1022
+ .append( $('<div class="dtr-modal-display"/>')
1023
+ .append( $('<div class="dtr-modal-content"/>')
1024
+ .append( render() )
1025
+ )
1026
+ .append( $('<div class="dtr-modal-close">&times;</div>' )
1027
+ .click( function () {
1028
+ close();
1029
+ } )
1030
+ )
1031
+ )
1032
+ .append( $('<div class="dtr-modal-background"/>')
1033
+ .click( function () {
1034
+ close();
1035
+ } )
1036
+ )
1037
+ .appendTo( 'body' );
1038
+
1039
+ $(document).on( 'keyup.dtr', function (e) {
1040
+ if ( e.keyCode === 27 ) {
1041
+ e.stopPropagation();
1042
+
1043
+ close();
1044
+ }
1045
+ } );
1046
+ }
1047
+ else {
1048
+ $('div.dtr-modal-content')
1049
+ .empty()
1050
+ .append( render() );
1051
+ }
1052
+
1053
+ if ( options && options.header ) {
1054
+ $('div.dtr-modal-content').prepend(
1055
+ '<h2>'+options.header( row )+'</h2>'
1056
+ );
1057
+ }
1058
+ };
1059
+ }
1060
+ };
1061
+
1062
+
1063
+ /**
1064
+ * Display methods - functions which define how the hidden data should be shown
1065
+ * in the table.
1066
+ *
1067
+ * @namespace
1068
+ * @name Responsive.defaults
1069
+ * @static
1070
+ */
1071
+ Responsive.renderer = {
1072
+ listHidden: function () {
1073
+ return function ( api, rowIdx, columns ) {
1074
+ var data = $.map( columns, function ( col ) {
1075
+ return col.hidden ?
1076
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1077
+ '<span class="dtr-title">'+
1078
+ col.title+
1079
+ '</span> '+
1080
+ '<span class="dtr-data">'+
1081
+ col.data+
1082
+ '</span>'+
1083
+ '</li>' :
1084
+ '';
1085
+ } ).join('');
1086
+
1087
+ return data ?
1088
+ $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
1089
+ false;
1090
+ }
1091
+ },
1092
+
1093
+ tableAll: function ( options ) {
1094
+ options = $.extend( {
1095
+ tableClass: ''
1096
+ }, options );
1097
+
1098
+ return function ( api, rowIdx, columns ) {
1099
+ var data = $.map( columns, function ( col ) {
1100
+ return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
1101
+ '<td>'+col.title+':'+'</td> '+
1102
+ '<td>'+col.data+'</td>'+
1103
+ '</tr>';
1104
+ } ).join('');
1105
+
1106
+ return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
1107
+ }
1108
+ }
1109
+ };
1110
+
1111
+ /**
1112
+ * Responsive default settings for initialisation
1113
+ *
1114
+ * @namespace
1115
+ * @name Responsive.defaults
1116
+ * @static
1117
+ */
1118
+ Responsive.defaults = {
1119
+ /**
1120
+ * List of breakpoints for the instance. Note that this means that each
1121
+ * instance can have its own breakpoints. Additionally, the breakpoints
1122
+ * cannot be changed once an instance has been creased.
1123
+ *
1124
+ * @type {Array}
1125
+ * @default Takes the value of `Responsive.breakpoints`
1126
+ */
1127
+ breakpoints: Responsive.breakpoints,
1128
+
1129
+ /**
1130
+ * Enable / disable auto hiding calculations. It can help to increase
1131
+ * performance slightly if you disable this option, but all columns would
1132
+ * need to have breakpoint classes assigned to them
1133
+ *
1134
+ * @type {Boolean}
1135
+ * @default `true`
1136
+ */
1137
+ auto: true,
1138
+
1139
+ /**
1140
+ * Details control. If given as a string value, the `type` property of the
1141
+ * default object is set to that value, and the defaults used for the rest
1142
+ * of the object - this is for ease of implementation.
1143
+ *
1144
+ * The object consists of the following properties:
1145
+ *
1146
+ * * `display` - A function that is used to show and hide the hidden details
1147
+ * * `renderer` - function that is called for display of the child row data.
1148
+ * The default function will show the data from the hidden columns
1149
+ * * `target` - Used as the selector for what objects to attach the child
1150
+ * open / close to
1151
+ * * `type` - `false` to disable the details display, `inline` or `column`
1152
+ * for the two control types
1153
+ *
1154
+ * @type {Object|string}
1155
+ */
1156
+ details: {
1157
+ display: Responsive.display.childRow,
1158
+
1159
+ renderer: Responsive.renderer.listHidden(),
1160
+
1161
+ target: 0,
1162
+
1163
+ type: 'inline'
1164
+ },
1165
+
1166
+ /**
1167
+ * Orthogonal data request option. This is used to define the data type
1168
+ * requested when Responsive gets the data to show in the child row.
1169
+ *
1170
+ * @type {String}
1171
+ */
1172
+ orthogonal: 'display'
1173
+ };
1174
+
1175
+
1176
+ /*
1177
+ * API
1178
+ */
1179
+ var Api = $.fn.dataTable.Api;
1180
+
1181
+ // Doesn't do anything - work around for a bug in DT... Not documented
1182
+ Api.register( 'responsive()', function () {
1183
+ return this;
1184
+ } );
1185
+
1186
+ Api.register( 'responsive.index()', function ( li ) {
1187
+ li = $(li);
1188
+
1189
+ return {
1190
+ column: li.data('dtr-index'),
1191
+ row: li.parent().data('dtr-index')
1192
+ };
1193
+ } );
1194
+
1195
+ Api.register( 'responsive.rebuild()', function () {
1196
+ return this.iterator( 'table', function ( ctx ) {
1197
+ if ( ctx._responsive ) {
1198
+ ctx._responsive._classLogic();
1199
+ }
1200
+ } );
1201
+ } );
1202
+
1203
+ Api.register( 'responsive.recalc()', function () {
1204
+ return this.iterator( 'table', function ( ctx ) {
1205
+ if ( ctx._responsive ) {
1206
+ ctx._responsive._resizeAuto();
1207
+ ctx._responsive._resize();
1208
+ }
1209
+ } );
1210
+ } );
1211
+
1212
+ Api.register( 'responsive.hasHidden()', function () {
1213
+ var ctx = this.context[0];
1214
+
1215
+ return ctx._responsive ?
1216
+ $.inArray( false, ctx._responsive.s.current ) !== -1 :
1217
+ false;
1218
+ } );
1219
+
1220
+
1221
+ /**
1222
+ * Version information
1223
+ *
1224
+ * @name Responsive.version
1225
+ * @static
1226
+ */
1227
+ Responsive.version = '2.1.1';
1228
+
1229
+
1230
+ $.fn.dataTable.Responsive = Responsive;
1231
+ $.fn.DataTable.Responsive = Responsive;
1232
+
1233
+ // Attach a listener to the document which listens for DataTables initialisation
1234
+ // events so we can automatically initialise
1235
+ $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
1236
+ if ( e.namespace !== 'dt' ) {
1237
+ return;
1238
+ }
1239
+
1240
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
1241
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
1242
+ settings.oInit.responsive ||
1243
+ DataTable.defaults.responsive
1244
+ ) {
1245
+ var init = settings.oInit.responsive;
1246
+
1247
+ if ( init !== false ) {
1248
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
1249
+ }
1250
+ }
1251
+ } );
1252
+
1253
+
1254
+ return Responsive;
1255
+ }));
admin/datatables/js/dataTables.responsive.min.js ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ Responsive 2.1.1
3
+ 2014-2016 SpryMedia Ltd - datatables.net/license
4
+ */
5
+ (function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[],
6
+ current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a=
7
+ c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width<b.width?1:a.width>
8
+ b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&&
9
+ e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&&
10
+ null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;e<f;e++)!0===h[e]&&(n+=d[e].minWidth);e=a.settings()[0].oScroll;e=e.sY||e.sX?e.iBarWidth:0;a=a.table().container().offsetWidth-e-n;e=0;for(f=h.length;e<f;e++)d[e].control&&(a-=d[e].minWidth);n=!1;e=0;for(f=g.length;e<f;e++){var i=g[e].columnIdx;"-"===h[i]&&(!d[i].control&&d[i].minWidth)&&(n||0>a-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e<f;e++)if(!d[e].control&&!d[e].never&&
11
+ !h[e]){g=!0;break}e=0;for(f=d.length;e<f;e++)d[e].control&&(h[e]=g);-1===c.inArray(!0,h)&&(h[0]=!0);return h},_classLogic:function(){var b=this,a=this.c.breakpoints,d=this.s.dt,e=d.columns().eq(0).map(function(a){var b=this.column(a),e=b.header().className,a=d.settings()[0].aoColumns[a].responsivePriority;a===p&&(b=c(b.header()).data("priority"),a=b!==p?1*b:1E4);return{className:e,includeIn:[],auto:!1,control:!1,never:e.match(/\bnever\b/)?!0:!1,priority:a}}),f=function(a,b){var d=e[a].includeIn;-1===
12
+ c.inArray(b,d)&&d.push(b)},g=function(c,d,i,g){if(i)if("max-"===i){g=b._find(d).width;d=0;for(i=a.length;d<i;d++)a[d].width<=g&&f(c,a[d].name)}else if("min-"===i){g=b._find(d).width;d=0;for(i=a.length;d<i;d++)a[d].width>=g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d<i;d++)-1===a[d].name.indexOf(g)&&f(c,a[d].name)}}else e[c].includeIn.push(d)};e.each(function(b,e){for(var d=b.className.split(" "),f=!1,j=0,l=d.length;j<l;j++){var k=c.trim(d[j]);if("all"===k){f=!0;b.includeIn=c.map(a,function(a){return a.name});
13
+ return}if("none"===k||b.never){f=!0;return}if("control"===k){f=!0;b.control=!0;return}c.each(a,function(a,b){var d=b.name.split("-"),c=k.match(RegExp("(min\\-|max\\-|not\\-)?("+d[0]+")(\\-[_a-zA-Z0-9])?"));c&&(f=!0,c[2]===d[0]&&c[3]==="-"+d[1]?g(e,b.name,c[1],c[2]+c[3]):c[2]===d[0]&&!c[3]&&g(e,b.name,c[1],c[2]))})}f||(b.auto=!0)});this.s.columns=e},_detailsDisplay:function(b,a){var d=this,e=this.s.dt,f=this.c.details;if(f&&!1!==f.type){var g=f.display(b,a,function(){return f.renderer(e,b[0],d._detailsObj(b[0]))});
14
+ (!0===g||!1===g)&&c(e.table().node()).triggerHandler("responsive-display.dt",[e,b,g,a])}},_detailsInit:function(){var b=this,a=this.s.dt,d=this.c.details;"inline"===d.type&&(d.target="td:first-child, th:first-child");a.on("draw.dtr",function(){b._tabIndexes()});b._tabIndexes();c(a.table().body()).on("keyup.dtr","td, th",function(b){b.keyCode===13&&c(this).data("dtr-keyboard")&&c(this).click()});var e=d.target;c(a.table().body()).on("click.dtr mousedown.dtr mouseup.dtr","string"===typeof e?e:"td, th",
15
+ function(d){if(c(a.table().node()).hasClass("collapsed")&&c.inArray(c(this).closest("tr").get(0),a.rows().nodes().toArray())!==-1){if(typeof e==="number"){var g=e<0?a.columns().eq(0).length+e:e;if(a.cell(this).index().column!==g)return}g=a.row(c(this).closest("tr"));d.type==="click"?b._detailsDisplay(g,false):d.type==="mousedown"?c(this).css("outline","none"):d.type==="mouseup"&&c(this).blur().css("outline","")}})},_detailsObj:function(b){var a=this,d=this.s.dt;return c.map(this.s.columns,function(e,
16
+ c){if(!e.never&&!e.control)return{title:d.settings()[0].aoColumns[c].sTitle,data:d.cell(b,c).render(a.c.orthogonal),hidden:d.column(c).visible()&&!a.s.current[c],columnIndex:c,rowIndex:b}})},_find:function(b){for(var a=this.c.breakpoints,d=0,c=a.length;d<c;d++)if(a[d].name===b)return a[d]},_redrawChildren:function(){var b=this,a=this.s.dt;a.rows({page:"current"}).iterator("row",function(c,e){a.row(e);b._detailsDisplay(a.row(e),!0)})},_resize:function(){var b=this,a=this.s.dt,d=c(l).width(),e=this.c.breakpoints,
17
+ f=e[0].name,g=this.s.columns,h,j=this.s.current.slice();for(h=e.length-1;0<=h;h--)if(d<=e[h].width){f=e[h].name;break}var i=this._columnsVisiblity(f);this.s.current=i;e=!1;h=0;for(d=g.length;h<d;h++)if(!1===i[h]&&!g[h].never&&!g[h].control){e=!0;break}c(a.table().node()).toggleClass("collapsed",e);var k=!1;a.columns().eq(0).each(function(a,c){i[c]!==j[c]&&(k=!0,b._setColumnVis(a,i[c]))});k&&(this._redrawChildren(),c(a.table().node()).trigger("responsive-resize.dt",[a,this.s.current]))},_resizeAuto:function(){var b=
18
+ this.s.dt,a=this.s.columns;if(this.c.auto&&-1!==c.inArray(!0,c.map(a,function(b){return b.auto}))){b.table().node();var d=b.table().node().cloneNode(!1),e=c(b.table().header().cloneNode(!1)).appendTo(d),f=c(b.table().body()).clone(!1,!1).empty().appendTo(d),g=b.columns().header().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell");c(f).append(c(b.rows({page:"current"}).nodes()).clone(!1)).find("th, td").css("display","");if(f=b.table().footer()){var f=c(f.cloneNode(!1)).appendTo(d),
19
+ h=b.columns().footer().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell");c("<tr/>").append(h).appendTo(f)}c("<tr/>").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("<div/>").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b,
20
+ a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex",
21
+ d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&&
22
+ b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('<div class="dtr-modal"/>').append(c('<div class="dtr-modal-display"/>').append(c('<div class="dtr-modal-content"/>').append(e())).append(c('<div class="dtr-modal-close">&times;</div>').click(function(){f()}))).append(c('<div class="dtr-modal-background"/>').click(function(){f()})).appendTo("body");
23
+ c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend("<h2>"+b.header(a)+"</h2>")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'<li data-dtr-index="'+a.columnIndex+'" data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><span class="dtr-title">'+a.title+'</span> <span class="dtr-data">'+a.data+"</span></li>":""}).join(""))?c('<ul data-dtr-index="'+a+'" class="dtr-details"/>').append(b):
24
+ !1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'<tr data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><td>'+a.title+":</td> <td>"+a.data+"</td></tr>"}).join("");return c('<table class="'+b.tableClass+' dtr-details" width="100%"/>').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api;
25
+ o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b=
26
+ this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j});
admin/datatables/js/datatables-all.js ADDED
@@ -0,0 +1,17649 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.16
2
+ * 2008-2017 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary DataTables
7
+ * @description Paginate, search and order HTML tables
8
+ * @version 1.10.16
9
+ * @file jquery.dataTables.js
10
+ * @author SpryMedia Ltd
11
+ * @contact www.datatables.net
12
+ * @copyright Copyright 2008-2017 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,_fnInvalidate,_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,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
+
27
+ (function( factory ) {
28
+ "use strict";
29
+
30
+ if ( typeof define === 'function' && define.amd ) {
31
+ // AMD
32
+ define( ['jquery'], function ( $ ) {
33
+ return factory( $, window, document );
34
+ } );
35
+ }
36
+ else if ( typeof exports === 'object' ) {
37
+ // CommonJS
38
+ module.exports = function (root, $) {
39
+ if ( ! root ) {
40
+ // CommonJS environments without a window global must pass a
41
+ // root. This will give an error otherwise
42
+ root = window;
43
+ }
44
+
45
+ if ( ! $ ) {
46
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
47
+ require('jquery') :
48
+ require('jquery')( root );
49
+ }
50
+
51
+ return factory( $, root, root.document );
52
+ };
53
+ }
54
+ else {
55
+ // Browser
56
+ factory( jQuery, window, document );
57
+ }
58
+ }
59
+ (function( $, window, document, undefined ) {
60
+ "use strict";
61
+
62
+ /**
63
+ * DataTables is a plug-in for the jQuery Javascript library. It is a highly
64
+ * flexible tool, based upon the foundations of progressive enhancement,
65
+ * which will add advanced interaction controls to any HTML table. For a
66
+ * full list of features please refer to
67
+ * [DataTables.net](href="http://datatables.net).
68
+ *
69
+ * Note that the `DataTable` object is not a global variable but is aliased
70
+ * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
71
+ * be accessed.
72
+ *
73
+ * @class
74
+ * @param {object} [init={}] Configuration object for DataTables. Options
75
+ * are defined by {@link DataTable.defaults}
76
+ * @requires jQuery 1.7+
77
+ *
78
+ * @example
79
+ * // Basic initialisation
80
+ * $(document).ready( function {
81
+ * $('#example').dataTable();
82
+ * } );
83
+ *
84
+ * @example
85
+ * // Initialisation with configuration options - in this case, disable
86
+ * // pagination and sorting.
87
+ * $(document).ready( function {
88
+ * $('#example').dataTable( {
89
+ * "paginate": false,
90
+ * "sort": false
91
+ * } );
92
+ * } );
93
+ */
94
+ var DataTable = function ( options )
95
+ {
96
+ /**
97
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
98
+ * return the resulting jQuery object.
99
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
100
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
101
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
102
+ * criterion ("applied") or all TR elements (i.e. no filter).
103
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
104
+ * Can be either 'current', whereby the current sorting of the table is used, or
105
+ * 'original' whereby the original order the data was read into the table is used.
106
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
107
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
108
+ * 'current' and filter is 'applied', regardless of what they might be given as.
109
+ * @returns {object} jQuery object, filtered by the given selector.
110
+ * @dtopt API
111
+ * @deprecated Since v1.10
112
+ *
113
+ * @example
114
+ * $(document).ready(function() {
115
+ * var oTable = $('#example').dataTable();
116
+ *
117
+ * // Highlight every second row
118
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
119
+ * } );
120
+ *
121
+ * @example
122
+ * $(document).ready(function() {
123
+ * var oTable = $('#example').dataTable();
124
+ *
125
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
126
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
127
+ * oTable.fnFilter('Webkit');
128
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
129
+ * oTable.fnFilter('');
130
+ * } );
131
+ */
132
+ this.$ = function ( sSelector, oOpts )
133
+ {
134
+ return this.api(true).$( sSelector, oOpts );
135
+ };
136
+
137
+
138
+ /**
139
+ * Almost identical to $ in operation, but in this case returns the data for the matched
140
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
141
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
142
+ * rows are found, the data returned is the original data array/object that was used to
143
+ * create the row (or a generated array if from a DOM source).
144
+ *
145
+ * This method is often useful in-combination with $ where both functions are given the
146
+ * same parameters and the array indexes will match identically.
147
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
148
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
149
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
150
+ * criterion ("applied") or all elements (i.e. no filter).
151
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
152
+ * Can be either 'current', whereby the current sorting of the table is used, or
153
+ * 'original' whereby the original order the data was read into the table is used.
154
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
155
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
156
+ * 'current' and filter is 'applied', regardless of what they might be given as.
157
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
158
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
159
+ * entry in the array.
160
+ * @dtopt API
161
+ * @deprecated Since v1.10
162
+ *
163
+ * @example
164
+ * $(document).ready(function() {
165
+ * var oTable = $('#example').dataTable();
166
+ *
167
+ * // Get the data from the first row in the table
168
+ * var data = oTable._('tr:first');
169
+ *
170
+ * // Do something useful with the data
171
+ * alert( "First cell is: "+data[0] );
172
+ * } );
173
+ *
174
+ * @example
175
+ * $(document).ready(function() {
176
+ * var oTable = $('#example').dataTable();
177
+ *
178
+ * // Filter to 'Webkit' and get all data for
179
+ * oTable.fnFilter('Webkit');
180
+ * var data = oTable._('tr', {"search": "applied"});
181
+ *
182
+ * // Do something with the data
183
+ * alert( data.length+" rows matched the search" );
184
+ * } );
185
+ */
186
+ this._ = function ( sSelector, oOpts )
187
+ {
188
+ return this.api(true).rows( sSelector, oOpts ).data();
189
+ };
190
+
191
+
192
+ /**
193
+ * Create a DataTables Api instance, with the currently selected tables for
194
+ * the Api's context.
195
+ * @param {boolean} [traditional=false] Set the API instance's context to be
196
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
197
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
198
+ * or if all tables captured in the jQuery object should be used.
199
+ * @return {DataTables.Api}
200
+ */
201
+ this.api = function ( traditional )
202
+ {
203
+ return traditional ?
204
+ new _Api(
205
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
206
+ ) :
207
+ new _Api( this );
208
+ };
209
+
210
+
211
+ /**
212
+ * Add a single new row or multiple rows of data to the table. Please note
213
+ * that this is suitable for client-side processing only - if you are using
214
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
215
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
216
+ * @param {array|object} data The data to be added to the table. This can be:
217
+ * <ul>
218
+ * <li>1D array of data - add a single row with the data provided</li>
219
+ * <li>2D array of arrays - add multiple rows in a single call</li>
220
+ * <li>object - data object when using <i>mData</i></li>
221
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
222
+ * </ul>
223
+ * @param {bool} [redraw=true] redraw the table or not
224
+ * @returns {array} An array of integers, representing the list of indexes in
225
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
226
+ * the table.
227
+ * @dtopt API
228
+ * @deprecated Since v1.10
229
+ *
230
+ * @example
231
+ * // Global var for counter
232
+ * var giCount = 2;
233
+ *
234
+ * $(document).ready(function() {
235
+ * $('#example').dataTable();
236
+ * } );
237
+ *
238
+ * function fnClickAddRow() {
239
+ * $('#example').dataTable().fnAddData( [
240
+ * giCount+".1",
241
+ * giCount+".2",
242
+ * giCount+".3",
243
+ * giCount+".4" ]
244
+ * );
245
+ *
246
+ * giCount++;
247
+ * }
248
+ */
249
+ this.fnAddData = function( data, redraw )
250
+ {
251
+ var api = this.api( true );
252
+
253
+ /* Check if we want to add multiple rows or not */
254
+ var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
255
+ api.rows.add( data ) :
256
+ api.row.add( data );
257
+
258
+ if ( redraw === undefined || redraw ) {
259
+ api.draw();
260
+ }
261
+
262
+ return rows.flatten().toArray();
263
+ };
264
+
265
+
266
+ /**
267
+ * This function will make DataTables recalculate the column sizes, based on the data
268
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
269
+ * through the sWidth parameter). This can be useful when the width of the table's
270
+ * parent element changes (for example a window resize).
271
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
272
+ * @dtopt API
273
+ * @deprecated Since v1.10
274
+ *
275
+ * @example
276
+ * $(document).ready(function() {
277
+ * var oTable = $('#example').dataTable( {
278
+ * "sScrollY": "200px",
279
+ * "bPaginate": false
280
+ * } );
281
+ *
282
+ * $(window).on('resize', function () {
283
+ * oTable.fnAdjustColumnSizing();
284
+ * } );
285
+ * } );
286
+ */
287
+ this.fnAdjustColumnSizing = function ( bRedraw )
288
+ {
289
+ var api = this.api( true ).columns.adjust();
290
+ var settings = api.settings()[0];
291
+ var scroll = settings.oScroll;
292
+
293
+ if ( bRedraw === undefined || bRedraw ) {
294
+ api.draw( false );
295
+ }
296
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
297
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
298
+ _fnScrollDraw( settings );
299
+ }
300
+ };
301
+
302
+
303
+ /**
304
+ * Quickly and simply clear a table
305
+ * @param {bool} [bRedraw=true] redraw the table or not
306
+ * @dtopt API
307
+ * @deprecated Since v1.10
308
+ *
309
+ * @example
310
+ * $(document).ready(function() {
311
+ * var oTable = $('#example').dataTable();
312
+ *
313
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
314
+ * oTable.fnClearTable();
315
+ * } );
316
+ */
317
+ this.fnClearTable = function( bRedraw )
318
+ {
319
+ var api = this.api( true ).clear();
320
+
321
+ if ( bRedraw === undefined || bRedraw ) {
322
+ api.draw();
323
+ }
324
+ };
325
+
326
+
327
+ /**
328
+ * The exact opposite of 'opening' a row, this function will close any rows which
329
+ * are currently 'open'.
330
+ * @param {node} nTr the table row to 'close'
331
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
332
+ * @dtopt API
333
+ * @deprecated Since v1.10
334
+ *
335
+ * @example
336
+ * $(document).ready(function() {
337
+ * var oTable;
338
+ *
339
+ * // 'open' an information row when a row is clicked on
340
+ * $('#example tbody tr').click( function () {
341
+ * if ( oTable.fnIsOpen(this) ) {
342
+ * oTable.fnClose( this );
343
+ * } else {
344
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
345
+ * }
346
+ * } );
347
+ *
348
+ * oTable = $('#example').dataTable();
349
+ * } );
350
+ */
351
+ this.fnClose = function( nTr )
352
+ {
353
+ this.api( true ).row( nTr ).child.hide();
354
+ };
355
+
356
+
357
+ /**
358
+ * Remove a row for the table
359
+ * @param {mixed} target The index of the row from aoData to be deleted, or
360
+ * the TR element you want to delete
361
+ * @param {function|null} [callBack] Callback function
362
+ * @param {bool} [redraw=true] Redraw the table or not
363
+ * @returns {array} The row that was deleted
364
+ * @dtopt API
365
+ * @deprecated Since v1.10
366
+ *
367
+ * @example
368
+ * $(document).ready(function() {
369
+ * var oTable = $('#example').dataTable();
370
+ *
371
+ * // Immediately remove the first row
372
+ * oTable.fnDeleteRow( 0 );
373
+ * } );
374
+ */
375
+ this.fnDeleteRow = function( target, callback, redraw )
376
+ {
377
+ var api = this.api( true );
378
+ var rows = api.rows( target );
379
+ var settings = rows.settings()[0];
380
+ var data = settings.aoData[ rows[0][0] ];
381
+
382
+ rows.remove();
383
+
384
+ if ( callback ) {
385
+ callback.call( this, settings, data );
386
+ }
387
+
388
+ if ( redraw === undefined || redraw ) {
389
+ api.draw();
390
+ }
391
+
392
+ return data;
393
+ };
394
+
395
+
396
+ /**
397
+ * Restore the table to it's original state in the DOM by removing all of DataTables
398
+ * enhancements, alterations to the DOM structure of the table and event listeners.
399
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
400
+ * @dtopt API
401
+ * @deprecated Since v1.10
402
+ *
403
+ * @example
404
+ * $(document).ready(function() {
405
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
406
+ * var oTable = $('#example').dataTable();
407
+ * oTable.fnDestroy();
408
+ * } );
409
+ */
410
+ this.fnDestroy = function ( remove )
411
+ {
412
+ this.api( true ).destroy( remove );
413
+ };
414
+
415
+
416
+ /**
417
+ * Redraw the table
418
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
419
+ * @dtopt API
420
+ * @deprecated Since v1.10
421
+ *
422
+ * @example
423
+ * $(document).ready(function() {
424
+ * var oTable = $('#example').dataTable();
425
+ *
426
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
427
+ * oTable.fnDraw();
428
+ * } );
429
+ */
430
+ this.fnDraw = function( complete )
431
+ {
432
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
433
+ // into account the new data, but can hold position.
434
+ this.api( true ).draw( complete );
435
+ };
436
+
437
+
438
+ /**
439
+ * Filter the input based on data
440
+ * @param {string} sInput String to filter the table on
441
+ * @param {int|null} [iColumn] Column to limit filtering to
442
+ * @param {bool} [bRegex=false] Treat as regular expression or not
443
+ * @param {bool} [bSmart=true] Perform smart filtering or not
444
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
445
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
446
+ * @dtopt API
447
+ * @deprecated Since v1.10
448
+ *
449
+ * @example
450
+ * $(document).ready(function() {
451
+ * var oTable = $('#example').dataTable();
452
+ *
453
+ * // Sometime later - filter...
454
+ * oTable.fnFilter( 'test string' );
455
+ * } );
456
+ */
457
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
458
+ {
459
+ var api = this.api( true );
460
+
461
+ if ( iColumn === null || iColumn === undefined ) {
462
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
463
+ }
464
+ else {
465
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
466
+ }
467
+
468
+ api.draw();
469
+ };
470
+
471
+
472
+ /**
473
+ * Get the data for the whole table, an individual row or an individual cell based on the
474
+ * provided parameters.
475
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
476
+ * a TR node then the data source for the whole row will be returned. If given as a
477
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
478
+ * cell returned. If given as an integer, then this is treated as the aoData internal
479
+ * data index for the row (see fnGetPosition) and the data for that row used.
480
+ * @param {int} [col] Optional column index that you want the data of.
481
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
482
+ * returned. If mRow is defined, just data for that row, and is iCol is
483
+ * defined, only data for the designated cell is returned.
484
+ * @dtopt API
485
+ * @deprecated Since v1.10
486
+ *
487
+ * @example
488
+ * // Row data
489
+ * $(document).ready(function() {
490
+ * oTable = $('#example').dataTable();
491
+ *
492
+ * oTable.$('tr').click( function () {
493
+ * var data = oTable.fnGetData( this );
494
+ * // ... do something with the array / object of data for the row
495
+ * } );
496
+ * } );
497
+ *
498
+ * @example
499
+ * // Individual cell data
500
+ * $(document).ready(function() {
501
+ * oTable = $('#example').dataTable();
502
+ *
503
+ * oTable.$('td').click( function () {
504
+ * var sData = oTable.fnGetData( this );
505
+ * alert( 'The cell clicked on had the value of '+sData );
506
+ * } );
507
+ * } );
508
+ */
509
+ this.fnGetData = function( src, col )
510
+ {
511
+ var api = this.api( true );
512
+
513
+ if ( src !== undefined ) {
514
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
515
+
516
+ return col !== undefined || type == 'td' || type == 'th' ?
517
+ api.cell( src, col ).data() :
518
+ api.row( src ).data() || null;
519
+ }
520
+
521
+ return api.data().toArray();
522
+ };
523
+
524
+
525
+ /**
526
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
527
+ * typically want to use the '$' API method in preference to this as it is more
528
+ * flexible.
529
+ * @param {int} [iRow] Optional row index for the TR element you want
530
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
531
+ * in the table's body, or iRow is defined, just the TR element requested.
532
+ * @dtopt API
533
+ * @deprecated Since v1.10
534
+ *
535
+ * @example
536
+ * $(document).ready(function() {
537
+ * var oTable = $('#example').dataTable();
538
+ *
539
+ * // Get the nodes from the table
540
+ * var nNodes = oTable.fnGetNodes( );
541
+ * } );
542
+ */
543
+ this.fnGetNodes = function( iRow )
544
+ {
545
+ var api = this.api( true );
546
+
547
+ return iRow !== undefined ?
548
+ api.row( iRow ).node() :
549
+ api.rows().nodes().flatten().toArray();
550
+ };
551
+
552
+
553
+ /**
554
+ * Get the array indexes of a particular cell from it's DOM element
555
+ * and column index including hidden columns
556
+ * @param {node} node this can either be a TR, TD or TH in the table's body
557
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
558
+ * if given as a cell, an array of [row index, column index (visible),
559
+ * column index (all)] is given.
560
+ * @dtopt API
561
+ * @deprecated Since v1.10
562
+ *
563
+ * @example
564
+ * $(document).ready(function() {
565
+ * $('#example tbody td').click( function () {
566
+ * // Get the position of the current data from the node
567
+ * var aPos = oTable.fnGetPosition( this );
568
+ *
569
+ * // Get the data array for this row
570
+ * var aData = oTable.fnGetData( aPos[0] );
571
+ *
572
+ * // Update the data array and return the value
573
+ * aData[ aPos[1] ] = 'clicked';
574
+ * this.innerHTML = 'clicked';
575
+ * } );
576
+ *
577
+ * // Init DataTables
578
+ * oTable = $('#example').dataTable();
579
+ * } );
580
+ */
581
+ this.fnGetPosition = function( node )
582
+ {
583
+ var api = this.api( true );
584
+ var nodeName = node.nodeName.toUpperCase();
585
+
586
+ if ( nodeName == 'TR' ) {
587
+ return api.row( node ).index();
588
+ }
589
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
590
+ var cell = api.cell( node ).index();
591
+
592
+ return [
593
+ cell.row,
594
+ cell.columnVisible,
595
+ cell.column
596
+ ];
597
+ }
598
+ return null;
599
+ };
600
+
601
+
602
+ /**
603
+ * Check to see if a row is 'open' or not.
604
+ * @param {node} nTr the table row to check
605
+ * @returns {boolean} true if the row is currently open, false otherwise
606
+ * @dtopt API
607
+ * @deprecated Since v1.10
608
+ *
609
+ * @example
610
+ * $(document).ready(function() {
611
+ * var oTable;
612
+ *
613
+ * // 'open' an information row when a row is clicked on
614
+ * $('#example tbody tr').click( function () {
615
+ * if ( oTable.fnIsOpen(this) ) {
616
+ * oTable.fnClose( this );
617
+ * } else {
618
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
619
+ * }
620
+ * } );
621
+ *
622
+ * oTable = $('#example').dataTable();
623
+ * } );
624
+ */
625
+ this.fnIsOpen = function( nTr )
626
+ {
627
+ return this.api( true ).row( nTr ).child.isShown();
628
+ };
629
+
630
+
631
+ /**
632
+ * This function will place a new row directly after a row which is currently
633
+ * on display on the page, with the HTML contents that is passed into the
634
+ * function. This can be used, for example, to ask for confirmation that a
635
+ * particular record should be deleted.
636
+ * @param {node} nTr The table row to 'open'
637
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
638
+ * @param {string} sClass Class to give the new TD cell
639
+ * @returns {node} The row opened. Note that if the table row passed in as the
640
+ * first parameter, is not found in the table, this method will silently
641
+ * return.
642
+ * @dtopt API
643
+ * @deprecated Since v1.10
644
+ *
645
+ * @example
646
+ * $(document).ready(function() {
647
+ * var oTable;
648
+ *
649
+ * // 'open' an information row when a row is clicked on
650
+ * $('#example tbody tr').click( function () {
651
+ * if ( oTable.fnIsOpen(this) ) {
652
+ * oTable.fnClose( this );
653
+ * } else {
654
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
655
+ * }
656
+ * } );
657
+ *
658
+ * oTable = $('#example').dataTable();
659
+ * } );
660
+ */
661
+ this.fnOpen = function( nTr, mHtml, sClass )
662
+ {
663
+ return this.api( true )
664
+ .row( nTr )
665
+ .child( mHtml, sClass )
666
+ .show()
667
+ .child()[0];
668
+ };
669
+
670
+
671
+ /**
672
+ * Change the pagination - provides the internal logic for pagination in a simple API
673
+ * function. With this function you can have a DataTables table go to the next,
674
+ * previous, first or last pages.
675
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
676
+ * or page number to jump to (integer), note that page 0 is the first page.
677
+ * @param {bool} [bRedraw=true] Redraw the table or not
678
+ * @dtopt API
679
+ * @deprecated Since v1.10
680
+ *
681
+ * @example
682
+ * $(document).ready(function() {
683
+ * var oTable = $('#example').dataTable();
684
+ * oTable.fnPageChange( 'next' );
685
+ * } );
686
+ */
687
+ this.fnPageChange = function ( mAction, bRedraw )
688
+ {
689
+ var api = this.api( true ).page( mAction );
690
+
691
+ if ( bRedraw === undefined || bRedraw ) {
692
+ api.draw(false);
693
+ }
694
+ };
695
+
696
+
697
+ /**
698
+ * Show a particular column
699
+ * @param {int} iCol The column whose display should be changed
700
+ * @param {bool} bShow Show (true) or hide (false) the column
701
+ * @param {bool} [bRedraw=true] Redraw the table or not
702
+ * @dtopt API
703
+ * @deprecated Since v1.10
704
+ *
705
+ * @example
706
+ * $(document).ready(function() {
707
+ * var oTable = $('#example').dataTable();
708
+ *
709
+ * // Hide the second column after initialisation
710
+ * oTable.fnSetColumnVis( 1, false );
711
+ * } );
712
+ */
713
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
714
+ {
715
+ var api = this.api( true ).column( iCol ).visible( bShow );
716
+
717
+ if ( bRedraw === undefined || bRedraw ) {
718
+ api.columns.adjust().draw();
719
+ }
720
+ };
721
+
722
+
723
+ /**
724
+ * Get the settings for a particular table for external manipulation
725
+ * @returns {object} DataTables settings object. See
726
+ * {@link DataTable.models.oSettings}
727
+ * @dtopt API
728
+ * @deprecated Since v1.10
729
+ *
730
+ * @example
731
+ * $(document).ready(function() {
732
+ * var oTable = $('#example').dataTable();
733
+ * var oSettings = oTable.fnSettings();
734
+ *
735
+ * // Show an example parameter from the settings
736
+ * alert( oSettings._iDisplayStart );
737
+ * } );
738
+ */
739
+ this.fnSettings = function()
740
+ {
741
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
742
+ };
743
+
744
+
745
+ /**
746
+ * Sort the table by a particular column
747
+ * @param {int} iCol the data index to sort on. Note that this will not match the
748
+ * 'display index' if you have hidden data entries
749
+ * @dtopt API
750
+ * @deprecated Since v1.10
751
+ *
752
+ * @example
753
+ * $(document).ready(function() {
754
+ * var oTable = $('#example').dataTable();
755
+ *
756
+ * // Sort immediately with columns 0 and 1
757
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
758
+ * } );
759
+ */
760
+ this.fnSort = function( aaSort )
761
+ {
762
+ this.api( true ).order( aaSort ).draw();
763
+ };
764
+
765
+
766
+ /**
767
+ * Attach a sort listener to an element for a given column
768
+ * @param {node} nNode the element to attach the sort listener to
769
+ * @param {int} iColumn the column that a click on this node will sort on
770
+ * @param {function} [fnCallback] callback function when sort is run
771
+ * @dtopt API
772
+ * @deprecated Since v1.10
773
+ *
774
+ * @example
775
+ * $(document).ready(function() {
776
+ * var oTable = $('#example').dataTable();
777
+ *
778
+ * // Sort on column 1, when 'sorter' is clicked on
779
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
780
+ * } );
781
+ */
782
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
783
+ {
784
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
785
+ };
786
+
787
+
788
+ /**
789
+ * Update a table cell or row - this method will accept either a single value to
790
+ * update the cell with, an array of values with one element for each column or
791
+ * an object in the same format as the original data source. The function is
792
+ * self-referencing in order to make the multi column updates easier.
793
+ * @param {object|array|string} mData Data to update the cell/row with
794
+ * @param {node|int} mRow TR element you want to update or the aoData index
795
+ * @param {int} [iColumn] The column to update, give as null or undefined to
796
+ * update a whole row.
797
+ * @param {bool} [bRedraw=true] Redraw the table or not
798
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
799
+ * @returns {int} 0 on success, 1 on error
800
+ * @dtopt API
801
+ * @deprecated Since v1.10
802
+ *
803
+ * @example
804
+ * $(document).ready(function() {
805
+ * var oTable = $('#example').dataTable();
806
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
807
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
808
+ * } );
809
+ */
810
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
811
+ {
812
+ var api = this.api( true );
813
+
814
+ if ( iColumn === undefined || iColumn === null ) {
815
+ api.row( mRow ).data( mData );
816
+ }
817
+ else {
818
+ api.cell( mRow, iColumn ).data( mData );
819
+ }
820
+
821
+ if ( bAction === undefined || bAction ) {
822
+ api.columns.adjust();
823
+ }
824
+
825
+ if ( bRedraw === undefined || bRedraw ) {
826
+ api.draw();
827
+ }
828
+ return 0;
829
+ };
830
+
831
+
832
+ /**
833
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
834
+ * to ensure compatibility.
835
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
836
+ * formats "X" and "X.Y" are also acceptable.
837
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
838
+ * version, or false if this version of DataTales is not suitable
839
+ * @method
840
+ * @dtopt API
841
+ * @deprecated Since v1.10
842
+ *
843
+ * @example
844
+ * $(document).ready(function() {
845
+ * var oTable = $('#example').dataTable();
846
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
847
+ * } );
848
+ */
849
+ this.fnVersionCheck = _ext.fnVersionCheck;
850
+
851
+
852
+ var _that = this;
853
+ var emptyInit = options === undefined;
854
+ var len = this.length;
855
+
856
+ if ( emptyInit ) {
857
+ options = {};
858
+ }
859
+
860
+ this.oApi = this.internal = _ext.internal;
861
+
862
+ // Extend with old style plug-in API methods
863
+ for ( var fn in DataTable.ext.internal ) {
864
+ if ( fn ) {
865
+ this[fn] = _fnExternApiFunc(fn);
866
+ }
867
+ }
868
+
869
+ this.each(function() {
870
+ // For each initialisation we want to give it a clean initialisation
871
+ // object that can be bashed around
872
+ var o = {};
873
+ var oInit = len > 1 ? // optimisation for single table case
874
+ _fnExtend( o, options, true ) :
875
+ options;
876
+
877
+ /*global oInit,_that,emptyInit*/
878
+ var i=0, iLen, j, jLen, k, kLen;
879
+ var sId = this.getAttribute( 'id' );
880
+ var bInitHandedOff = false;
881
+ var defaults = DataTable.defaults;
882
+ var $this = $(this);
883
+
884
+
885
+ /* Sanity check */
886
+ if ( this.nodeName.toLowerCase() != 'table' )
887
+ {
888
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
889
+ return;
890
+ }
891
+
892
+ /* Backwards compatibility for the defaults */
893
+ _fnCompatOpts( defaults );
894
+ _fnCompatCols( defaults.column );
895
+
896
+ /* Convert the camel-case defaults to Hungarian */
897
+ _fnCamelToHungarian( defaults, defaults, true );
898
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
899
+
900
+ /* Setting up the initialisation object */
901
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
902
+
903
+
904
+
905
+ /* Check to see if we are re-initialising a table */
906
+ var allSettings = DataTable.settings;
907
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
908
+ {
909
+ var s = allSettings[i];
910
+
911
+ /* Base check on table node */
912
+ if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
913
+ {
914
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
915
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
916
+
917
+ if ( emptyInit || bRetrieve )
918
+ {
919
+ return s.oInstance;
920
+ }
921
+ else if ( bDestroy )
922
+ {
923
+ s.oInstance.fnDestroy();
924
+ break;
925
+ }
926
+ else
927
+ {
928
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
929
+ return;
930
+ }
931
+ }
932
+
933
+ /* If the element we are initialising has the same ID as a table which was previously
934
+ * initialised, but the table nodes don't match (from before) then we destroy the old
935
+ * instance by simply deleting it. This is under the assumption that the table has been
936
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
937
+ */
938
+ if ( s.sTableId == this.id )
939
+ {
940
+ allSettings.splice( i, 1 );
941
+ break;
942
+ }
943
+ }
944
+
945
+ /* Ensure the table has an ID - required for accessibility */
946
+ if ( sId === null || sId === "" )
947
+ {
948
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
949
+ this.id = sId;
950
+ }
951
+
952
+ /* Create the settings object for this table and set some of the default parameters */
953
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
954
+ "sDestroyWidth": $this[0].style.width,
955
+ "sInstance": sId,
956
+ "sTableId": sId
957
+ } );
958
+ oSettings.nTable = this;
959
+ oSettings.oApi = _that.internal;
960
+ oSettings.oInit = oInit;
961
+
962
+ allSettings.push( oSettings );
963
+
964
+ // Need to add the instance after the instance after the settings object has been added
965
+ // to the settings array, so we can self reference the table instance if more than one
966
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
967
+
968
+ // Backwards compatibility, before we apply all the defaults
969
+ _fnCompatOpts( oInit );
970
+
971
+ if ( oInit.oLanguage )
972
+ {
973
+ _fnLanguageCompat( oInit.oLanguage );
974
+ }
975
+
976
+ // If the length menu is given, but the init display length is not, use the length menu
977
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
978
+ {
979
+ oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
980
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
981
+ }
982
+
983
+ // Apply the defaults and init options to make a single init object will all
984
+ // options defined from defaults and instance options.
985
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
986
+
987
+
988
+ // Map the initialisation options onto the settings object
989
+ _fnMap( oSettings.oFeatures, oInit, [
990
+ "bPaginate",
991
+ "bLengthChange",
992
+ "bFilter",
993
+ "bSort",
994
+ "bSortMulti",
995
+ "bInfo",
996
+ "bProcessing",
997
+ "bAutoWidth",
998
+ "bSortClasses",
999
+ "bServerSide",
1000
+ "bDeferRender"
1001
+ ] );
1002
+ _fnMap( oSettings, oInit, [
1003
+ "asStripeClasses",
1004
+ "ajax",
1005
+ "fnServerData",
1006
+ "fnFormatNumber",
1007
+ "sServerMethod",
1008
+ "aaSorting",
1009
+ "aaSortingFixed",
1010
+ "aLengthMenu",
1011
+ "sPaginationType",
1012
+ "sAjaxSource",
1013
+ "sAjaxDataProp",
1014
+ "iStateDuration",
1015
+ "sDom",
1016
+ "bSortCellsTop",
1017
+ "iTabIndex",
1018
+ "fnStateLoadCallback",
1019
+ "fnStateSaveCallback",
1020
+ "renderer",
1021
+ "searchDelay",
1022
+ "rowId",
1023
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
1024
+ [ "oSearch", "oPreviousSearch" ],
1025
+ [ "aoSearchCols", "aoPreSearchCols" ],
1026
+ [ "iDisplayLength", "_iDisplayLength" ]
1027
+ ] );
1028
+ _fnMap( oSettings.oScroll, oInit, [
1029
+ [ "sScrollX", "sX" ],
1030
+ [ "sScrollXInner", "sXInner" ],
1031
+ [ "sScrollY", "sY" ],
1032
+ [ "bScrollCollapse", "bCollapse" ]
1033
+ ] );
1034
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1035
+
1036
+ /* Callback functions which are array driven */
1037
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1038
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1039
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1040
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1041
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1042
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1043
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1044
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1045
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1046
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1047
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1048
+
1049
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1050
+
1051
+ /* Browser support detection */
1052
+ _fnBrowserDetect( oSettings );
1053
+
1054
+ var oClasses = oSettings.oClasses;
1055
+
1056
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1057
+ $this.addClass( oClasses.sTable );
1058
+
1059
+
1060
+ if ( oSettings.iInitDisplayStart === undefined )
1061
+ {
1062
+ /* Display start point, taking into account the save saving */
1063
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
1064
+ oSettings._iDisplayStart = oInit.iDisplayStart;
1065
+ }
1066
+
1067
+ if ( oInit.iDeferLoading !== null )
1068
+ {
1069
+ oSettings.bDeferLoading = true;
1070
+ var tmp = $.isArray( oInit.iDeferLoading );
1071
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1072
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1073
+ }
1074
+
1075
+ /* Language definitions */
1076
+ var oLanguage = oSettings.oLanguage;
1077
+ $.extend( true, oLanguage, oInit.oLanguage );
1078
+
1079
+ if ( oLanguage.sUrl )
1080
+ {
1081
+ /* Get the language definitions from a file - because this Ajax call makes the language
1082
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
1083
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1084
+ */
1085
+ $.ajax( {
1086
+ dataType: 'json',
1087
+ url: oLanguage.sUrl,
1088
+ success: function ( json ) {
1089
+ _fnLanguageCompat( json );
1090
+ _fnCamelToHungarian( defaults.oLanguage, json );
1091
+ $.extend( true, oLanguage, json );
1092
+ _fnInitialise( oSettings );
1093
+ },
1094
+ error: function () {
1095
+ // Error occurred loading language file, continue on as best we can
1096
+ _fnInitialise( oSettings );
1097
+ }
1098
+ } );
1099
+ bInitHandedOff = true;
1100
+ }
1101
+
1102
+ /*
1103
+ * Stripes
1104
+ */
1105
+ if ( oInit.asStripeClasses === null )
1106
+ {
1107
+ oSettings.asStripeClasses =[
1108
+ oClasses.sStripeOdd,
1109
+ oClasses.sStripeEven
1110
+ ];
1111
+ }
1112
+
1113
+ /* Remove row stripe classes if they are already on the table row */
1114
+ var stripeClasses = oSettings.asStripeClasses;
1115
+ var rowOne = $this.children('tbody').find('tr').eq(0);
1116
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1117
+ return rowOne.hasClass(el);
1118
+ } ) ) !== -1 ) {
1119
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1120
+ oSettings.asDestroyStripes = stripeClasses.slice();
1121
+ }
1122
+
1123
+ /*
1124
+ * Columns
1125
+ * See if we should load columns automatically or use defined ones
1126
+ */
1127
+ var anThs = [];
1128
+ var aoColumnsInit;
1129
+ var nThead = this.getElementsByTagName('thead');
1130
+ if ( nThead.length !== 0 )
1131
+ {
1132
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1133
+ anThs = _fnGetUniqueThs( oSettings );
1134
+ }
1135
+
1136
+ /* If not given a column array, generate one with nulls */
1137
+ if ( oInit.aoColumns === null )
1138
+ {
1139
+ aoColumnsInit = [];
1140
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1141
+ {
1142
+ aoColumnsInit.push( null );
1143
+ }
1144
+ }
1145
+ else
1146
+ {
1147
+ aoColumnsInit = oInit.aoColumns;
1148
+ }
1149
+
1150
+ /* Add the columns */
1151
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1152
+ {
1153
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1154
+ }
1155
+
1156
+ /* Apply the column definitions */
1157
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1158
+ _fnColumnOptions( oSettings, iCol, oDef );
1159
+ } );
1160
+
1161
+ /* HTML5 attribute detection - build an mData object automatically if the
1162
+ * attributes are found
1163
+ */
1164
+ if ( rowOne.length ) {
1165
+ var a = function ( cell, name ) {
1166
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1167
+ };
1168
+
1169
+ $( rowOne[0] ).children('th, td').each( function (i, cell) {
1170
+ var col = oSettings.aoColumns[i];
1171
+
1172
+ if ( col.mData === i ) {
1173
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
1174
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
1175
+
1176
+ if ( sort !== null || filter !== null ) {
1177
+ col.mData = {
1178
+ _: i+'.display',
1179
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
1180
+ type: sort !== null ? i+'.@data-'+sort : undefined,
1181
+ filter: filter !== null ? i+'.@data-'+filter : undefined
1182
+ };
1183
+
1184
+ _fnColumnOptions( oSettings, i );
1185
+ }
1186
+ }
1187
+ } );
1188
+ }
1189
+
1190
+ var features = oSettings.oFeatures;
1191
+ var loadedInit = function () {
1192
+ /*
1193
+ * Sorting
1194
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
1195
+ */
1196
+
1197
+ // If aaSorting is not defined, then we use the first indicator in asSorting
1198
+ // in case that has been altered, so the default sort reflects that option
1199
+ if ( oInit.aaSorting === undefined ) {
1200
+ var sorting = oSettings.aaSorting;
1201
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1202
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1203
+ }
1204
+ }
1205
+
1206
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
1207
+ * account, and also will apply sorting disabled classes if disabled
1208
+ */
1209
+ _fnSortingClasses( oSettings );
1210
+
1211
+ if ( features.bSort ) {
1212
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1213
+ if ( oSettings.bSorted ) {
1214
+ var aSort = _fnSortFlatten( oSettings );
1215
+ var sortedColumns = {};
1216
+
1217
+ $.each( aSort, function (i, val) {
1218
+ sortedColumns[ val.src ] = val.dir;
1219
+ } );
1220
+
1221
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1222
+ _fnSortAria( oSettings );
1223
+ }
1224
+ } );
1225
+ }
1226
+
1227
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1228
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1229
+ _fnSortingClasses( oSettings );
1230
+ }
1231
+ }, 'sc' );
1232
+
1233
+
1234
+ /*
1235
+ * Final init
1236
+ * Cache the header, body and footer as required, creating them if needed
1237
+ */
1238
+
1239
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1240
+ var captions = $this.children('caption').each( function () {
1241
+ this._captionSide = $(this).css('caption-side');
1242
+ } );
1243
+
1244
+ var thead = $this.children('thead');
1245
+ if ( thead.length === 0 ) {
1246
+ thead = $('<thead/>').appendTo($this);
1247
+ }
1248
+ oSettings.nTHead = thead[0];
1249
+
1250
+ var tbody = $this.children('tbody');
1251
+ if ( tbody.length === 0 ) {
1252
+ tbody = $('<tbody/>').appendTo($this);
1253
+ }
1254
+ oSettings.nTBody = tbody[0];
1255
+
1256
+ var tfoot = $this.children('tfoot');
1257
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1258
+ // If we are a scrolling table, and no footer has been given, then we need to create
1259
+ // a tfoot element for the caption element to be appended to
1260
+ tfoot = $('<tfoot/>').appendTo($this);
1261
+ }
1262
+
1263
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1264
+ $this.addClass( oClasses.sNoFooter );
1265
+ }
1266
+ else if ( tfoot.length > 0 ) {
1267
+ oSettings.nTFoot = tfoot[0];
1268
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1269
+ }
1270
+
1271
+ /* Check if there is data passing into the constructor */
1272
+ if ( oInit.aaData ) {
1273
+ for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1274
+ _fnAddData( oSettings, oInit.aaData[ i ] );
1275
+ }
1276
+ }
1277
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1278
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
1279
+ * source since there is no point in reading the DOM data if we are then going
1280
+ * to replace it with Ajax data
1281
+ */
1282
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1283
+ }
1284
+
1285
+ /* Copy the data index array */
1286
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1287
+
1288
+ /* Initialisation complete - table can be drawn */
1289
+ oSettings.bInitialised = true;
1290
+
1291
+ /* Check if we need to initialise the table (it might not have been handed off to the
1292
+ * language processor)
1293
+ */
1294
+ if ( bInitHandedOff === false ) {
1295
+ _fnInitialise( oSettings );
1296
+ }
1297
+ };
1298
+
1299
+ /* Must be done after everything which can be overridden by the state saving! */
1300
+ if ( oInit.bStateSave )
1301
+ {
1302
+ features.bStateSave = true;
1303
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1304
+ _fnLoadState( oSettings, oInit, loadedInit );
1305
+ }
1306
+ else {
1307
+ loadedInit();
1308
+ }
1309
+
1310
+ } );
1311
+ _that = null;
1312
+ return this;
1313
+ };
1314
+
1315
+
1316
+ /*
1317
+ * It is useful to have variables which are scoped locally so only the
1318
+ * DataTables functions can access them and they don't leak into global space.
1319
+ * At the same time these functions are often useful over multiple files in the
1320
+ * core and API, so we list, or at least document, all variables which are used
1321
+ * by DataTables as private variables here. This also ensures that there is no
1322
+ * clashing of variable names and that they can easily referenced for reuse.
1323
+ */
1324
+
1325
+
1326
+ // Defined else where
1327
+ // _selector_run
1328
+ // _selector_opts
1329
+ // _selector_first
1330
+ // _selector_row_indexes
1331
+
1332
+ var _ext; // DataTable.ext
1333
+ var _Api; // DataTable.Api
1334
+ var _api_register; // DataTable.Api.register
1335
+ var _api_registerPlural; // DataTable.Api.registerPlural
1336
+
1337
+ var _re_dic = {};
1338
+ var _re_new_lines = /[\r\n]/g;
1339
+ var _re_html = /<.*?>/g;
1340
+
1341
+ // This is not strict ISO8601 - Date.parse() is quite lax, although
1342
+ // implementations differ between browsers.
1343
+ var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1344
+
1345
+ // Escape regular expression special characters
1346
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1347
+
1348
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
1349
+ // - \u20BD - Russian ruble.
1350
+ // - \u20a9 - South Korean Won
1351
+ // - \u20BA - Turkish Lira
1352
+ // - \u20B9 - Indian Rupee
1353
+ // - R - Brazil (R$) and South Africa
1354
+ // - fr - Swiss Franc
1355
+ // - kr - Swedish krona, Norwegian krone and Danish krone
1356
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1357
+ // standards as thousands separators.
1358
+ var _re_formatted_numeric = /[',$ツ」竄ャツ・%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1359
+
1360
+
1361
+ var _empty = function ( d ) {
1362
+ return !d || d === true || d === '-' ? true : false;
1363
+ };
1364
+
1365
+
1366
+ var _intVal = function ( s ) {
1367
+ var integer = parseInt( s, 10 );
1368
+ return !isNaN(integer) && isFinite(s) ? integer : null;
1369
+ };
1370
+
1371
+ // Convert from a formatted number with characters other than `.` as the
1372
+ // decimal place, to a Javascript number
1373
+ var _numToDecimal = function ( num, decimalPoint ) {
1374
+ // Cache created regular expressions for speed as this function is called often
1375
+ if ( ! _re_dic[ decimalPoint ] ) {
1376
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1377
+ }
1378
+ return typeof num === 'string' && decimalPoint !== '.' ?
1379
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1380
+ num;
1381
+ };
1382
+
1383
+
1384
+ var _isNumber = function ( d, decimalPoint, formatted ) {
1385
+ var strType = typeof d === 'string';
1386
+
1387
+ // If empty return immediately so there must be a number if it is a
1388
+ // formatted string (this stops the string "k", or "kr", etc being detected
1389
+ // as a formatted number for currency
1390
+ if ( _empty( d ) ) {
1391
+ return true;
1392
+ }
1393
+
1394
+ if ( decimalPoint && strType ) {
1395
+ d = _numToDecimal( d, decimalPoint );
1396
+ }
1397
+
1398
+ if ( formatted && strType ) {
1399
+ d = d.replace( _re_formatted_numeric, '' );
1400
+ }
1401
+
1402
+ return !isNaN( parseFloat(d) ) && isFinite( d );
1403
+ };
1404
+
1405
+
1406
+ // A string without HTML in it can be considered to be HTML still
1407
+ var _isHtml = function ( d ) {
1408
+ return _empty( d ) || typeof d === 'string';
1409
+ };
1410
+
1411
+
1412
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1413
+ if ( _empty( d ) ) {
1414
+ return true;
1415
+ }
1416
+
1417
+ var html = _isHtml( d );
1418
+ return ! html ?
1419
+ null :
1420
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1421
+ true :
1422
+ null;
1423
+ };
1424
+
1425
+
1426
+ var _pluck = function ( a, prop, prop2 ) {
1427
+ var out = [];
1428
+ var i=0, ien=a.length;
1429
+
1430
+ // Could have the test in the loop for slightly smaller code, but speed
1431
+ // is essential here
1432
+ if ( prop2 !== undefined ) {
1433
+ for ( ; i<ien ; i++ ) {
1434
+ if ( a[i] && a[i][ prop ] ) {
1435
+ out.push( a[i][ prop ][ prop2 ] );
1436
+ }
1437
+ }
1438
+ }
1439
+ else {
1440
+ for ( ; i<ien ; i++ ) {
1441
+ if ( a[i] ) {
1442
+ out.push( a[i][ prop ] );
1443
+ }
1444
+ }
1445
+ }
1446
+
1447
+ return out;
1448
+ };
1449
+
1450
+
1451
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
1452
+ // as the indexes to pick from `a`
1453
+ var _pluck_order = function ( a, order, prop, prop2 )
1454
+ {
1455
+ var out = [];
1456
+ var i=0, ien=order.length;
1457
+
1458
+ // Could have the test in the loop for slightly smaller code, but speed
1459
+ // is essential here
1460
+ if ( prop2 !== undefined ) {
1461
+ for ( ; i<ien ; i++ ) {
1462
+ if ( a[ order[i] ][ prop ] ) {
1463
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
1464
+ }
1465
+ }
1466
+ }
1467
+ else {
1468
+ for ( ; i<ien ; i++ ) {
1469
+ out.push( a[ order[i] ][ prop ] );
1470
+ }
1471
+ }
1472
+
1473
+ return out;
1474
+ };
1475
+
1476
+
1477
+ var _range = function ( len, start )
1478
+ {
1479
+ var out = [];
1480
+ var end;
1481
+
1482
+ if ( start === undefined ) {
1483
+ start = 0;
1484
+ end = len;
1485
+ }
1486
+ else {
1487
+ end = start;
1488
+ start = len;
1489
+ }
1490
+
1491
+ for ( var i=start ; i<end ; i++ ) {
1492
+ out.push( i );
1493
+ }
1494
+
1495
+ return out;
1496
+ };
1497
+
1498
+
1499
+ var _removeEmpty = function ( a )
1500
+ {
1501
+ var out = [];
1502
+
1503
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1504
+ if ( a[i] ) { // careful - will remove all falsy values!
1505
+ out.push( a[i] );
1506
+ }
1507
+ }
1508
+
1509
+ return out;
1510
+ };
1511
+
1512
+
1513
+ var _stripHtml = function ( d ) {
1514
+ return d.replace( _re_html, '' );
1515
+ };
1516
+
1517
+
1518
+ /**
1519
+ * Determine if all values in the array are unique. This means we can short
1520
+ * cut the _unique method at the cost of a single loop. A sorted array is used
1521
+ * to easily check the values.
1522
+ *
1523
+ * @param {array} src Source array
1524
+ * @return {boolean} true if all unique, false otherwise
1525
+ * @ignore
1526
+ */
1527
+ var _areAllUnique = function ( src ) {
1528
+ if ( src.length < 2 ) {
1529
+ return true;
1530
+ }
1531
+
1532
+ var sorted = src.slice().sort();
1533
+ var last = sorted[0];
1534
+
1535
+ for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1536
+ if ( sorted[i] === last ) {
1537
+ return false;
1538
+ }
1539
+
1540
+ last = sorted[i];
1541
+ }
1542
+
1543
+ return true;
1544
+ };
1545
+
1546
+
1547
+ /**
1548
+ * Find the unique elements in a source array.
1549
+ *
1550
+ * @param {array} src Source array
1551
+ * @return {array} Array of unique items
1552
+ * @ignore
1553
+ */
1554
+ var _unique = function ( src )
1555
+ {
1556
+ if ( _areAllUnique( src ) ) {
1557
+ return src.slice();
1558
+ }
1559
+
1560
+ // A faster unique method is to use object keys to identify used values,
1561
+ // but this doesn't work with arrays or objects, which we must also
1562
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
1563
+ // information.
1564
+ var
1565
+ out = [],
1566
+ val,
1567
+ i, ien=src.length,
1568
+ j, k=0;
1569
+
1570
+ again: for ( i=0 ; i<ien ; i++ ) {
1571
+ val = src[i];
1572
+
1573
+ for ( j=0 ; j<k ; j++ ) {
1574
+ if ( out[j] === val ) {
1575
+ continue again;
1576
+ }
1577
+ }
1578
+
1579
+ out.push( val );
1580
+ k++;
1581
+ }
1582
+
1583
+ return out;
1584
+ };
1585
+
1586
+
1587
+ /**
1588
+ * DataTables utility methods
1589
+ *
1590
+ * This namespace provides helper methods that DataTables uses internally to
1591
+ * create a DataTable, but which are not exclusively used only for DataTables.
1592
+ * These methods can be used by extension authors to save the duplication of
1593
+ * code.
1594
+ *
1595
+ * @namespace
1596
+ */
1597
+ DataTable.util = {
1598
+ /**
1599
+ * Throttle the calls to a function. Arguments and context are maintained
1600
+ * for the throttled function.
1601
+ *
1602
+ * @param {function} fn Function to be called
1603
+ * @param {integer} freq Call frequency in mS
1604
+ * @return {function} Wrapped function
1605
+ */
1606
+ throttle: function ( fn, freq ) {
1607
+ var
1608
+ frequency = freq !== undefined ? freq : 200,
1609
+ last,
1610
+ timer;
1611
+
1612
+ return function () {
1613
+ var
1614
+ that = this,
1615
+ now = +new Date(),
1616
+ args = arguments;
1617
+
1618
+ if ( last && now < last + frequency ) {
1619
+ clearTimeout( timer );
1620
+
1621
+ timer = setTimeout( function () {
1622
+ last = undefined;
1623
+ fn.apply( that, args );
1624
+ }, frequency );
1625
+ }
1626
+ else {
1627
+ last = now;
1628
+ fn.apply( that, args );
1629
+ }
1630
+ };
1631
+ },
1632
+
1633
+
1634
+ /**
1635
+ * Escape a string such that it can be used in a regular expression
1636
+ *
1637
+ * @param {string} val string to escape
1638
+ * @returns {string} escaped string
1639
+ */
1640
+ escapeRegex: function ( val ) {
1641
+ return val.replace( _re_escape_regex, '\\$1' );
1642
+ }
1643
+ };
1644
+
1645
+
1646
+
1647
+ /**
1648
+ * Create a mapping object that allows camel case parameters to be looked up
1649
+ * for their Hungarian counterparts. The mapping is stored in a private
1650
+ * parameter called `_hungarianMap` which can be accessed on the source object.
1651
+ * @param {object} o
1652
+ * @memberof DataTable#oApi
1653
+ */
1654
+ function _fnHungarianMap ( o )
1655
+ {
1656
+ var
1657
+ hungarian = 'a aa ai ao as b fn i m o s ',
1658
+ match,
1659
+ newKey,
1660
+ map = {};
1661
+
1662
+ $.each( o, function (key, val) {
1663
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
1664
+
1665
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1666
+ {
1667
+ newKey = key.replace( match[0], match[2].toLowerCase() );
1668
+ map[ newKey ] = key;
1669
+
1670
+ if ( match[1] === 'o' )
1671
+ {
1672
+ _fnHungarianMap( o[key] );
1673
+ }
1674
+ }
1675
+ } );
1676
+
1677
+ o._hungarianMap = map;
1678
+ }
1679
+
1680
+
1681
+ /**
1682
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
1683
+ * created by _fnHungarianMap.
1684
+ * @param {object} src The model object which holds all parameters that can be
1685
+ * mapped.
1686
+ * @param {object} user The object to convert from camel case to Hungarian.
1687
+ * @param {boolean} force When set to `true`, properties which already have a
1688
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
1689
+ * won't be.
1690
+ * @memberof DataTable#oApi
1691
+ */
1692
+ function _fnCamelToHungarian ( src, user, force )
1693
+ {
1694
+ if ( ! src._hungarianMap ) {
1695
+ _fnHungarianMap( src );
1696
+ }
1697
+
1698
+ var hungarianKey;
1699
+
1700
+ $.each( user, function (key, val) {
1701
+ hungarianKey = src._hungarianMap[ key ];
1702
+
1703
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1704
+ {
1705
+ // For objects, we need to buzz down into the object to copy parameters
1706
+ if ( hungarianKey.charAt(0) === 'o' )
1707
+ {
1708
+ // Copy the camelCase options over to the hungarian
1709
+ if ( ! user[ hungarianKey ] ) {
1710
+ user[ hungarianKey ] = {};
1711
+ }
1712
+ $.extend( true, user[hungarianKey], user[key] );
1713
+
1714
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1715
+ }
1716
+ else {
1717
+ user[hungarianKey] = user[ key ];
1718
+ }
1719
+ }
1720
+ } );
1721
+ }
1722
+
1723
+
1724
+ /**
1725
+ * Language compatibility - when certain options are given, and others aren't, we
1726
+ * need to duplicate the values over, in order to provide backwards compatibility
1727
+ * with older language files.
1728
+ * @param {object} oSettings dataTables settings object
1729
+ * @memberof DataTable#oApi
1730
+ */
1731
+ function _fnLanguageCompat( lang )
1732
+ {
1733
+ var defaults = DataTable.defaults.oLanguage;
1734
+ var zeroRecords = lang.sZeroRecords;
1735
+
1736
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1737
+ * sZeroRecords - assuming that is given.
1738
+ */
1739
+ if ( ! lang.sEmptyTable && zeroRecords &&
1740
+ defaults.sEmptyTable === "No data available in table" )
1741
+ {
1742
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1743
+ }
1744
+
1745
+ /* Likewise with loading records */
1746
+ if ( ! lang.sLoadingRecords && zeroRecords &&
1747
+ defaults.sLoadingRecords === "Loading..." )
1748
+ {
1749
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1750
+ }
1751
+
1752
+ // Old parameter name of the thousands separator mapped onto the new
1753
+ if ( lang.sInfoThousands ) {
1754
+ lang.sThousands = lang.sInfoThousands;
1755
+ }
1756
+
1757
+ var decimal = lang.sDecimal;
1758
+ if ( decimal ) {
1759
+ _addNumericSort( decimal );
1760
+ }
1761
+ }
1762
+
1763
+
1764
+ /**
1765
+ * Map one parameter onto another
1766
+ * @param {object} o Object to map
1767
+ * @param {*} knew The new parameter name
1768
+ * @param {*} old The old parameter name
1769
+ */
1770
+ var _fnCompatMap = function ( o, knew, old ) {
1771
+ if ( o[ knew ] !== undefined ) {
1772
+ o[ old ] = o[ knew ];
1773
+ }
1774
+ };
1775
+
1776
+
1777
+ /**
1778
+ * Provide backwards compatibility for the main DT options. Note that the new
1779
+ * options are mapped onto the old parameters, so this is an external interface
1780
+ * change only.
1781
+ * @param {object} init Object to map
1782
+ */
1783
+ function _fnCompatOpts ( init )
1784
+ {
1785
+ _fnCompatMap( init, 'ordering', 'bSort' );
1786
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1787
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1788
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1789
+ _fnCompatMap( init, 'order', 'aaSorting' );
1790
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1791
+ _fnCompatMap( init, 'paging', 'bPaginate' );
1792
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1793
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1794
+ _fnCompatMap( init, 'searching', 'bFilter' );
1795
+
1796
+ // Boolean initialisation of x-scrolling
1797
+ if ( typeof init.sScrollX === 'boolean' ) {
1798
+ init.sScrollX = init.sScrollX ? '100%' : '';
1799
+ }
1800
+ if ( typeof init.scrollX === 'boolean' ) {
1801
+ init.scrollX = init.scrollX ? '100%' : '';
1802
+ }
1803
+
1804
+ // Column search objects are in an array, so it needs to be converted
1805
+ // element by element
1806
+ var searchCols = init.aoSearchCols;
1807
+
1808
+ if ( searchCols ) {
1809
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1810
+ if ( searchCols[i] ) {
1811
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1812
+ }
1813
+ }
1814
+ }
1815
+ }
1816
+
1817
+
1818
+ /**
1819
+ * Provide backwards compatibility for column options. Note that the new options
1820
+ * are mapped onto the old parameters, so this is an external interface change
1821
+ * only.
1822
+ * @param {object} init Object to map
1823
+ */
1824
+ function _fnCompatCols ( init )
1825
+ {
1826
+ _fnCompatMap( init, 'orderable', 'bSortable' );
1827
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
1828
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
1829
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1830
+
1831
+ // orderData can be given as an integer
1832
+ var dataSort = init.aDataSort;
1833
+ if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1834
+ init.aDataSort = [ dataSort ];
1835
+ }
1836
+ }
1837
+
1838
+
1839
+ /**
1840
+ * Browser feature detection for capabilities, quirks
1841
+ * @param {object} settings dataTables settings object
1842
+ * @memberof DataTable#oApi
1843
+ */
1844
+ function _fnBrowserDetect( settings )
1845
+ {
1846
+ // We don't need to do this every time DataTables is constructed, the values
1847
+ // calculated are specific to the browser and OS configuration which we
1848
+ // don't expect to change between initialisations
1849
+ if ( ! DataTable.__browser ) {
1850
+ var browser = {};
1851
+ DataTable.__browser = browser;
1852
+
1853
+ // Scrolling feature / quirks detection
1854
+ var n = $('<div/>')
1855
+ .css( {
1856
+ position: 'fixed',
1857
+ top: 0,
1858
+ left: $(window).scrollLeft()*-1, // allow for scrolling
1859
+ height: 1,
1860
+ width: 1,
1861
+ overflow: 'hidden'
1862
+ } )
1863
+ .append(
1864
+ $('<div/>')
1865
+ .css( {
1866
+ position: 'absolute',
1867
+ top: 1,
1868
+ left: 1,
1869
+ width: 100,
1870
+ overflow: 'scroll'
1871
+ } )
1872
+ .append(
1873
+ $('<div/>')
1874
+ .css( {
1875
+ width: '100%',
1876
+ height: 10
1877
+ } )
1878
+ )
1879
+ )
1880
+ .appendTo( 'body' );
1881
+
1882
+ var outer = n.children();
1883
+ var inner = outer.children();
1884
+
1885
+ // Numbers below, in order, are:
1886
+ // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1887
+ //
1888
+ // IE6 XP: 100 100 100 83
1889
+ // IE7 Vista: 100 100 100 83
1890
+ // IE 8+ Windows: 83 83 100 83
1891
+ // Evergreen Windows: 83 83 100 83
1892
+ // Evergreen Mac with scrollbars: 85 85 100 85
1893
+ // Evergreen Mac without scrollbars: 100 100 100 100
1894
+
1895
+ // Get scrollbar width
1896
+ browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1897
+
1898
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
1899
+ // include the width of the scrollbar, while other browsers ensure the inner
1900
+ // element is contained without forcing scrolling
1901
+ browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1902
+
1903
+ // In rtl text layout, some browsers (most, but not all) will place the
1904
+ // scrollbar on the left, rather than the right.
1905
+ browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1906
+
1907
+ // IE8- don't provide height and width for getBoundingClientRect
1908
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1909
+
1910
+ n.remove();
1911
+ }
1912
+
1913
+ $.extend( settings.oBrowser, DataTable.__browser );
1914
+ settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1915
+ }
1916
+
1917
+
1918
+ /**
1919
+ * Array.prototype reduce[Right] method, used for browsers which don't support
1920
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
1921
+ * @param {object} settings dataTables settings object
1922
+ * @memberof DataTable#oApi
1923
+ */
1924
+ function _fnReduce ( that, fn, init, start, end, inc )
1925
+ {
1926
+ var
1927
+ i = start,
1928
+ value,
1929
+ isSet = false;
1930
+
1931
+ if ( init !== undefined ) {
1932
+ value = init;
1933
+ isSet = true;
1934
+ }
1935
+
1936
+ while ( i !== end ) {
1937
+ if ( ! that.hasOwnProperty(i) ) {
1938
+ continue;
1939
+ }
1940
+
1941
+ value = isSet ?
1942
+ fn( value, that[i], i, that ) :
1943
+ that[i];
1944
+
1945
+ isSet = true;
1946
+ i += inc;
1947
+ }
1948
+
1949
+ return value;
1950
+ }
1951
+
1952
+ /**
1953
+ * Add a column to the list used for the table with default values
1954
+ * @param {object} oSettings dataTables settings object
1955
+ * @param {node} nTh The th element for this column
1956
+ * @memberof DataTable#oApi
1957
+ */
1958
+ function _fnAddColumn( oSettings, nTh )
1959
+ {
1960
+ // Add column to aoColumns array
1961
+ var oDefaults = DataTable.defaults.column;
1962
+ var iCol = oSettings.aoColumns.length;
1963
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1964
+ "nTh": nTh ? nTh : document.createElement('th'),
1965
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1966
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1967
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
1968
+ idx: iCol
1969
+ } );
1970
+ oSettings.aoColumns.push( oCol );
1971
+
1972
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1973
+ // passed into extend can be undefined. This allows the user to give a default
1974
+ // with only some of the parameters defined, and also not give a default
1975
+ var searchCols = oSettings.aoPreSearchCols;
1976
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1977
+
1978
+ // Use the default column options function to initialise classes etc
1979
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1980
+ }
1981
+
1982
+
1983
+ /**
1984
+ * Apply options for a column
1985
+ * @param {object} oSettings dataTables settings object
1986
+ * @param {int} iCol column index to consider
1987
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
1988
+ * @memberof DataTable#oApi
1989
+ */
1990
+ function _fnColumnOptions( oSettings, iCol, oOptions )
1991
+ {
1992
+ var oCol = oSettings.aoColumns[ iCol ];
1993
+ var oClasses = oSettings.oClasses;
1994
+ var th = $(oCol.nTh);
1995
+
1996
+ // Try to get width information from the DOM. We can't get it from CSS
1997
+ // as we'd need to parse the CSS stylesheet. `width` option can override
1998
+ if ( ! oCol.sWidthOrig ) {
1999
+ // Width attribute
2000
+ oCol.sWidthOrig = th.attr('width') || null;
2001
+
2002
+ // Style attribute
2003
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2004
+ if ( t ) {
2005
+ oCol.sWidthOrig = t[1];
2006
+ }
2007
+ }
2008
+
2009
+ /* User specified column options */
2010
+ if ( oOptions !== undefined && oOptions !== null )
2011
+ {
2012
+ // Backwards compatibility
2013
+ _fnCompatCols( oOptions );
2014
+
2015
+ // Map camel case parameters to their Hungarian counterparts
2016
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2017
+
2018
+ /* Backwards compatibility for mDataProp */
2019
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2020
+ {
2021
+ oOptions.mData = oOptions.mDataProp;
2022
+ }
2023
+
2024
+ if ( oOptions.sType )
2025
+ {
2026
+ oCol._sManualType = oOptions.sType;
2027
+ }
2028
+
2029
+ // `class` is a reserved word in Javascript, so we need to provide
2030
+ // the ability to use a valid name for the camel case input
2031
+ if ( oOptions.className && ! oOptions.sClass )
2032
+ {
2033
+ oOptions.sClass = oOptions.className;
2034
+ }
2035
+ if ( oOptions.sClass ) {
2036
+ th.addClass( oOptions.sClass );
2037
+ }
2038
+
2039
+ $.extend( oCol, oOptions );
2040
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2041
+
2042
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2043
+ * priority if defined
2044
+ */
2045
+ if ( oOptions.iDataSort !== undefined )
2046
+ {
2047
+ oCol.aDataSort = [ oOptions.iDataSort ];
2048
+ }
2049
+ _fnMap( oCol, oOptions, "aDataSort" );
2050
+ }
2051
+
2052
+ /* Cache the data get and set functions for speed */
2053
+ var mDataSrc = oCol.mData;
2054
+ var mData = _fnGetObjectDataFn( mDataSrc );
2055
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2056
+
2057
+ var attrTest = function( src ) {
2058
+ return typeof src === 'string' && src.indexOf('@') !== -1;
2059
+ };
2060
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2061
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2062
+ );
2063
+ oCol._setter = null;
2064
+
2065
+ oCol.fnGetData = function (rowData, type, meta) {
2066
+ var innerData = mData( rowData, type, undefined, meta );
2067
+
2068
+ return mRender && type ?
2069
+ mRender( innerData, type, rowData, meta ) :
2070
+ innerData;
2071
+ };
2072
+ oCol.fnSetData = function ( rowData, val, meta ) {
2073
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2074
+ };
2075
+
2076
+ // Indicate if DataTables should read DOM data as an object or array
2077
+ // Used in _fnGetRowElements
2078
+ if ( typeof mDataSrc !== 'number' ) {
2079
+ oSettings._rowReadObject = true;
2080
+ }
2081
+
2082
+ /* Feature sorting overrides column specific when off */
2083
+ if ( !oSettings.oFeatures.bSort )
2084
+ {
2085
+ oCol.bSortable = false;
2086
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2087
+ }
2088
+
2089
+ /* Check that the class assignment is correct for sorting */
2090
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2091
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2092
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
2093
+ {
2094
+ oCol.sSortingClass = oClasses.sSortableNone;
2095
+ oCol.sSortingClassJUI = "";
2096
+ }
2097
+ else if ( bAsc && !bDesc )
2098
+ {
2099
+ oCol.sSortingClass = oClasses.sSortableAsc;
2100
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2101
+ }
2102
+ else if ( !bAsc && bDesc )
2103
+ {
2104
+ oCol.sSortingClass = oClasses.sSortableDesc;
2105
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2106
+ }
2107
+ else
2108
+ {
2109
+ oCol.sSortingClass = oClasses.sSortable;
2110
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
2111
+ }
2112
+ }
2113
+
2114
+
2115
+ /**
2116
+ * Adjust the table column widths for new data. Note: you would probably want to
2117
+ * do a redraw after calling this function!
2118
+ * @param {object} settings dataTables settings object
2119
+ * @memberof DataTable#oApi
2120
+ */
2121
+ function _fnAdjustColumnSizing ( settings )
2122
+ {
2123
+ /* Not interested in doing column width calculation if auto-width is disabled */
2124
+ if ( settings.oFeatures.bAutoWidth !== false )
2125
+ {
2126
+ var columns = settings.aoColumns;
2127
+
2128
+ _fnCalculateColumnWidths( settings );
2129
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2130
+ {
2131
+ columns[i].nTh.style.width = columns[i].sWidth;
2132
+ }
2133
+ }
2134
+
2135
+ var scroll = settings.oScroll;
2136
+ if ( scroll.sY !== '' || scroll.sX !== '')
2137
+ {
2138
+ _fnScrollDraw( settings );
2139
+ }
2140
+
2141
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2142
+ }
2143
+
2144
+
2145
+ /**
2146
+ * Covert the index of a visible column to the index in the data array (take account
2147
+ * of hidden columns)
2148
+ * @param {object} oSettings dataTables settings object
2149
+ * @param {int} iMatch Visible column index to lookup
2150
+ * @returns {int} i the data index
2151
+ * @memberof DataTable#oApi
2152
+ */
2153
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
2154
+ {
2155
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2156
+
2157
+ return typeof aiVis[iMatch] === 'number' ?
2158
+ aiVis[iMatch] :
2159
+ null;
2160
+ }
2161
+
2162
+
2163
+ /**
2164
+ * Covert the index of an index in the data array and convert it to the visible
2165
+ * column index (take account of hidden columns)
2166
+ * @param {int} iMatch Column index to lookup
2167
+ * @param {object} oSettings dataTables settings object
2168
+ * @returns {int} i the data index
2169
+ * @memberof DataTable#oApi
2170
+ */
2171
+ function _fnColumnIndexToVisible( oSettings, iMatch )
2172
+ {
2173
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2174
+ var iPos = $.inArray( iMatch, aiVis );
2175
+
2176
+ return iPos !== -1 ? iPos : null;
2177
+ }
2178
+
2179
+
2180
+ /**
2181
+ * Get the number of visible columns
2182
+ * @param {object} oSettings dataTables settings object
2183
+ * @returns {int} i the number of visible columns
2184
+ * @memberof DataTable#oApi
2185
+ */
2186
+ function _fnVisbleColumns( oSettings )
2187
+ {
2188
+ var vis = 0;
2189
+
2190
+ // No reduce in IE8, use a loop for now
2191
+ $.each( oSettings.aoColumns, function ( i, col ) {
2192
+ if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2193
+ vis++;
2194
+ }
2195
+ } );
2196
+
2197
+ return vis;
2198
+ }
2199
+
2200
+
2201
+ /**
2202
+ * Get an array of column indexes that match a given property
2203
+ * @param {object} oSettings dataTables settings object
2204
+ * @param {string} sParam Parameter in aoColumns to look for - typically
2205
+ * bVisible or bSearchable
2206
+ * @returns {array} Array of indexes with matched properties
2207
+ * @memberof DataTable#oApi
2208
+ */
2209
+ function _fnGetColumns( oSettings, sParam )
2210
+ {
2211
+ var a = [];
2212
+
2213
+ $.map( oSettings.aoColumns, function(val, i) {
2214
+ if ( val[sParam] ) {
2215
+ a.push( i );
2216
+ }
2217
+ } );
2218
+
2219
+ return a;
2220
+ }
2221
+
2222
+
2223
+ /**
2224
+ * Calculate the 'type' of a column
2225
+ * @param {object} settings dataTables settings object
2226
+ * @memberof DataTable#oApi
2227
+ */
2228
+ function _fnColumnTypes ( settings )
2229
+ {
2230
+ var columns = settings.aoColumns;
2231
+ var data = settings.aoData;
2232
+ var types = DataTable.ext.type.detect;
2233
+ var i, ien, j, jen, k, ken;
2234
+ var col, cell, detectedType, cache;
2235
+
2236
+ // For each column, spin over the
2237
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2238
+ col = columns[i];
2239
+ cache = [];
2240
+
2241
+ if ( ! col.sType && col._sManualType ) {
2242
+ col.sType = col._sManualType;
2243
+ }
2244
+ else if ( ! col.sType ) {
2245
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
2246
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
2247
+ // Use a cache array so we only need to get the type data
2248
+ // from the formatter once (when using multiple detectors)
2249
+ if ( cache[k] === undefined ) {
2250
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
2251
+ }
2252
+
2253
+ detectedType = types[j]( cache[k], settings );
2254
+
2255
+ // If null, then this type can't apply to this column, so
2256
+ // rather than testing all cells, break out. There is an
2257
+ // exception for the last type which is `html`. We need to
2258
+ // scan all rows since it is possible to mix string and HTML
2259
+ // types
2260
+ if ( ! detectedType && j !== types.length-1 ) {
2261
+ break;
2262
+ }
2263
+
2264
+ // Only a single match is needed for html type since it is
2265
+ // bottom of the pile and very similar to string
2266
+ if ( detectedType === 'html' ) {
2267
+ break;
2268
+ }
2269
+ }
2270
+
2271
+ // Type is valid for all data points in the column - use this
2272
+ // type
2273
+ if ( detectedType ) {
2274
+ col.sType = detectedType;
2275
+ break;
2276
+ }
2277
+ }
2278
+
2279
+ // Fall back - if no type was detected, always use string
2280
+ if ( ! col.sType ) {
2281
+ col.sType = 'string';
2282
+ }
2283
+ }
2284
+ }
2285
+ }
2286
+
2287
+
2288
+ /**
2289
+ * Take the column definitions and static columns arrays and calculate how
2290
+ * they relate to column indexes. The callback function will then apply the
2291
+ * definition found for a column to a suitable configuration object.
2292
+ * @param {object} oSettings dataTables settings object
2293
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2294
+ * @param {array} aoCols The aoColumns array that defines columns individually
2295
+ * @param {function} fn Callback function - takes two parameters, the calculated
2296
+ * column index and the definition for that column.
2297
+ * @memberof DataTable#oApi
2298
+ */
2299
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2300
+ {
2301
+ var i, iLen, j, jLen, k, kLen, def;
2302
+ var columns = oSettings.aoColumns;
2303
+
2304
+ // Column definitions with aTargets
2305
+ if ( aoColDefs )
2306
+ {
2307
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
2308
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2309
+ {
2310
+ def = aoColDefs[i];
2311
+
2312
+ /* Each definition can target multiple columns, as it is an array */
2313
+ var aTargets = def.targets !== undefined ?
2314
+ def.targets :
2315
+ def.aTargets;
2316
+
2317
+ if ( ! $.isArray( aTargets ) )
2318
+ {
2319
+ aTargets = [ aTargets ];
2320
+ }
2321
+
2322
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2323
+ {
2324
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2325
+ {
2326
+ /* Add columns that we don't yet know about */
2327
+ while( columns.length <= aTargets[j] )
2328
+ {
2329
+ _fnAddColumn( oSettings );
2330
+ }
2331
+
2332
+ /* Integer, basic index */
2333
+ fn( aTargets[j], def );
2334
+ }
2335
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2336
+ {
2337
+ /* Negative integer, right to left column counting */
2338
+ fn( columns.length+aTargets[j], def );
2339
+ }
2340
+ else if ( typeof aTargets[j] === 'string' )
2341
+ {
2342
+ /* Class name matching on TH element */
2343
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2344
+ {
2345
+ if ( aTargets[j] == "_all" ||
2346
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
2347
+ {
2348
+ fn( k, def );
2349
+ }
2350
+ }
2351
+ }
2352
+ }
2353
+ }
2354
+ }
2355
+
2356
+ // Statically defined columns array
2357
+ if ( aoCols )
2358
+ {
2359
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2360
+ {
2361
+ fn( i, aoCols[i] );
2362
+ }
2363
+ }
2364
+ }
2365
+
2366
+ /**
2367
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
2368
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
2369
+ * DOM source.
2370
+ * @param {object} oSettings dataTables settings object
2371
+ * @param {array} aData data array to be added
2372
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
2373
+ * DataTables will create a row automatically
2374
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2375
+ * if nTr is.
2376
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2377
+ * @memberof DataTable#oApi
2378
+ */
2379
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2380
+ {
2381
+ /* Create the object for storing information about this new row */
2382
+ var iRow = oSettings.aoData.length;
2383
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
2384
+ src: nTr ? 'dom' : 'data',
2385
+ idx: iRow
2386
+ } );
2387
+
2388
+ oData._aData = aDataIn;
2389
+ oSettings.aoData.push( oData );
2390
+
2391
+ /* Create the cells */
2392
+ var nTd, sThisType;
2393
+ var columns = oSettings.aoColumns;
2394
+
2395
+ // Invalidate the column types as the new data needs to be revalidated
2396
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2397
+ {
2398
+ columns[i].sType = null;
2399
+ }
2400
+
2401
+ /* Add to the display array */
2402
+ oSettings.aiDisplayMaster.push( iRow );
2403
+
2404
+ var id = oSettings.rowIdFn( aDataIn );
2405
+ if ( id !== undefined ) {
2406
+ oSettings.aIds[ id ] = oData;
2407
+ }
2408
+
2409
+ /* Create the DOM information, or register it if already present */
2410
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
2411
+ {
2412
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
2413
+ }
2414
+
2415
+ return iRow;
2416
+ }
2417
+
2418
+
2419
+ /**
2420
+ * Add one or more TR elements to the table. Generally we'd expect to
2421
+ * use this for reading data from a DOM sourced table, but it could be
2422
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
2423
+ * it is not cloned).
2424
+ * @param {object} settings dataTables settings object
2425
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
2426
+ * @returns {array} Array of indexes for the added rows
2427
+ * @memberof DataTable#oApi
2428
+ */
2429
+ function _fnAddTr( settings, trs )
2430
+ {
2431
+ var row;
2432
+
2433
+ // Allow an individual node to be passed in
2434
+ if ( ! (trs instanceof $) ) {
2435
+ trs = $(trs);
2436
+ }
2437
+
2438
+ return trs.map( function (i, el) {
2439
+ row = _fnGetRowElements( settings, el );
2440
+ return _fnAddData( settings, row.data, el, row.cells );
2441
+ } );
2442
+ }
2443
+
2444
+
2445
+ /**
2446
+ * Take a TR element and convert it to an index in aoData
2447
+ * @param {object} oSettings dataTables settings object
2448
+ * @param {node} n the TR element to find
2449
+ * @returns {int} index if the node is found, null if not
2450
+ * @memberof DataTable#oApi
2451
+ */
2452
+ function _fnNodeToDataIndex( oSettings, n )
2453
+ {
2454
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2455
+ }
2456
+
2457
+
2458
+ /**
2459
+ * Take a TD element and convert it into a column data index (not the visible index)
2460
+ * @param {object} oSettings dataTables settings object
2461
+ * @param {int} iRow The row number the TD/TH can be found in
2462
+ * @param {node} n The TD/TH element to find
2463
+ * @returns {int} index if the node is found, -1 if not
2464
+ * @memberof DataTable#oApi
2465
+ */
2466
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
2467
+ {
2468
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2469
+ }
2470
+
2471
+
2472
+ /**
2473
+ * Get the data for a given cell from the internal cache, taking into account data mapping
2474
+ * @param {object} settings dataTables settings object
2475
+ * @param {int} rowIdx aoData row id
2476
+ * @param {int} colIdx Column index
2477
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2478
+ * @returns {*} Cell data
2479
+ * @memberof DataTable#oApi
2480
+ */
2481
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
2482
+ {
2483
+ var draw = settings.iDraw;
2484
+ var col = settings.aoColumns[colIdx];
2485
+ var rowData = settings.aoData[rowIdx]._aData;
2486
+ var defaultContent = col.sDefaultContent;
2487
+ var cellData = col.fnGetData( rowData, type, {
2488
+ settings: settings,
2489
+ row: rowIdx,
2490
+ col: colIdx
2491
+ } );
2492
+
2493
+ if ( cellData === undefined ) {
2494
+ if ( settings.iDrawError != draw && defaultContent === null ) {
2495
+ _fnLog( settings, 0, "Requested unknown parameter "+
2496
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2497
+ " for row "+rowIdx+", column "+colIdx, 4 );
2498
+ settings.iDrawError = draw;
2499
+ }
2500
+ return defaultContent;
2501
+ }
2502
+
2503
+ // When the data source is null and a specific data type is requested (i.e.
2504
+ // not the original data), we can use default column data
2505
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2506
+ cellData = defaultContent;
2507
+ }
2508
+ else if ( typeof cellData === 'function' ) {
2509
+ // If the data source is a function, then we run it and use the return,
2510
+ // executing in the scope of the data object (for instances)
2511
+ return cellData.call( rowData );
2512
+ }
2513
+
2514
+ if ( cellData === null && type == 'display' ) {
2515
+ return '';
2516
+ }
2517
+ return cellData;
2518
+ }
2519
+
2520
+
2521
+ /**
2522
+ * Set the value for a specific cell, into the internal data cache
2523
+ * @param {object} settings dataTables settings object
2524
+ * @param {int} rowIdx aoData row id
2525
+ * @param {int} colIdx Column index
2526
+ * @param {*} val Value to set
2527
+ * @memberof DataTable#oApi
2528
+ */
2529
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
2530
+ {
2531
+ var col = settings.aoColumns[colIdx];
2532
+ var rowData = settings.aoData[rowIdx]._aData;
2533
+
2534
+ col.fnSetData( rowData, val, {
2535
+ settings: settings,
2536
+ row: rowIdx,
2537
+ col: colIdx
2538
+ } );
2539
+ }
2540
+
2541
+
2542
+ // Private variable that is used to match action syntax in the data property object
2543
+ var __reArray = /\[.*?\]$/;
2544
+ var __reFn = /\(\)$/;
2545
+
2546
+ /**
2547
+ * Split string on periods, taking into account escaped periods
2548
+ * @param {string} str String to split
2549
+ * @return {array} Split string
2550
+ */
2551
+ function _fnSplitObjNotation( str )
2552
+ {
2553
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2554
+ return s.replace(/\\\./g, '.');
2555
+ } );
2556
+ }
2557
+
2558
+
2559
+ /**
2560
+ * Return a function that can be used to get data from a source object, taking
2561
+ * into account the ability to use nested objects as a source
2562
+ * @param {string|int|function} mSource The data source for the object
2563
+ * @returns {function} Data get function
2564
+ * @memberof DataTable#oApi
2565
+ */
2566
+ function _fnGetObjectDataFn( mSource )
2567
+ {
2568
+ if ( $.isPlainObject( mSource ) )
2569
+ {
2570
+ /* Build an object of get functions, and wrap them in a single call */
2571
+ var o = {};
2572
+ $.each( mSource, function (key, val) {
2573
+ if ( val ) {
2574
+ o[key] = _fnGetObjectDataFn( val );
2575
+ }
2576
+ } );
2577
+
2578
+ return function (data, type, row, meta) {
2579
+ var t = o[type] || o._;
2580
+ return t !== undefined ?
2581
+ t(data, type, row, meta) :
2582
+ data;
2583
+ };
2584
+ }
2585
+ else if ( mSource === null )
2586
+ {
2587
+ /* Give an empty string for rendering / sorting etc */
2588
+ return function (data) { // type, row and meta also passed, but not used
2589
+ return data;
2590
+ };
2591
+ }
2592
+ else if ( typeof mSource === 'function' )
2593
+ {
2594
+ return function (data, type, row, meta) {
2595
+ return mSource( data, type, row, meta );
2596
+ };
2597
+ }
2598
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2599
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2600
+ {
2601
+ /* If there is a . in the source string then the data source is in a
2602
+ * nested object so we loop over the data for each level to get the next
2603
+ * level down. On each loop we test for undefined, and if found immediately
2604
+ * return. This allows entire objects to be missing and sDefaultContent to
2605
+ * be used if defined, rather than throwing an error
2606
+ */
2607
+ var fetchData = function (data, type, src) {
2608
+ var arrayNotation, funcNotation, out, innerSrc;
2609
+
2610
+ if ( src !== "" )
2611
+ {
2612
+ var a = _fnSplitObjNotation( src );
2613
+
2614
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2615
+ {
2616
+ // Check if we are dealing with special notation
2617
+ arrayNotation = a[i].match(__reArray);
2618
+ funcNotation = a[i].match(__reFn);
2619
+
2620
+ if ( arrayNotation )
2621
+ {
2622
+ // Array notation
2623
+ a[i] = a[i].replace(__reArray, '');
2624
+
2625
+ // Condition allows simply [] to be passed in
2626
+ if ( a[i] !== "" ) {
2627
+ data = data[ a[i] ];
2628
+ }
2629
+ out = [];
2630
+
2631
+ // Get the remainder of the nested object to get
2632
+ a.splice( 0, i+1 );
2633
+ innerSrc = a.join('.');
2634
+
2635
+ // Traverse each entry in the array getting the properties requested
2636
+ if ( $.isArray( data ) ) {
2637
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2638
+ out.push( fetchData( data[j], type, innerSrc ) );
2639
+ }
2640
+ }
2641
+
2642
+ // If a string is given in between the array notation indicators, that
2643
+ // is used to join the strings together, otherwise an array is returned
2644
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2645
+ data = (join==="") ? out : out.join(join);
2646
+
2647
+ // The inner call to fetchData has already traversed through the remainder
2648
+ // of the source requested, so we exit from the loop
2649
+ break;
2650
+ }
2651
+ else if ( funcNotation )
2652
+ {
2653
+ // Function call
2654
+ a[i] = a[i].replace(__reFn, '');
2655
+ data = data[ a[i] ]();
2656
+ continue;
2657
+ }
2658
+
2659
+ if ( data === null || data[ a[i] ] === undefined )
2660
+ {
2661
+ return undefined;
2662
+ }
2663
+ data = data[ a[i] ];
2664
+ }
2665
+ }
2666
+
2667
+ return data;
2668
+ };
2669
+
2670
+ return function (data, type) { // row and meta also passed, but not used
2671
+ return fetchData( data, type, mSource );
2672
+ };
2673
+ }
2674
+ else
2675
+ {
2676
+ /* Array or flat object mapping */
2677
+ return function (data, type) { // row and meta also passed, but not used
2678
+ return data[mSource];
2679
+ };
2680
+ }
2681
+ }
2682
+
2683
+
2684
+ /**
2685
+ * Return a function that can be used to set data from a source object, taking
2686
+ * into account the ability to use nested objects as a source
2687
+ * @param {string|int|function} mSource The data source for the object
2688
+ * @returns {function} Data set function
2689
+ * @memberof DataTable#oApi
2690
+ */
2691
+ function _fnSetObjectDataFn( mSource )
2692
+ {
2693
+ if ( $.isPlainObject( mSource ) )
2694
+ {
2695
+ /* Unlike get, only the underscore (global) option is used for for
2696
+ * setting data since we don't know the type here. This is why an object
2697
+ * option is not documented for `mData` (which is read/write), but it is
2698
+ * for `mRender` which is read only.
2699
+ */
2700
+ return _fnSetObjectDataFn( mSource._ );
2701
+ }
2702
+ else if ( mSource === null )
2703
+ {
2704
+ /* Nothing to do when the data source is null */
2705
+ return function () {};
2706
+ }
2707
+ else if ( typeof mSource === 'function' )
2708
+ {
2709
+ return function (data, val, meta) {
2710
+ mSource( data, 'set', val, meta );
2711
+ };
2712
+ }
2713
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2714
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2715
+ {
2716
+ /* Like the get, we need to get data from a nested object */
2717
+ var setData = function (data, val, src) {
2718
+ var a = _fnSplitObjNotation( src ), b;
2719
+ var aLast = a[a.length-1];
2720
+ var arrayNotation, funcNotation, o, innerSrc;
2721
+
2722
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2723
+ {
2724
+ // Check if we are dealing with an array notation request
2725
+ arrayNotation = a[i].match(__reArray);
2726
+ funcNotation = a[i].match(__reFn);
2727
+
2728
+ if ( arrayNotation )
2729
+ {
2730
+ a[i] = a[i].replace(__reArray, '');
2731
+ data[ a[i] ] = [];
2732
+
2733
+ // Get the remainder of the nested object to set so we can recurse
2734
+ b = a.slice();
2735
+ b.splice( 0, i+1 );
2736
+ innerSrc = b.join('.');
2737
+
2738
+ // Traverse each entry in the array setting the properties requested
2739
+ if ( $.isArray( val ) )
2740
+ {
2741
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2742
+ {
2743
+ o = {};
2744
+ setData( o, val[j], innerSrc );
2745
+ data[ a[i] ].push( o );
2746
+ }
2747
+ }
2748
+ else
2749
+ {
2750
+ // We've been asked to save data to an array, but it
2751
+ // isn't array data to be saved. Best that can be done
2752
+ // is to just save the value.
2753
+ data[ a[i] ] = val;
2754
+ }
2755
+
2756
+ // The inner call to setData has already traversed through the remainder
2757
+ // of the source and has set the data, thus we can exit here
2758
+ return;
2759
+ }
2760
+ else if ( funcNotation )
2761
+ {
2762
+ // Function call
2763
+ a[i] = a[i].replace(__reFn, '');
2764
+ data = data[ a[i] ]( val );
2765
+ }
2766
+
2767
+ // If the nested object doesn't currently exist - since we are
2768
+ // trying to set the value - create it
2769
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2770
+ {
2771
+ data[ a[i] ] = {};
2772
+ }
2773
+ data = data[ a[i] ];
2774
+ }
2775
+
2776
+ // Last item in the input - i.e, the actual set
2777
+ if ( aLast.match(__reFn ) )
2778
+ {
2779
+ // Function call
2780
+ data = data[ aLast.replace(__reFn, '') ]( val );
2781
+ }
2782
+ else
2783
+ {
2784
+ // If array notation is used, we just want to strip it and use the property name
2785
+ // and assign the value. If it isn't used, then we get the result we want anyway
2786
+ data[ aLast.replace(__reArray, '') ] = val;
2787
+ }
2788
+ };
2789
+
2790
+ return function (data, val) { // meta is also passed in, but not used
2791
+ return setData( data, val, mSource );
2792
+ };
2793
+ }
2794
+ else
2795
+ {
2796
+ /* Array or flat object mapping */
2797
+ return function (data, val) { // meta is also passed in, but not used
2798
+ data[mSource] = val;
2799
+ };
2800
+ }
2801
+ }
2802
+
2803
+
2804
+ /**
2805
+ * Return an array with the full table data
2806
+ * @param {object} oSettings dataTables settings object
2807
+ * @returns array {array} aData Master data array
2808
+ * @memberof DataTable#oApi
2809
+ */
2810
+ function _fnGetDataMaster ( settings )
2811
+ {
2812
+ return _pluck( settings.aoData, '_aData' );
2813
+ }
2814
+
2815
+
2816
+ /**
2817
+ * Nuke the table
2818
+ * @param {object} oSettings dataTables settings object
2819
+ * @memberof DataTable#oApi
2820
+ */
2821
+ function _fnClearTable( settings )
2822
+ {
2823
+ settings.aoData.length = 0;
2824
+ settings.aiDisplayMaster.length = 0;
2825
+ settings.aiDisplay.length = 0;
2826
+ settings.aIds = {};
2827
+ }
2828
+
2829
+
2830
+ /**
2831
+ * Take an array of integers (index array) and remove a target integer (value - not
2832
+ * the key!)
2833
+ * @param {array} a Index array to target
2834
+ * @param {int} iTarget value to find
2835
+ * @memberof DataTable#oApi
2836
+ */
2837
+ function _fnDeleteIndex( a, iTarget, splice )
2838
+ {
2839
+ var iTargetIndex = -1;
2840
+
2841
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2842
+ {
2843
+ if ( a[i] == iTarget )
2844
+ {
2845
+ iTargetIndex = i;
2846
+ }
2847
+ else if ( a[i] > iTarget )
2848
+ {
2849
+ a[i]--;
2850
+ }
2851
+ }
2852
+
2853
+ if ( iTargetIndex != -1 && splice === undefined )
2854
+ {
2855
+ a.splice( iTargetIndex, 1 );
2856
+ }
2857
+ }
2858
+
2859
+
2860
+ /**
2861
+ * Mark cached data as invalid such that a re-read of the data will occur when
2862
+ * the cached data is next requested. Also update from the data source object.
2863
+ *
2864
+ * @param {object} settings DataTables settings object
2865
+ * @param {int} rowIdx Row index to invalidate
2866
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2867
+ * or 'data'
2868
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2869
+ * row will be invalidated
2870
+ * @memberof DataTable#oApi
2871
+ *
2872
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
2873
+ * the sort and filter methods can subscribe to it. That will required
2874
+ * initialisation options for sorting, which is why it is not already baked in
2875
+ */
2876
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
2877
+ {
2878
+ var row = settings.aoData[ rowIdx ];
2879
+ var i, ien;
2880
+ var cellWrite = function ( cell, col ) {
2881
+ // This is very frustrating, but in IE if you just write directly
2882
+ // to innerHTML, and elements that are overwritten are GC'ed,
2883
+ // even if there is a reference to them elsewhere
2884
+ while ( cell.childNodes.length ) {
2885
+ cell.removeChild( cell.firstChild );
2886
+ }
2887
+
2888
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2889
+ };
2890
+
2891
+ // Are we reading last data from DOM or the data object?
2892
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2893
+ // Read the data from the DOM
2894
+ row._aData = _fnGetRowElements(
2895
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2896
+ )
2897
+ .data;
2898
+ }
2899
+ else {
2900
+ // Reading from data object, update the DOM
2901
+ var cells = row.anCells;
2902
+
2903
+ if ( cells ) {
2904
+ if ( colIdx !== undefined ) {
2905
+ cellWrite( cells[colIdx], colIdx );
2906
+ }
2907
+ else {
2908
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2909
+ cellWrite( cells[i], i );
2910
+ }
2911
+ }
2912
+ }
2913
+ }
2914
+
2915
+ // For both row and cell invalidation, the cached data for sorting and
2916
+ // filtering is nulled out
2917
+ row._aSortData = null;
2918
+ row._aFilterData = null;
2919
+
2920
+ // Invalidate the type for a specific column (if given) or all columns since
2921
+ // the data might have changed
2922
+ var cols = settings.aoColumns;
2923
+ if ( colIdx !== undefined ) {
2924
+ cols[ colIdx ].sType = null;
2925
+ }
2926
+ else {
2927
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2928
+ cols[i].sType = null;
2929
+ }
2930
+
2931
+ // Update DataTables special `DT_*` attributes for the row
2932
+ _fnRowAttributes( settings, row );
2933
+ }
2934
+ }
2935
+
2936
+
2937
+ /**
2938
+ * Build a data source object from an HTML row, reading the contents of the
2939
+ * cells that are in the row.
2940
+ *
2941
+ * @param {object} settings DataTables settings object
2942
+ * @param {node|object} TR element from which to read data or existing row
2943
+ * object from which to re-read the data from the cells
2944
+ * @param {int} [colIdx] Optional column index
2945
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
2946
+ * parameter should also be given and will be used to write the data into.
2947
+ * Only the column in question will be written
2948
+ * @returns {object} Object with two parameters: `data` the data read, in
2949
+ * document order, and `cells` and array of nodes (they can be useful to the
2950
+ * caller, so rather than needing a second traversal to get them, just return
2951
+ * them from here).
2952
+ * @memberof DataTable#oApi
2953
+ */
2954
+ function _fnGetRowElements( settings, row, colIdx, d )
2955
+ {
2956
+ var
2957
+ tds = [],
2958
+ td = row.firstChild,
2959
+ name, col, o, i=0, contents,
2960
+ columns = settings.aoColumns,
2961
+ objectRead = settings._rowReadObject;
2962
+
2963
+ // Allow the data object to be passed in, or construct
2964
+ d = d !== undefined ?
2965
+ d :
2966
+ objectRead ?
2967
+ {} :
2968
+ [];
2969
+
2970
+ var attr = function ( str, td ) {
2971
+ if ( typeof str === 'string' ) {
2972
+ var idx = str.indexOf('@');
2973
+
2974
+ if ( idx !== -1 ) {
2975
+ var attr = str.substring( idx+1 );
2976
+ var setter = _fnSetObjectDataFn( str );
2977
+ setter( d, td.getAttribute( attr ) );
2978
+ }
2979
+ }
2980
+ };
2981
+
2982
+ // Read data from a cell and store into the data object
2983
+ var cellProcess = function ( cell ) {
2984
+ if ( colIdx === undefined || colIdx === i ) {
2985
+ col = columns[i];
2986
+ contents = $.trim(cell.innerHTML);
2987
+
2988
+ if ( col && col._bAttrSrc ) {
2989
+ var setter = _fnSetObjectDataFn( col.mData._ );
2990
+ setter( d, contents );
2991
+
2992
+ attr( col.mData.sort, cell );
2993
+ attr( col.mData.type, cell );
2994
+ attr( col.mData.filter, cell );
2995
+ }
2996
+ else {
2997
+ // Depending on the `data` option for the columns the data can
2998
+ // be read to either an object or an array.
2999
+ if ( objectRead ) {
3000
+ if ( ! col._setter ) {
3001
+ // Cache the setter function
3002
+ col._setter = _fnSetObjectDataFn( col.mData );
3003
+ }
3004
+ col._setter( d, contents );
3005
+ }
3006
+ else {
3007
+ d[i] = contents;
3008
+ }
3009
+ }
3010
+ }
3011
+
3012
+ i++;
3013
+ };
3014
+
3015
+ if ( td ) {
3016
+ // `tr` element was passed in
3017
+ while ( td ) {
3018
+ name = td.nodeName.toUpperCase();
3019
+
3020
+ if ( name == "TD" || name == "TH" ) {
3021
+ cellProcess( td );
3022
+ tds.push( td );
3023
+ }
3024
+
3025
+ td = td.nextSibling;
3026
+ }
3027
+ }
3028
+ else {
3029
+ // Existing row object passed in
3030
+ tds = row.anCells;
3031
+
3032
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3033
+ cellProcess( tds[j] );
3034
+ }
3035
+ }
3036
+
3037
+ // Read the ID from the DOM if present
3038
+ var rowNode = row.firstChild ? row : row.nTr;
3039
+
3040
+ if ( rowNode ) {
3041
+ var id = rowNode.getAttribute( 'id' );
3042
+
3043
+ if ( id ) {
3044
+ _fnSetObjectDataFn( settings.rowId )( d, id );
3045
+ }
3046
+ }
3047
+
3048
+ return {
3049
+ data: d,
3050
+ cells: tds
3051
+ };
3052
+ }
3053
+ /**
3054
+ * Create a new TR element (and it's TD children) for a row
3055
+ * @param {object} oSettings dataTables settings object
3056
+ * @param {int} iRow Row to consider
3057
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3058
+ * DataTables will create a row automatically
3059
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3060
+ * if nTr is.
3061
+ * @memberof DataTable#oApi
3062
+ */
3063
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3064
+ {
3065
+ var
3066
+ row = oSettings.aoData[iRow],
3067
+ rowData = row._aData,
3068
+ cells = [],
3069
+ nTr, nTd, oCol,
3070
+ i, iLen;
3071
+
3072
+ if ( row.nTr === null )
3073
+ {
3074
+ nTr = nTrIn || document.createElement('tr');
3075
+
3076
+ row.nTr = nTr;
3077
+ row.anCells = cells;
3078
+
3079
+ /* Use a private property on the node to allow reserve mapping from the node
3080
+ * to the aoData array for fast look up
3081
+ */
3082
+ nTr._DT_RowIndex = iRow;
3083
+
3084
+ /* Special parameters can be given by the data source to be used on the row */
3085
+ _fnRowAttributes( oSettings, row );
3086
+
3087
+ /* Process each column */
3088
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3089
+ {
3090
+ oCol = oSettings.aoColumns[i];
3091
+
3092
+ nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3093
+ nTd._DT_CellIndex = {
3094
+ row: iRow,
3095
+ column: i
3096
+ };
3097
+
3098
+ cells.push( nTd );
3099
+
3100
+ // Need to create the HTML if new, or if a rendering function is defined
3101
+ if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
3102
+ (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3103
+ ) {
3104
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3105
+ }
3106
+
3107
+ /* Add user defined class */
3108
+ if ( oCol.sClass )
3109
+ {
3110
+ nTd.className += ' '+oCol.sClass;
3111
+ }
3112
+
3113
+ // Visibility - add or remove as required
3114
+ if ( oCol.bVisible && ! nTrIn )
3115
+ {
3116
+ nTr.appendChild( nTd );
3117
+ }
3118
+ else if ( ! oCol.bVisible && nTrIn )
3119
+ {
3120
+ nTd.parentNode.removeChild( nTd );
3121
+ }
3122
+
3123
+ if ( oCol.fnCreatedCell )
3124
+ {
3125
+ oCol.fnCreatedCell.call( oSettings.oInstance,
3126
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3127
+ );
3128
+ }
3129
+ }
3130
+
3131
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
3132
+ }
3133
+
3134
+ // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3135
+ // and deployed
3136
+ row.nTr.setAttribute( 'role', 'row' );
3137
+ }
3138
+
3139
+
3140
+ /**
3141
+ * Add attributes to a row based on the special `DT_*` parameters in a data
3142
+ * source object.
3143
+ * @param {object} settings DataTables settings object
3144
+ * @param {object} DataTables row object for the row to be modified
3145
+ * @memberof DataTable#oApi
3146
+ */
3147
+ function _fnRowAttributes( settings, row )
3148
+ {
3149
+ var tr = row.nTr;
3150
+ var data = row._aData;
3151
+
3152
+ if ( tr ) {
3153
+ var id = settings.rowIdFn( data );
3154
+
3155
+ if ( id ) {
3156
+ tr.id = id;
3157
+ }
3158
+
3159
+ if ( data.DT_RowClass ) {
3160
+ // Remove any classes added by DT_RowClass before
3161
+ var a = data.DT_RowClass.split(' ');
3162
+ row.__rowc = row.__rowc ?
3163
+ _unique( row.__rowc.concat( a ) ) :
3164
+ a;
3165
+
3166
+ $(tr)
3167
+ .removeClass( row.__rowc.join(' ') )
3168
+ .addClass( data.DT_RowClass );
3169
+ }
3170
+
3171
+ if ( data.DT_RowAttr ) {
3172
+ $(tr).attr( data.DT_RowAttr );
3173
+ }
3174
+
3175
+ if ( data.DT_RowData ) {
3176
+ $(tr).data( data.DT_RowData );
3177
+ }
3178
+ }
3179
+ }
3180
+
3181
+
3182
+ /**
3183
+ * Create the HTML header for the table
3184
+ * @param {object} oSettings dataTables settings object
3185
+ * @memberof DataTable#oApi
3186
+ */
3187
+ function _fnBuildHead( oSettings )
3188
+ {
3189
+ var i, ien, cell, row, column;
3190
+ var thead = oSettings.nTHead;
3191
+ var tfoot = oSettings.nTFoot;
3192
+ var createHeader = $('th, td', thead).length === 0;
3193
+ var classes = oSettings.oClasses;
3194
+ var columns = oSettings.aoColumns;
3195
+
3196
+ if ( createHeader ) {
3197
+ row = $('<tr/>').appendTo( thead );
3198
+ }
3199
+
3200
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3201
+ column = columns[i];
3202
+ cell = $( column.nTh ).addClass( column.sClass );
3203
+
3204
+ if ( createHeader ) {
3205
+ cell.appendTo( row );
3206
+ }
3207
+
3208
+ // 1.11 move into sorting
3209
+ if ( oSettings.oFeatures.bSort ) {
3210
+ cell.addClass( column.sSortingClass );
3211
+
3212
+ if ( column.bSortable !== false ) {
3213
+ cell
3214
+ .attr( 'tabindex', oSettings.iTabIndex )
3215
+ .attr( 'aria-controls', oSettings.sTableId );
3216
+
3217
+ _fnSortAttachListener( oSettings, column.nTh, i );
3218
+ }
3219
+ }
3220
+
3221
+ if ( column.sTitle != cell[0].innerHTML ) {
3222
+ cell.html( column.sTitle );
3223
+ }
3224
+
3225
+ _fnRenderer( oSettings, 'header' )(
3226
+ oSettings, cell, column, classes
3227
+ );
3228
+ }
3229
+
3230
+ if ( createHeader ) {
3231
+ _fnDetectHeader( oSettings.aoHeader, thead );
3232
+ }
3233
+
3234
+ /* ARIA role for the rows */
3235
+ $(thead).find('>tr').attr('role', 'row');
3236
+
3237
+ /* Deal with the footer - add classes if required */
3238
+ $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3239
+ $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3240
+
3241
+ // Cache the footer cells. Note that we only take the cells from the first
3242
+ // row in the footer. If there is more than one row the user wants to
3243
+ // interact with, they need to use the table().foot() method. Note also this
3244
+ // allows cells to be used for multiple columns using colspan
3245
+ if ( tfoot !== null ) {
3246
+ var cells = oSettings.aoFooter[0];
3247
+
3248
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3249
+ column = columns[i];
3250
+ column.nTf = cells[i].cell;
3251
+
3252
+ if ( column.sClass ) {
3253
+ $(column.nTf).addClass( column.sClass );
3254
+ }
3255
+ }
3256
+ }
3257
+ }
3258
+
3259
+
3260
+ /**
3261
+ * Draw the header (or footer) element based on the column visibility states. The
3262
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
3263
+ * the instantaneous column visibility, to construct the new layout. The grid is
3264
+ * traversed over cell at a time in a rows x columns grid fashion, although each
3265
+ * cell insert can cover multiple elements in the grid - which is tracks using the
3266
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
3267
+ * already a cell in that position.
3268
+ * @param {object} oSettings dataTables settings object
3269
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
3270
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3271
+ * @memberof DataTable#oApi
3272
+ */
3273
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3274
+ {
3275
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3276
+ var aoLocal = [];
3277
+ var aApplied = [];
3278
+ var iColumns = oSettings.aoColumns.length;
3279
+ var iRowspan, iColspan;
3280
+
3281
+ if ( ! aoSource )
3282
+ {
3283
+ return;
3284
+ }
3285
+
3286
+ if ( bIncludeHidden === undefined )
3287
+ {
3288
+ bIncludeHidden = false;
3289
+ }
3290
+
3291
+ /* Make a copy of the master layout array, but without the visible columns in it */
3292
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3293
+ {
3294
+ aoLocal[i] = aoSource[i].slice();
3295
+ aoLocal[i].nTr = aoSource[i].nTr;
3296
+
3297
+ /* Remove any columns which are currently hidden */
3298
+ for ( j=iColumns-1 ; j>=0 ; j-- )
3299
+ {
3300
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3301
+ {
3302
+ aoLocal[i].splice( j, 1 );
3303
+ }
3304
+ }
3305
+
3306
+ /* Prep the applied array - it needs an element for each row */
3307
+ aApplied.push( [] );
3308
+ }
3309
+
3310
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3311
+ {
3312
+ nLocalTr = aoLocal[i].nTr;
3313
+
3314
+ /* All cells are going to be replaced, so empty out the row */
3315
+ if ( nLocalTr )
3316
+ {
3317
+ while( (n = nLocalTr.firstChild) )
3318
+ {
3319
+ nLocalTr.removeChild( n );
3320
+ }
3321
+ }
3322
+
3323
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3324
+ {
3325
+ iRowspan = 1;
3326
+ iColspan = 1;
3327
+
3328
+ /* Check to see if there is already a cell (row/colspan) covering our target
3329
+ * insert point. If there is, then there is nothing to do.
3330
+ */
3331
+ if ( aApplied[i][j] === undefined )
3332
+ {
3333
+ nLocalTr.appendChild( aoLocal[i][j].cell );
3334
+ aApplied[i][j] = 1;
3335
+
3336
+ /* Expand the cell to cover as many rows as needed */
3337
+ while ( aoLocal[i+iRowspan] !== undefined &&
3338
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3339
+ {
3340
+ aApplied[i+iRowspan][j] = 1;
3341
+ iRowspan++;
3342
+ }
3343
+
3344
+ /* Expand the cell to cover as many columns as needed */
3345
+ while ( aoLocal[i][j+iColspan] !== undefined &&
3346
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3347
+ {
3348
+ /* Must update the applied array over the rows for the columns */
3349
+ for ( k=0 ; k<iRowspan ; k++ )
3350
+ {
3351
+ aApplied[i+k][j+iColspan] = 1;
3352
+ }
3353
+ iColspan++;
3354
+ }
3355
+
3356
+ /* Do the actual expansion in the DOM */
3357
+ $(aoLocal[i][j].cell)
3358
+ .attr('rowspan', iRowspan)
3359
+ .attr('colspan', iColspan);
3360
+ }
3361
+ }
3362
+ }
3363
+ }
3364
+
3365
+
3366
+ /**
3367
+ * Insert the required TR nodes into the table for display
3368
+ * @param {object} oSettings dataTables settings object
3369
+ * @memberof DataTable#oApi
3370
+ */
3371
+ function _fnDraw( oSettings )
3372
+ {
3373
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3374
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3375
+ if ( $.inArray( false, aPreDraw ) !== -1 )
3376
+ {
3377
+ _fnProcessingDisplay( oSettings, false );
3378
+ return;
3379
+ }
3380
+
3381
+ var i, iLen, n;
3382
+ var anRows = [];
3383
+ var iRowCount = 0;
3384
+ var asStripeClasses = oSettings.asStripeClasses;
3385
+ var iStripes = asStripeClasses.length;
3386
+ var iOpenRows = oSettings.aoOpenRows.length;
3387
+ var oLang = oSettings.oLanguage;
3388
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
3389
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3390
+ var aiDisplay = oSettings.aiDisplay;
3391
+
3392
+ oSettings.bDrawing = true;
3393
+
3394
+ /* Check and see if we have an initial draw position from state saving */
3395
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3396
+ {
3397
+ oSettings._iDisplayStart = bServerSide ?
3398
+ iInitDisplayStart :
3399
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3400
+ 0 :
3401
+ iInitDisplayStart;
3402
+
3403
+ oSettings.iInitDisplayStart = -1;
3404
+ }
3405
+
3406
+ var iDisplayStart = oSettings._iDisplayStart;
3407
+ var iDisplayEnd = oSettings.fnDisplayEnd();
3408
+
3409
+ /* Server-side processing draw intercept */
3410
+ if ( oSettings.bDeferLoading )
3411
+ {
3412
+ oSettings.bDeferLoading = false;
3413
+ oSettings.iDraw++;
3414
+ _fnProcessingDisplay( oSettings, false );
3415
+ }
3416
+ else if ( !bServerSide )
3417
+ {
3418
+ oSettings.iDraw++;
3419
+ }
3420
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3421
+ {
3422
+ return;
3423
+ }
3424
+
3425
+ if ( aiDisplay.length !== 0 )
3426
+ {
3427
+ var iStart = bServerSide ? 0 : iDisplayStart;
3428
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3429
+
3430
+ for ( var j=iStart ; j<iEnd ; j++ )
3431
+ {
3432
+ var iDataIndex = aiDisplay[j];
3433
+ var aoData = oSettings.aoData[ iDataIndex ];
3434
+ if ( aoData.nTr === null )
3435
+ {
3436
+ _fnCreateTr( oSettings, iDataIndex );
3437
+ }
3438
+
3439
+ var nRow = aoData.nTr;
3440
+
3441
+ /* Remove the old striping classes and then add the new one */
3442
+ if ( iStripes !== 0 )
3443
+ {
3444
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
3445
+ if ( aoData._sRowStripe != sStripe )
3446
+ {
3447
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3448
+ aoData._sRowStripe = sStripe;
3449
+ }
3450
+ }
3451
+
3452
+ // Row callback functions - might want to manipulate the row
3453
+ // iRowCount and j are not currently documented. Are they at all
3454
+ // useful?
3455
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
3456
+ [nRow, aoData._aData, iRowCount, j] );
3457
+
3458
+ anRows.push( nRow );
3459
+ iRowCount++;
3460
+ }
3461
+ }
3462
+ else
3463
+ {
3464
+ /* Table is empty - create a row with an empty message in it */
3465
+ var sZero = oLang.sZeroRecords;
3466
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3467
+ {
3468
+ sZero = oLang.sLoadingRecords;
3469
+ }
3470
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3471
+ {
3472
+ sZero = oLang.sEmptyTable;
3473
+ }
3474
+
3475
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3476
+ .append( $('<td />', {
3477
+ 'valign': 'top',
3478
+ 'colSpan': _fnVisbleColumns( oSettings ),
3479
+ 'class': oSettings.oClasses.sRowEmpty
3480
+ } ).html( sZero ) )[0];
3481
+ }
3482
+
3483
+ /* Header and footer callbacks */
3484
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3485
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3486
+
3487
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3488
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3489
+
3490
+ var body = $(oSettings.nTBody);
3491
+
3492
+ body.children().detach();
3493
+ body.append( $(anRows) );
3494
+
3495
+ /* Call all required callback functions for the end of a draw */
3496
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3497
+
3498
+ /* Draw is complete, sorting and filtering must be as well */
3499
+ oSettings.bSorted = false;
3500
+ oSettings.bFiltered = false;
3501
+ oSettings.bDrawing = false;
3502
+ }
3503
+
3504
+
3505
+ /**
3506
+ * Redraw the table - taking account of the various features which are enabled
3507
+ * @param {object} oSettings dataTables settings object
3508
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
3509
+ * the paging is reset to the first page
3510
+ * @memberof DataTable#oApi
3511
+ */
3512
+ function _fnReDraw( settings, holdPosition )
3513
+ {
3514
+ var
3515
+ features = settings.oFeatures,
3516
+ sort = features.bSort,
3517
+ filter = features.bFilter;
3518
+
3519
+ if ( sort ) {
3520
+ _fnSort( settings );
3521
+ }
3522
+
3523
+ if ( filter ) {
3524
+ _fnFilterComplete( settings, settings.oPreviousSearch );
3525
+ }
3526
+ else {
3527
+ // No filtering, so we want to just use the display master
3528
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
3529
+ }
3530
+
3531
+ if ( holdPosition !== true ) {
3532
+ settings._iDisplayStart = 0;
3533
+ }
3534
+
3535
+ // Let any modules know about the draw hold position state (used by
3536
+ // scrolling internally)
3537
+ settings._drawHold = holdPosition;
3538
+
3539
+ _fnDraw( settings );
3540
+
3541
+ settings._drawHold = false;
3542
+ }
3543
+
3544
+
3545
+ /**
3546
+ * Add the options to the page HTML for the table
3547
+ * @param {object} oSettings dataTables settings object
3548
+ * @memberof DataTable#oApi
3549
+ */
3550
+ function _fnAddOptionsHtml ( oSettings )
3551
+ {
3552
+ var classes = oSettings.oClasses;
3553
+ var table = $(oSettings.nTable);
3554
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3555
+ var features = oSettings.oFeatures;
3556
+
3557
+ // All DataTables are wrapped in a div
3558
+ var insert = $('<div/>', {
3559
+ id: oSettings.sTableId+'_wrapper',
3560
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3561
+ } );
3562
+
3563
+ oSettings.nHolding = holding[0];
3564
+ oSettings.nTableWrapper = insert[0];
3565
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3566
+
3567
+ /* Loop over the user set positioning and place the elements as needed */
3568
+ var aDom = oSettings.sDom.split('');
3569
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
3570
+ for ( var i=0 ; i<aDom.length ; i++ )
3571
+ {
3572
+ featureNode = null;
3573
+ cOption = aDom[i];
3574
+
3575
+ if ( cOption == '<' )
3576
+ {
3577
+ /* New container div */
3578
+ nNewNode = $('<div/>')[0];
3579
+
3580
+ /* Check to see if we should append an id and/or a class name to the container */
3581
+ cNext = aDom[i+1];
3582
+ if ( cNext == "'" || cNext == '"' )
3583
+ {
3584
+ sAttr = "";
3585
+ j = 2;
3586
+ while ( aDom[i+j] != cNext )
3587
+ {
3588
+ sAttr += aDom[i+j];
3589
+ j++;
3590
+ }
3591
+
3592
+ /* Replace jQuery UI constants @todo depreciated */
3593
+ if ( sAttr == "H" )
3594
+ {
3595
+ sAttr = classes.sJUIHeader;
3596
+ }
3597
+ else if ( sAttr == "F" )
3598
+ {
3599
+ sAttr = classes.sJUIFooter;
3600
+ }
3601
+
3602
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3603
+ * breaks the string into parts and applies them as needed
3604
+ */
3605
+ if ( sAttr.indexOf('.') != -1 )
3606
+ {
3607
+ var aSplit = sAttr.split('.');
3608
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3609
+ nNewNode.className = aSplit[1];
3610
+ }
3611
+ else if ( sAttr.charAt(0) == "#" )
3612
+ {
3613
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
3614
+ }
3615
+ else
3616
+ {
3617
+ nNewNode.className = sAttr;
3618
+ }
3619
+
3620
+ i += j; /* Move along the position array */
3621
+ }
3622
+
3623
+ insert.append( nNewNode );
3624
+ insert = $(nNewNode);
3625
+ }
3626
+ else if ( cOption == '>' )
3627
+ {
3628
+ /* End container div */
3629
+ insert = insert.parent();
3630
+ }
3631
+ // @todo Move options into their own plugins?
3632
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3633
+ {
3634
+ /* Length */
3635
+ featureNode = _fnFeatureHtmlLength( oSettings );
3636
+ }
3637
+ else if ( cOption == 'f' && features.bFilter )
3638
+ {
3639
+ /* Filter */
3640
+ featureNode = _fnFeatureHtmlFilter( oSettings );
3641
+ }
3642
+ else if ( cOption == 'r' && features.bProcessing )
3643
+ {
3644
+ /* pRocessing */
3645
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
3646
+ }
3647
+ else if ( cOption == 't' )
3648
+ {
3649
+ /* Table */
3650
+ featureNode = _fnFeatureHtmlTable( oSettings );
3651
+ }
3652
+ else if ( cOption == 'i' && features.bInfo )
3653
+ {
3654
+ /* Info */
3655
+ featureNode = _fnFeatureHtmlInfo( oSettings );
3656
+ }
3657
+ else if ( cOption == 'p' && features.bPaginate )
3658
+ {
3659
+ /* Pagination */
3660
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
3661
+ }
3662
+ else if ( DataTable.ext.feature.length !== 0 )
3663
+ {
3664
+ /* Plug-in features */
3665
+ var aoFeatures = DataTable.ext.feature;
3666
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3667
+ {
3668
+ if ( cOption == aoFeatures[k].cFeature )
3669
+ {
3670
+ featureNode = aoFeatures[k].fnInit( oSettings );
3671
+ break;
3672
+ }
3673
+ }
3674
+ }
3675
+
3676
+ /* Add to the 2D features array */
3677
+ if ( featureNode )
3678
+ {
3679
+ var aanFeatures = oSettings.aanFeatures;
3680
+
3681
+ if ( ! aanFeatures[cOption] )
3682
+ {
3683
+ aanFeatures[cOption] = [];
3684
+ }
3685
+
3686
+ aanFeatures[cOption].push( featureNode );
3687
+ insert.append( featureNode );
3688
+ }
3689
+ }
3690
+
3691
+ /* Built our DOM structure - replace the holding div with what we want */
3692
+ holding.replaceWith( insert );
3693
+ oSettings.nHolding = null;
3694
+ }
3695
+
3696
+
3697
+ /**
3698
+ * Use the DOM source to create up an array of header cells. The idea here is to
3699
+ * create a layout grid (array) of rows x columns, which contains a reference
3700
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
3701
+ * any column / row could be removed and the new grid constructed
3702
+ * @param array {object} aLayout Array to store the calculated layout in
3703
+ * @param {node} nThead The header/footer element for the table
3704
+ * @memberof DataTable#oApi
3705
+ */
3706
+ function _fnDetectHeader ( aLayout, nThead )
3707
+ {
3708
+ var nTrs = $(nThead).children('tr');
3709
+ var nTr, nCell;
3710
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3711
+ var bUnique;
3712
+ var fnShiftCol = function ( a, i, j ) {
3713
+ var k = a[i];
3714
+ while ( k[j] ) {
3715
+ j++;
3716
+ }
3717
+ return j;
3718
+ };
3719
+
3720
+ aLayout.splice( 0, aLayout.length );
3721
+
3722
+ /* We know how many rows there are in the layout - so prep it */
3723
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3724
+ {
3725
+ aLayout.push( [] );
3726
+ }
3727
+
3728
+ /* Calculate a layout array */
3729
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3730
+ {
3731
+ nTr = nTrs[i];
3732
+ iColumn = 0;
3733
+
3734
+ /* For every cell in the row... */
3735
+ nCell = nTr.firstChild;
3736
+ while ( nCell ) {
3737
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
3738
+ nCell.nodeName.toUpperCase() == "TH" )
3739
+ {
3740
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
3741
+ iColspan = nCell.getAttribute('colspan') * 1;
3742
+ iRowspan = nCell.getAttribute('rowspan') * 1;
3743
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3744
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3745
+
3746
+ /* There might be colspan cells already in this row, so shift our target
3747
+ * accordingly
3748
+ */
3749
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
3750
+
3751
+ /* Cache calculation for unique columns */
3752
+ bUnique = iColspan === 1 ? true : false;
3753
+
3754
+ /* If there is col / rowspan, copy the information into the layout grid */
3755
+ for ( l=0 ; l<iColspan ; l++ )
3756
+ {
3757
+ for ( k=0 ; k<iRowspan ; k++ )
3758
+ {
3759
+ aLayout[i+k][iColShifted+l] = {
3760
+ "cell": nCell,
3761
+ "unique": bUnique
3762
+ };
3763
+ aLayout[i+k].nTr = nTr;
3764
+ }
3765
+ }
3766
+ }
3767
+ nCell = nCell.nextSibling;
3768
+ }
3769
+ }
3770
+ }
3771
+
3772
+
3773
+ /**
3774
+ * Get an array of unique th elements, one for each column
3775
+ * @param {object} oSettings dataTables settings object
3776
+ * @param {node} nHeader automatically detect the layout from this node - optional
3777
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3778
+ * @returns array {node} aReturn list of unique th's
3779
+ * @memberof DataTable#oApi
3780
+ */
3781
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3782
+ {
3783
+ var aReturn = [];
3784
+ if ( !aLayout )
3785
+ {
3786
+ aLayout = oSettings.aoHeader;
3787
+ if ( nHeader )
3788
+ {
3789
+ aLayout = [];
3790
+ _fnDetectHeader( aLayout, nHeader );
3791
+ }
3792
+ }
3793
+
3794
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3795
+ {
3796
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3797
+ {
3798
+ if ( aLayout[i][j].unique &&
3799
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
3800
+ {
3801
+ aReturn[j] = aLayout[i][j].cell;
3802
+ }
3803
+ }
3804
+ }
3805
+
3806
+ return aReturn;
3807
+ }
3808
+
3809
+ /**
3810
+ * Create an Ajax call based on the table's settings, taking into account that
3811
+ * parameters can have multiple forms, and backwards compatibility.
3812
+ *
3813
+ * @param {object} oSettings dataTables settings object
3814
+ * @param {array} data Data to send to the server, required by
3815
+ * DataTables - may be augmented by developer callbacks
3816
+ * @param {function} fn Callback function to run when data is obtained
3817
+ */
3818
+ function _fnBuildAjax( oSettings, data, fn )
3819
+ {
3820
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
3821
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3822
+
3823
+ // Convert to object based for 1.10+ if using the old array scheme which can
3824
+ // come from server-side processing or serverParams
3825
+ if ( data && $.isArray(data) ) {
3826
+ var tmp = {};
3827
+ var rbracket = /(.*?)\[\]$/;
3828
+
3829
+ $.each( data, function (key, val) {
3830
+ var match = val.name.match(rbracket);
3831
+
3832
+ if ( match ) {
3833
+ // Support for arrays
3834
+ var name = match[0];
3835
+
3836
+ if ( ! tmp[ name ] ) {
3837
+ tmp[ name ] = [];
3838
+ }
3839
+ tmp[ name ].push( val.value );
3840
+ }
3841
+ else {
3842
+ tmp[val.name] = val.value;
3843
+ }
3844
+ } );
3845
+ data = tmp;
3846
+ }
3847
+
3848
+ var ajaxData;
3849
+ var ajax = oSettings.ajax;
3850
+ var instance = oSettings.oInstance;
3851
+ var callback = function ( json ) {
3852
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3853
+ fn( json );
3854
+ };
3855
+
3856
+ if ( $.isPlainObject( ajax ) && ajax.data )
3857
+ {
3858
+ ajaxData = ajax.data;
3859
+
3860
+ var newData = $.isFunction( ajaxData ) ?
3861
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
3862
+ ajaxData; // an object object or array to merge
3863
+
3864
+ // If the function returned something, use that alone
3865
+ data = $.isFunction( ajaxData ) && newData ?
3866
+ newData :
3867
+ $.extend( true, data, newData );
3868
+
3869
+ // Remove the data property as we've resolved it already and don't want
3870
+ // jQuery to do it again (it is restored at the end of the function)
3871
+ delete ajax.data;
3872
+ }
3873
+
3874
+ var baseAjax = {
3875
+ "data": data,
3876
+ "success": function (json) {
3877
+ var error = json.error || json.sError;
3878
+ if ( error ) {
3879
+ _fnLog( oSettings, 0, error );
3880
+ }
3881
+
3882
+ oSettings.json = json;
3883
+ callback( json );
3884
+ },
3885
+ "dataType": "json",
3886
+ "cache": false,
3887
+ "type": oSettings.sServerMethod,
3888
+ "error": function (xhr, error, thrown) {
3889
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3890
+
3891
+ if ( $.inArray( true, ret ) === -1 ) {
3892
+ if ( error == "parsererror" ) {
3893
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3894
+ }
3895
+ else if ( xhr.readyState === 4 ) {
3896
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
3897
+ }
3898
+ }
3899
+
3900
+ _fnProcessingDisplay( oSettings, false );
3901
+ }
3902
+ };
3903
+
3904
+ // Store the data submitted for the API
3905
+ oSettings.oAjaxData = data;
3906
+
3907
+ // Allow plug-ins and external processes to modify the data
3908
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3909
+
3910
+ if ( oSettings.fnServerData )
3911
+ {
3912
+ // DataTables 1.9- compatibility
3913
+ oSettings.fnServerData.call( instance,
3914
+ oSettings.sAjaxSource,
3915
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3916
+ return { name: key, value: val };
3917
+ } ),
3918
+ callback,
3919
+ oSettings
3920
+ );
3921
+ }
3922
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3923
+ {
3924
+ // DataTables 1.9- compatibility
3925
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3926
+ url: ajax || oSettings.sAjaxSource
3927
+ } ) );
3928
+ }
3929
+ else if ( $.isFunction( ajax ) )
3930
+ {
3931
+ // Is a function - let the caller define what needs to be done
3932
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3933
+ }
3934
+ else
3935
+ {
3936
+ // Object to extend the base settings
3937
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3938
+
3939
+ // Restore for next time around
3940
+ ajax.data = ajaxData;
3941
+ }
3942
+ }
3943
+
3944
+
3945
+ /**
3946
+ * Update the table using an Ajax call
3947
+ * @param {object} settings dataTables settings object
3948
+ * @returns {boolean} Block the table drawing or not
3949
+ * @memberof DataTable#oApi
3950
+ */
3951
+ function _fnAjaxUpdate( settings )
3952
+ {
3953
+ if ( settings.bAjaxDataGet ) {
3954
+ settings.iDraw++;
3955
+ _fnProcessingDisplay( settings, true );
3956
+
3957
+ _fnBuildAjax(
3958
+ settings,
3959
+ _fnAjaxParameters( settings ),
3960
+ function(json) {
3961
+ _fnAjaxUpdateDraw( settings, json );
3962
+ }
3963
+ );
3964
+
3965
+ return false;
3966
+ }
3967
+ return true;
3968
+ }
3969
+
3970
+
3971
+ /**
3972
+ * Build up the parameters in an object needed for a server-side processing
3973
+ * request. Note that this is basically done twice, is different ways - a modern
3974
+ * method which is used by default in DataTables 1.10 which uses objects and
3975
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3976
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
3977
+ * option is set.
3978
+ * @param {object} oSettings dataTables settings object
3979
+ * @returns {bool} block the table drawing or not
3980
+ * @memberof DataTable#oApi
3981
+ */
3982
+ function _fnAjaxParameters( settings )
3983
+ {
3984
+ var
3985
+ columns = settings.aoColumns,
3986
+ columnCount = columns.length,
3987
+ features = settings.oFeatures,
3988
+ preSearch = settings.oPreviousSearch,
3989
+ preColSearch = settings.aoPreSearchCols,
3990
+ i, data = [], dataProp, column, columnSearch,
3991
+ sort = _fnSortFlatten( settings ),
3992
+ displayStart = settings._iDisplayStart,
3993
+ displayLength = features.bPaginate !== false ?
3994
+ settings._iDisplayLength :
3995
+ -1;
3996
+
3997
+ var param = function ( name, value ) {
3998
+ data.push( { 'name': name, 'value': value } );
3999
+ };
4000
+
4001
+ // DataTables 1.9- compatible method
4002
+ param( 'sEcho', settings.iDraw );
4003
+ param( 'iColumns', columnCount );
4004
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4005
+ param( 'iDisplayStart', displayStart );
4006
+ param( 'iDisplayLength', displayLength );
4007
+
4008
+ // DataTables 1.10+ method
4009
+ var d = {
4010
+ draw: settings.iDraw,
4011
+ columns: [],
4012
+ order: [],
4013
+ start: displayStart,
4014
+ length: displayLength,
4015
+ search: {
4016
+ value: preSearch.sSearch,
4017
+ regex: preSearch.bRegex
4018
+ }
4019
+ };
4020
+
4021
+ for ( i=0 ; i<columnCount ; i++ ) {
4022
+ column = columns[i];
4023
+ columnSearch = preColSearch[i];
4024
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4025
+
4026
+ d.columns.push( {
4027
+ data: dataProp,
4028
+ name: column.sName,
4029
+ searchable: column.bSearchable,
4030
+ orderable: column.bSortable,
4031
+ search: {
4032
+ value: columnSearch.sSearch,
4033
+ regex: columnSearch.bRegex
4034
+ }
4035
+ } );
4036
+
4037
+ param( "mDataProp_"+i, dataProp );
4038
+
4039
+ if ( features.bFilter ) {
4040
+ param( 'sSearch_'+i, columnSearch.sSearch );
4041
+ param( 'bRegex_'+i, columnSearch.bRegex );
4042
+ param( 'bSearchable_'+i, column.bSearchable );
4043
+ }
4044
+
4045
+ if ( features.bSort ) {
4046
+ param( 'bSortable_'+i, column.bSortable );
4047
+ }
4048
+ }
4049
+
4050
+ if ( features.bFilter ) {
4051
+ param( 'sSearch', preSearch.sSearch );
4052
+ param( 'bRegex', preSearch.bRegex );
4053
+ }
4054
+
4055
+ if ( features.bSort ) {
4056
+ $.each( sort, function ( i, val ) {
4057
+ d.order.push( { column: val.col, dir: val.dir } );
4058
+
4059
+ param( 'iSortCol_'+i, val.col );
4060
+ param( 'sSortDir_'+i, val.dir );
4061
+ } );
4062
+
4063
+ param( 'iSortingCols', sort.length );
4064
+ }
4065
+
4066
+ // If the legacy.ajax parameter is null, then we automatically decide which
4067
+ // form to use, based on sAjaxSource
4068
+ var legacy = DataTable.ext.legacy.ajax;
4069
+ if ( legacy === null ) {
4070
+ return settings.sAjaxSource ? data : d;
4071
+ }
4072
+
4073
+ // Otherwise, if legacy has been specified then we use that to decide on the
4074
+ // form
4075
+ return legacy ? data : d;
4076
+ }
4077
+
4078
+
4079
+ /**
4080
+ * Data the data from the server (nuking the old) and redraw the table
4081
+ * @param {object} oSettings dataTables settings object
4082
+ * @param {object} json json data return from the server.
4083
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
4084
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4085
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4086
+ * @param {array} json.aaData The data to display on this page
4087
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4088
+ * @memberof DataTable#oApi
4089
+ */
4090
+ function _fnAjaxUpdateDraw ( settings, json )
4091
+ {
4092
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4093
+ // Support both
4094
+ var compat = function ( old, modern ) {
4095
+ return json[old] !== undefined ? json[old] : json[modern];
4096
+ };
4097
+
4098
+ var data = _fnAjaxDataSrc( settings, json );
4099
+ var draw = compat( 'sEcho', 'draw' );
4100
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4101
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4102
+
4103
+ if ( draw ) {
4104
+ // Protect against out of sequence returns
4105
+ if ( draw*1 < settings.iDraw ) {
4106
+ return;
4107
+ }
4108
+ settings.iDraw = draw * 1;
4109
+ }
4110
+
4111
+ _fnClearTable( settings );
4112
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
4113
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4114
+
4115
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4116
+ _fnAddData( settings, data[i] );
4117
+ }
4118
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
4119
+
4120
+ settings.bAjaxDataGet = false;
4121
+ _fnDraw( settings );
4122
+
4123
+ if ( ! settings._bInitComplete ) {
4124
+ _fnInitComplete( settings, json );
4125
+ }
4126
+
4127
+ settings.bAjaxDataGet = true;
4128
+ _fnProcessingDisplay( settings, false );
4129
+ }
4130
+
4131
+
4132
+ /**
4133
+ * Get the data from the JSON data source to use for drawing a table. Using
4134
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4135
+ * source object, or from a processing function.
4136
+ * @param {object} oSettings dataTables settings object
4137
+ * @param {object} json Data source object / array from the server
4138
+ * @return {array} Array of data to use
4139
+ */
4140
+ function _fnAjaxDataSrc ( oSettings, json )
4141
+ {
4142
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4143
+ oSettings.ajax.dataSrc :
4144
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4145
+
4146
+ // Compatibility with 1.9-. In order to read from aaData, check if the
4147
+ // default has been changed, if not, check for aaData
4148
+ if ( dataSrc === 'data' ) {
4149
+ return json.aaData || json[dataSrc];
4150
+ }
4151
+
4152
+ return dataSrc !== "" ?
4153
+ _fnGetObjectDataFn( dataSrc )( json ) :
4154
+ json;
4155
+ }
4156
+
4157
+ /**
4158
+ * Generate the node required for filtering text
4159
+ * @returns {node} Filter control element
4160
+ * @param {object} oSettings dataTables settings object
4161
+ * @memberof DataTable#oApi
4162
+ */
4163
+ function _fnFeatureHtmlFilter ( settings )
4164
+ {
4165
+ var classes = settings.oClasses;
4166
+ var tableId = settings.sTableId;
4167
+ var language = settings.oLanguage;
4168
+ var previousSearch = settings.oPreviousSearch;
4169
+ var features = settings.aanFeatures;
4170
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4171
+
4172
+ var str = language.sSearch;
4173
+ str = str.match(/_INPUT_/) ?
4174
+ str.replace('_INPUT_', input) :
4175
+ str+input;
4176
+
4177
+ var filter = $('<div/>', {
4178
+ 'id': ! features.f ? tableId+'_filter' : null,
4179
+ 'class': classes.sFilter
4180
+ } )
4181
+ .append( $('<label/>' ).append( str ) );
4182
+
4183
+ var searchFn = function() {
4184
+ /* Update all other filter input elements for the new display */
4185
+ var n = features.f;
4186
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4187
+
4188
+ /* Now do the filter */
4189
+ if ( val != previousSearch.sSearch ) {
4190
+ _fnFilterComplete( settings, {
4191
+ "sSearch": val,
4192
+ "bRegex": previousSearch.bRegex,
4193
+ "bSmart": previousSearch.bSmart ,
4194
+ "bCaseInsensitive": previousSearch.bCaseInsensitive
4195
+ } );
4196
+
4197
+ // Need to redraw, without resorting
4198
+ settings._iDisplayStart = 0;
4199
+ _fnDraw( settings );
4200
+ }
4201
+ };
4202
+
4203
+ var searchDelay = settings.searchDelay !== null ?
4204
+ settings.searchDelay :
4205
+ _fnDataSource( settings ) === 'ssp' ?
4206
+ 400 :
4207
+ 0;
4208
+
4209
+ var jqFilter = $('input', filter)
4210
+ .val( previousSearch.sSearch )
4211
+ .attr( 'placeholder', language.sSearchPlaceholder )
4212
+ .on(
4213
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
4214
+ searchDelay ?
4215
+ _fnThrottle( searchFn, searchDelay ) :
4216
+ searchFn
4217
+ )
4218
+ .on( 'keypress.DT', function(e) {
4219
+ /* Prevent form submission */
4220
+ if ( e.keyCode == 13 ) {
4221
+ return false;
4222
+ }
4223
+ } )
4224
+ .attr('aria-controls', tableId);
4225
+
4226
+ // Update the input elements whenever the table is filtered
4227
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4228
+ if ( settings === s ) {
4229
+ // IE9 throws an 'unknown error' if document.activeElement is used
4230
+ // inside an iframe or frame...
4231
+ try {
4232
+ if ( jqFilter[0] !== document.activeElement ) {
4233
+ jqFilter.val( previousSearch.sSearch );
4234
+ }
4235
+ }
4236
+ catch ( e ) {}
4237
+ }
4238
+ } );
4239
+
4240
+ return filter[0];
4241
+ }
4242
+
4243
+
4244
+ /**
4245
+ * Filter the table using both the global filter and column based filtering
4246
+ * @param {object} oSettings dataTables settings object
4247
+ * @param {object} oSearch search information
4248
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4249
+ * @memberof DataTable#oApi
4250
+ */
4251
+ function _fnFilterComplete ( oSettings, oInput, iForce )
4252
+ {
4253
+ var oPrevSearch = oSettings.oPreviousSearch;
4254
+ var aoPrevSearch = oSettings.aoPreSearchCols;
4255
+ var fnSaveFilter = function ( oFilter ) {
4256
+ /* Save the filtering values */
4257
+ oPrevSearch.sSearch = oFilter.sSearch;
4258
+ oPrevSearch.bRegex = oFilter.bRegex;
4259
+ oPrevSearch.bSmart = oFilter.bSmart;
4260
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4261
+ };
4262
+ var fnRegex = function ( o ) {
4263
+ // Backwards compatibility with the bEscapeRegex option
4264
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4265
+ };
4266
+
4267
+ // Resolve any column types that are unknown due to addition or invalidation
4268
+ // @todo As per sort - can this be moved into an event handler?
4269
+ _fnColumnTypes( oSettings );
4270
+
4271
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
4272
+ if ( _fnDataSource( oSettings ) != 'ssp' )
4273
+ {
4274
+ /* Global filter */
4275
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4276
+ fnSaveFilter( oInput );
4277
+
4278
+ /* Now do the individual column filter */
4279
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4280
+ {
4281
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4282
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4283
+ }
4284
+
4285
+ /* Custom filtering */
4286
+ _fnFilterCustom( oSettings );
4287
+ }
4288
+ else
4289
+ {
4290
+ fnSaveFilter( oInput );
4291
+ }
4292
+
4293
+ /* Tell the draw function we have been filtering */
4294
+ oSettings.bFiltered = true;
4295
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4296
+ }
4297
+
4298
+
4299
+ /**
4300
+ * Apply custom filtering functions
4301
+ * @param {object} oSettings dataTables settings object
4302
+ * @memberof DataTable#oApi
4303
+ */
4304
+ function _fnFilterCustom( settings )
4305
+ {
4306
+ var filters = DataTable.ext.search;
4307
+ var displayRows = settings.aiDisplay;
4308
+ var row, rowIdx;
4309
+
4310
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4311
+ var rows = [];
4312
+
4313
+ // Loop over each row and see if it should be included
4314
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4315
+ rowIdx = displayRows[ j ];
4316
+ row = settings.aoData[ rowIdx ];
4317
+
4318
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4319
+ rows.push( rowIdx );
4320
+ }
4321
+ }
4322
+
4323
+ // So the array reference doesn't break set the results into the
4324
+ // existing array
4325
+ displayRows.length = 0;
4326
+ $.merge( displayRows, rows );
4327
+ }
4328
+ }
4329
+
4330
+
4331
+ /**
4332
+ * Filter the table on a per-column basis
4333
+ * @param {object} oSettings dataTables settings object
4334
+ * @param {string} sInput string to filter on
4335
+ * @param {int} iColumn column to filter
4336
+ * @param {bool} bRegex treat search string as a regular expression or not
4337
+ * @param {bool} bSmart use smart filtering or not
4338
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
4339
+ * @memberof DataTable#oApi
4340
+ */
4341
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4342
+ {
4343
+ if ( searchStr === '' ) {
4344
+ return;
4345
+ }
4346
+
4347
+ var data;
4348
+ var out = [];
4349
+ var display = settings.aiDisplay;
4350
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4351
+
4352
+ for ( var i=0 ; i<display.length ; i++ ) {
4353
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4354
+
4355
+ if ( rpSearch.test( data ) ) {
4356
+ out.push( display[i] );
4357
+ }
4358
+ }
4359
+
4360
+ settings.aiDisplay = out;
4361
+ }
4362
+
4363
+
4364
+ /**
4365
+ * Filter the data table based on user input and draw the table
4366
+ * @param {object} settings dataTables settings object
4367
+ * @param {string} input string to filter on
4368
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4369
+ * @param {bool} regex treat as a regular expression or not
4370
+ * @param {bool} smart perform smart filtering or not
4371
+ * @param {bool} caseInsensitive Do case insenstive matching or not
4372
+ * @memberof DataTable#oApi
4373
+ */
4374
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4375
+ {
4376
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4377
+ var prevSearch = settings.oPreviousSearch.sSearch;
4378
+ var displayMaster = settings.aiDisplayMaster;
4379
+ var display, invalidated, i;
4380
+ var filtered = [];
4381
+
4382
+ // Need to take account of custom filtering functions - always filter
4383
+ if ( DataTable.ext.search.length !== 0 ) {
4384
+ force = true;
4385
+ }
4386
+
4387
+ // Check if any of the rows were invalidated
4388
+ invalidated = _fnFilterData( settings );
4389
+
4390
+ // If the input is blank - we just want the full data set
4391
+ if ( input.length <= 0 ) {
4392
+ settings.aiDisplay = displayMaster.slice();
4393
+ }
4394
+ else {
4395
+ // New search - start from the master array
4396
+ if ( invalidated ||
4397
+ force ||
4398
+ prevSearch.length > input.length ||
4399
+ input.indexOf(prevSearch) !== 0 ||
4400
+ settings.bSorted // On resort, the display master needs to be
4401
+ // re-filtered since indexes will have changed
4402
+ ) {
4403
+ settings.aiDisplay = displayMaster.slice();
4404
+ }
4405
+
4406
+ // Search the display array
4407
+ display = settings.aiDisplay;
4408
+
4409
+ for ( i=0 ; i<display.length ; i++ ) {
4410
+ if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4411
+ filtered.push( display[i] );
4412
+ }
4413
+ }
4414
+
4415
+ settings.aiDisplay = filtered;
4416
+ }
4417
+ }
4418
+
4419
+
4420
+ /**
4421
+ * Build a regular expression object suitable for searching a table
4422
+ * @param {string} sSearch string to search for
4423
+ * @param {bool} bRegex treat as a regular expression or not
4424
+ * @param {bool} bSmart perform smart filtering or not
4425
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
4426
+ * @returns {RegExp} constructed object
4427
+ * @memberof DataTable#oApi
4428
+ */
4429
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4430
+ {
4431
+ search = regex ?
4432
+ search :
4433
+ _fnEscapeRegex( search );
4434
+
4435
+ if ( smart ) {
4436
+ /* For smart filtering we want to allow the search to work regardless of
4437
+ * word order. We also want double quoted text to be preserved, so word
4438
+ * order is important - a la google. So this is what we want to
4439
+ * generate:
4440
+ *
4441
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4442
+ */
4443
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4444
+ if ( word.charAt(0) === '"' ) {
4445
+ var m = word.match( /^"(.*)"$/ );
4446
+ word = m ? m[1] : word;
4447
+ }
4448
+
4449
+ return word.replace('"', '');
4450
+ } );
4451
+
4452
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4453
+ }
4454
+
4455
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
4456
+ }
4457
+
4458
+
4459
+ /**
4460
+ * Escape a string such that it can be used in a regular expression
4461
+ * @param {string} sVal string to escape
4462
+ * @returns {string} escaped string
4463
+ * @memberof DataTable#oApi
4464
+ */
4465
+ var _fnEscapeRegex = DataTable.util.escapeRegex;
4466
+
4467
+ var __filter_div = $('<div>')[0];
4468
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
4469
+
4470
+ // Update the filtering data for each row if needed (by invalidation or first run)
4471
+ function _fnFilterData ( settings )
4472
+ {
4473
+ var columns = settings.aoColumns;
4474
+ var column;
4475
+ var i, j, ien, jen, filterData, cellData, row;
4476
+ var fomatters = DataTable.ext.type.search;
4477
+ var wasInvalidated = false;
4478
+
4479
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4480
+ row = settings.aoData[i];
4481
+
4482
+ if ( ! row._aFilterData ) {
4483
+ filterData = [];
4484
+
4485
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4486
+ column = columns[j];
4487
+
4488
+ if ( column.bSearchable ) {
4489
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
4490
+
4491
+ if ( fomatters[ column.sType ] ) {
4492
+ cellData = fomatters[ column.sType ]( cellData );
4493
+ }
4494
+
4495
+ // Search in DataTables 1.10 is string based. In 1.11 this
4496
+ // should be altered to also allow strict type checking.
4497
+ if ( cellData === null ) {
4498
+ cellData = '';
4499
+ }
4500
+
4501
+ if ( typeof cellData !== 'string' && cellData.toString ) {
4502
+ cellData = cellData.toString();
4503
+ }
4504
+ }
4505
+ else {
4506
+ cellData = '';
4507
+ }
4508
+
4509
+ // If it looks like there is an HTML entity in the string,
4510
+ // attempt to decode it so sorting works as expected. Note that
4511
+ // we could use a single line of jQuery to do this, but the DOM
4512
+ // method used here is much faster http://jsperf.com/html-decode
4513
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4514
+ __filter_div.innerHTML = cellData;
4515
+ cellData = __filter_div_textContent ?
4516
+ __filter_div.textContent :
4517
+ __filter_div.innerText;
4518
+ }
4519
+
4520
+ if ( cellData.replace ) {
4521
+ cellData = cellData.replace(/[\r\n]/g, '');
4522
+ }
4523
+
4524
+ filterData.push( cellData );
4525
+ }
4526
+
4527
+ row._aFilterData = filterData;
4528
+ row._sFilterRow = filterData.join(' ');
4529
+ wasInvalidated = true;
4530
+ }
4531
+ }
4532
+
4533
+ return wasInvalidated;
4534
+ }
4535
+
4536
+
4537
+ /**
4538
+ * Convert from the internal Hungarian notation to camelCase for external
4539
+ * interaction
4540
+ * @param {object} obj Object to convert
4541
+ * @returns {object} Inverted object
4542
+ * @memberof DataTable#oApi
4543
+ */
4544
+ function _fnSearchToCamel ( obj )
4545
+ {
4546
+ return {
4547
+ search: obj.sSearch,
4548
+ smart: obj.bSmart,
4549
+ regex: obj.bRegex,
4550
+ caseInsensitive: obj.bCaseInsensitive
4551
+ };
4552
+ }
4553
+
4554
+
4555
+
4556
+ /**
4557
+ * Convert from camelCase notation to the internal Hungarian. We could use the
4558
+ * Hungarian convert function here, but this is cleaner
4559
+ * @param {object} obj Object to convert
4560
+ * @returns {object} Inverted object
4561
+ * @memberof DataTable#oApi
4562
+ */
4563
+ function _fnSearchToHung ( obj )
4564
+ {
4565
+ return {
4566
+ sSearch: obj.search,
4567
+ bSmart: obj.smart,
4568
+ bRegex: obj.regex,
4569
+ bCaseInsensitive: obj.caseInsensitive
4570
+ };
4571
+ }
4572
+
4573
+ /**
4574
+ * Generate the node required for the info display
4575
+ * @param {object} oSettings dataTables settings object
4576
+ * @returns {node} Information element
4577
+ * @memberof DataTable#oApi
4578
+ */
4579
+ function _fnFeatureHtmlInfo ( settings )
4580
+ {
4581
+ var
4582
+ tid = settings.sTableId,
4583
+ nodes = settings.aanFeatures.i,
4584
+ n = $('<div/>', {
4585
+ 'class': settings.oClasses.sInfo,
4586
+ 'id': ! nodes ? tid+'_info' : null
4587
+ } );
4588
+
4589
+ if ( ! nodes ) {
4590
+ // Update display on each draw
4591
+ settings.aoDrawCallback.push( {
4592
+ "fn": _fnUpdateInfo,
4593
+ "sName": "information"
4594
+ } );
4595
+
4596
+ n
4597
+ .attr( 'role', 'status' )
4598
+ .attr( 'aria-live', 'polite' );
4599
+
4600
+ // Table is described by our info div
4601
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4602
+ }
4603
+
4604
+ return n[0];
4605
+ }
4606
+
4607
+
4608
+ /**
4609
+ * Update the information elements in the display
4610
+ * @param {object} settings dataTables settings object
4611
+ * @memberof DataTable#oApi
4612
+ */
4613
+ function _fnUpdateInfo ( settings )
4614
+ {
4615
+ /* Show information about the table */
4616
+ var nodes = settings.aanFeatures.i;
4617
+ if ( nodes.length === 0 ) {
4618
+ return;
4619
+ }
4620
+
4621
+ var
4622
+ lang = settings.oLanguage,
4623
+ start = settings._iDisplayStart+1,
4624
+ end = settings.fnDisplayEnd(),
4625
+ max = settings.fnRecordsTotal(),
4626
+ total = settings.fnRecordsDisplay(),
4627
+ out = total ?
4628
+ lang.sInfo :
4629
+ lang.sInfoEmpty;
4630
+
4631
+ if ( total !== max ) {
4632
+ /* Record set after filtering */
4633
+ out += ' ' + lang.sInfoFiltered;
4634
+ }
4635
+
4636
+ // Convert the macros
4637
+ out += lang.sInfoPostFix;
4638
+ out = _fnInfoMacros( settings, out );
4639
+
4640
+ var callback = lang.fnInfoCallback;
4641
+ if ( callback !== null ) {
4642
+ out = callback.call( settings.oInstance,
4643
+ settings, start, end, max, total, out
4644
+ );
4645
+ }
4646
+
4647
+ $(nodes).html( out );
4648
+ }
4649
+
4650
+
4651
+ function _fnInfoMacros ( settings, str )
4652
+ {
4653
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4654
+ // internally
4655
+ var
4656
+ formatter = settings.fnFormatNumber,
4657
+ start = settings._iDisplayStart+1,
4658
+ len = settings._iDisplayLength,
4659
+ vis = settings.fnRecordsDisplay(),
4660
+ all = len === -1;
4661
+
4662
+ return str.
4663
+ replace(/_START_/g, formatter.call( settings, start ) ).
4664
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4665
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4666
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4667
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4668
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4669
+ }
4670
+
4671
+
4672
+
4673
+ /**
4674
+ * Draw the table for the first time, adding all required features
4675
+ * @param {object} settings dataTables settings object
4676
+ * @memberof DataTable#oApi
4677
+ */
4678
+ function _fnInitialise ( settings )
4679
+ {
4680
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4681
+ var columns = settings.aoColumns, column;
4682
+ var features = settings.oFeatures;
4683
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
4684
+
4685
+ /* Ensure that the table data is fully initialised */
4686
+ if ( ! settings.bInitialised ) {
4687
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4688
+ return;
4689
+ }
4690
+
4691
+ /* Show the display HTML options */
4692
+ _fnAddOptionsHtml( settings );
4693
+
4694
+ /* Build and draw the header / footer for the table */
4695
+ _fnBuildHead( settings );
4696
+ _fnDrawHead( settings, settings.aoHeader );
4697
+ _fnDrawHead( settings, settings.aoFooter );
4698
+
4699
+ /* Okay to show that something is going on now */
4700
+ _fnProcessingDisplay( settings, true );
4701
+
4702
+ /* Calculate sizes for columns */
4703
+ if ( features.bAutoWidth ) {
4704
+ _fnCalculateColumnWidths( settings );
4705
+ }
4706
+
4707
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4708
+ column = columns[i];
4709
+
4710
+ if ( column.sWidth ) {
4711
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
4712
+ }
4713
+ }
4714
+
4715
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
4716
+
4717
+ // If there is default sorting required - let's do it. The sort function
4718
+ // will do the drawing for us. Otherwise we draw the table regardless of the
4719
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
4720
+ // data (show 'loading' message possibly)
4721
+ _fnReDraw( settings );
4722
+
4723
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
4724
+ var dataSrc = _fnDataSource( settings );
4725
+ if ( dataSrc != 'ssp' || deferLoading ) {
4726
+ // if there is an ajax source load the data
4727
+ if ( dataSrc == 'ajax' ) {
4728
+ _fnBuildAjax( settings, [], function(json) {
4729
+ var aData = _fnAjaxDataSrc( settings, json );
4730
+
4731
+ // Got the data - add it to the table
4732
+ for ( i=0 ; i<aData.length ; i++ ) {
4733
+ _fnAddData( settings, aData[i] );
4734
+ }
4735
+
4736
+ // Reset the init display for cookie saving. We've already done
4737
+ // a filter, and therefore cleared it before. So we need to make
4738
+ // it appear 'fresh'
4739
+ settings.iInitDisplayStart = iAjaxStart;
4740
+
4741
+ _fnReDraw( settings );
4742
+
4743
+ _fnProcessingDisplay( settings, false );
4744
+ _fnInitComplete( settings, json );
4745
+ }, settings );
4746
+ }
4747
+ else {
4748
+ _fnProcessingDisplay( settings, false );
4749
+ _fnInitComplete( settings );
4750
+ }
4751
+ }
4752
+ }
4753
+
4754
+
4755
+ /**
4756
+ * Draw the table for the first time, adding all required features
4757
+ * @param {object} oSettings dataTables settings object
4758
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4759
+ * with client-side processing (optional)
4760
+ * @memberof DataTable#oApi
4761
+ */
4762
+ function _fnInitComplete ( settings, json )
4763
+ {
4764
+ settings._bInitComplete = true;
4765
+
4766
+ // When data was added after the initialisation (data or Ajax) we need to
4767
+ // calculate the column sizing
4768
+ if ( json || settings.oInit.aaData ) {
4769
+ _fnAdjustColumnSizing( settings );
4770
+ }
4771
+
4772
+ _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4773
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4774
+ }
4775
+
4776
+
4777
+ function _fnLengthChange ( settings, val )
4778
+ {
4779
+ var len = parseInt( val, 10 );
4780
+ settings._iDisplayLength = len;
4781
+
4782
+ _fnLengthOverflow( settings );
4783
+
4784
+ // Fire length change event
4785
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
4786
+ }
4787
+
4788
+
4789
+ /**
4790
+ * Generate the node required for user display length changing
4791
+ * @param {object} settings dataTables settings object
4792
+ * @returns {node} Display length feature node
4793
+ * @memberof DataTable#oApi
4794
+ */
4795
+ function _fnFeatureHtmlLength ( settings )
4796
+ {
4797
+ var
4798
+ classes = settings.oClasses,
4799
+ tableId = settings.sTableId,
4800
+ menu = settings.aLengthMenu,
4801
+ d2 = $.isArray( menu[0] ),
4802
+ lengths = d2 ? menu[0] : menu,
4803
+ language = d2 ? menu[1] : menu;
4804
+
4805
+ var select = $('<select/>', {
4806
+ 'name': tableId+'_length',
4807
+ 'aria-controls': tableId,
4808
+ 'class': classes.sLengthSelect
4809
+ } );
4810
+
4811
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4812
+ select[0][ i ] = new Option(
4813
+ typeof language[i] === 'number' ?
4814
+ settings.fnFormatNumber( language[i] ) :
4815
+ language[i],
4816
+ lengths[i]
4817
+ );
4818
+ }
4819
+
4820
+ var div = $('<div><label/></div>').addClass( classes.sLength );
4821
+ if ( ! settings.aanFeatures.l ) {
4822
+ div[0].id = tableId+'_length';
4823
+ }
4824
+
4825
+ div.children().append(
4826
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4827
+ );
4828
+
4829
+ // Can't use `select` variable as user might provide their own and the
4830
+ // reference is broken by the use of outerHTML
4831
+ $('select', div)
4832
+ .val( settings._iDisplayLength )
4833
+ .on( 'change.DT', function(e) {
4834
+ _fnLengthChange( settings, $(this).val() );
4835
+ _fnDraw( settings );
4836
+ } );
4837
+
4838
+ // Update node value whenever anything changes the table's length
4839
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4840
+ if ( settings === s ) {
4841
+ $('select', div).val( len );
4842
+ }
4843
+ } );
4844
+
4845
+ return div[0];
4846
+ }
4847
+
4848
+
4849
+
4850
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4851
+ * Note that most of the paging logic is done in
4852
+ * DataTable.ext.pager
4853
+ */
4854
+
4855
+ /**
4856
+ * Generate the node required for default pagination
4857
+ * @param {object} oSettings dataTables settings object
4858
+ * @returns {node} Pagination feature node
4859
+ * @memberof DataTable#oApi
4860
+ */
4861
+ function _fnFeatureHtmlPaginate ( settings )
4862
+ {
4863
+ var
4864
+ type = settings.sPaginationType,
4865
+ plugin = DataTable.ext.pager[ type ],
4866
+ modern = typeof plugin === 'function',
4867
+ redraw = function( settings ) {
4868
+ _fnDraw( settings );
4869
+ },
4870
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4871
+ features = settings.aanFeatures;
4872
+
4873
+ if ( ! modern ) {
4874
+ plugin.fnInit( settings, node, redraw );
4875
+ }
4876
+
4877
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
4878
+ if ( ! features.p )
4879
+ {
4880
+ node.id = settings.sTableId+'_paginate';
4881
+
4882
+ settings.aoDrawCallback.push( {
4883
+ "fn": function( settings ) {
4884
+ if ( modern ) {
4885
+ var
4886
+ start = settings._iDisplayStart,
4887
+ len = settings._iDisplayLength,
4888
+ visRecords = settings.fnRecordsDisplay(),
4889
+ all = len === -1,
4890
+ page = all ? 0 : Math.ceil( start / len ),
4891
+ pages = all ? 1 : Math.ceil( visRecords / len ),
4892
+ buttons = plugin(page, pages),
4893
+ i, ien;
4894
+
4895
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4896
+ _fnRenderer( settings, 'pageButton' )(
4897
+ settings, features.p[i], i, buttons, page, pages
4898
+ );
4899
+ }
4900
+ }
4901
+ else {
4902
+ plugin.fnUpdate( settings, redraw );
4903
+ }
4904
+ },
4905
+ "sName": "pagination"
4906
+ } );
4907
+ }
4908
+
4909
+ return node;
4910
+ }
4911
+
4912
+
4913
+ /**
4914
+ * Alter the display settings to change the page
4915
+ * @param {object} settings DataTables settings object
4916
+ * @param {string|int} action Paging action to take: "first", "previous",
4917
+ * "next" or "last" or page number to jump to (integer)
4918
+ * @param [bool] redraw Automatically draw the update or not
4919
+ * @returns {bool} true page has changed, false - no change
4920
+ * @memberof DataTable#oApi
4921
+ */
4922
+ function _fnPageChange ( settings, action, redraw )
4923
+ {
4924
+ var
4925
+ start = settings._iDisplayStart,
4926
+ len = settings._iDisplayLength,
4927
+ records = settings.fnRecordsDisplay();
4928
+
4929
+ if ( records === 0 || len === -1 )
4930
+ {
4931
+ start = 0;
4932
+ }
4933
+ else if ( typeof action === "number" )
4934
+ {
4935
+ start = action * len;
4936
+
4937
+ if ( start > records )
4938
+ {
4939
+ start = 0;
4940
+ }
4941
+ }
4942
+ else if ( action == "first" )
4943
+ {
4944
+ start = 0;
4945
+ }
4946
+ else if ( action == "previous" )
4947
+ {
4948
+ start = len >= 0 ?
4949
+ start - len :
4950
+ 0;
4951
+
4952
+ if ( start < 0 )
4953
+ {
4954
+ start = 0;
4955
+ }
4956
+ }
4957
+ else if ( action == "next" )
4958
+ {
4959
+ if ( start + len < records )
4960
+ {
4961
+ start += len;
4962
+ }
4963
+ }
4964
+ else if ( action == "last" )
4965
+ {
4966
+ start = Math.floor( (records-1) / len) * len;
4967
+ }
4968
+ else
4969
+ {
4970
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4971
+ }
4972
+
4973
+ var changed = settings._iDisplayStart !== start;
4974
+ settings._iDisplayStart = start;
4975
+
4976
+ if ( changed ) {
4977
+ _fnCallbackFire( settings, null, 'page', [settings] );
4978
+
4979
+ if ( redraw ) {
4980
+ _fnDraw( settings );
4981
+ }
4982
+ }
4983
+
4984
+ return changed;
4985
+ }
4986
+
4987
+
4988
+
4989
+ /**
4990
+ * Generate the node required for the processing node
4991
+ * @param {object} settings dataTables settings object
4992
+ * @returns {node} Processing element
4993
+ * @memberof DataTable#oApi
4994
+ */
4995
+ function _fnFeatureHtmlProcessing ( settings )
4996
+ {
4997
+ return $('<div/>', {
4998
+ 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
4999
+ 'class': settings.oClasses.sProcessing
5000
+ } )
5001
+ .html( settings.oLanguage.sProcessing )
5002
+ .insertBefore( settings.nTable )[0];
5003
+ }
5004
+
5005
+
5006
+ /**
5007
+ * Display or hide the processing indicator
5008
+ * @param {object} settings dataTables settings object
5009
+ * @param {bool} show Show the processing indicator (true) or not (false)
5010
+ * @memberof DataTable#oApi
5011
+ */
5012
+ function _fnProcessingDisplay ( settings, show )
5013
+ {
5014
+ if ( settings.oFeatures.bProcessing ) {
5015
+ $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
5016
+ }
5017
+
5018
+ _fnCallbackFire( settings, null, 'processing', [settings, show] );
5019
+ }
5020
+
5021
+ /**
5022
+ * Add any control elements for the table - specifically scrolling
5023
+ * @param {object} settings dataTables settings object
5024
+ * @returns {node} Node to add to the DOM
5025
+ * @memberof DataTable#oApi
5026
+ */
5027
+ function _fnFeatureHtmlTable ( settings )
5028
+ {
5029
+ var table = $(settings.nTable);
5030
+
5031
+ // Add the ARIA grid role to the table
5032
+ table.attr( 'role', 'grid' );
5033
+
5034
+ // Scrolling from here on in
5035
+ var scroll = settings.oScroll;
5036
+
5037
+ if ( scroll.sX === '' && scroll.sY === '' ) {
5038
+ return settings.nTable;
5039
+ }
5040
+
5041
+ var scrollX = scroll.sX;
5042
+ var scrollY = scroll.sY;
5043
+ var classes = settings.oClasses;
5044
+ var caption = table.children('caption');
5045
+ var captionSide = caption.length ? caption[0]._captionSide : null;
5046
+ var headerClone = $( table[0].cloneNode(false) );
5047
+ var footerClone = $( table[0].cloneNode(false) );
5048
+ var footer = table.children('tfoot');
5049
+ var _div = '<div/>';
5050
+ var size = function ( s ) {
5051
+ return !s ? null : _fnStringToCss( s );
5052
+ };
5053
+
5054
+ if ( ! footer.length ) {
5055
+ footer = null;
5056
+ }
5057
+
5058
+ /*
5059
+ * The HTML structure that we want to generate in this function is:
5060
+ * div - scroller
5061
+ * div - scroll head
5062
+ * div - scroll head inner
5063
+ * table - scroll head table
5064
+ * thead - thead
5065
+ * div - scroll body
5066
+ * table - table (master table)
5067
+ * thead - thead clone for sizing
5068
+ * tbody - tbody
5069
+ * div - scroll foot
5070
+ * div - scroll foot inner
5071
+ * table - scroll foot table
5072
+ * tfoot - tfoot
5073
+ */
5074
+ var scroller = $( _div, { 'class': classes.sScrollWrapper } )
5075
+ .append(
5076
+ $(_div, { 'class': classes.sScrollHead } )
5077
+ .css( {
5078
+ overflow: 'hidden',
5079
+ position: 'relative',
5080
+ border: 0,
5081
+ width: scrollX ? size(scrollX) : '100%'
5082
+ } )
5083
+ .append(
5084
+ $(_div, { 'class': classes.sScrollHeadInner } )
5085
+ .css( {
5086
+ 'box-sizing': 'content-box',
5087
+ width: scroll.sXInner || '100%'
5088
+ } )
5089
+ .append(
5090
+ headerClone
5091
+ .removeAttr('id')
5092
+ .css( 'margin-left', 0 )
5093
+ .append( captionSide === 'top' ? caption : null )
5094
+ .append(
5095
+ table.children('thead')
5096
+ )
5097
+ )
5098
+ )
5099
+ )
5100
+ .append(
5101
+ $(_div, { 'class': classes.sScrollBody } )
5102
+ .css( {
5103
+ position: 'relative',
5104
+ overflow: 'auto',
5105
+ width: size( scrollX )
5106
+ } )
5107
+ .append( table )
5108
+ );
5109
+
5110
+ if ( footer ) {
5111
+ scroller.append(
5112
+ $(_div, { 'class': classes.sScrollFoot } )
5113
+ .css( {
5114
+ overflow: 'hidden',
5115
+ border: 0,
5116
+ width: scrollX ? size(scrollX) : '100%'
5117
+ } )
5118
+ .append(
5119
+ $(_div, { 'class': classes.sScrollFootInner } )
5120
+ .append(
5121
+ footerClone
5122
+ .removeAttr('id')
5123
+ .css( 'margin-left', 0 )
5124
+ .append( captionSide === 'bottom' ? caption : null )
5125
+ .append(
5126
+ table.children('tfoot')
5127
+ )
5128
+ )
5129
+ )
5130
+ );
5131
+ }
5132
+
5133
+ var children = scroller.children();
5134
+ var scrollHead = children[0];
5135
+ var scrollBody = children[1];
5136
+ var scrollFoot = footer ? children[2] : null;
5137
+
5138
+ // When the body is scrolled, then we also want to scroll the headers
5139
+ if ( scrollX ) {
5140
+ $(scrollBody).on( 'scroll.DT', function (e) {
5141
+ var scrollLeft = this.scrollLeft;
5142
+
5143
+ scrollHead.scrollLeft = scrollLeft;
5144
+
5145
+ if ( footer ) {
5146
+ scrollFoot.scrollLeft = scrollLeft;
5147
+ }
5148
+ } );
5149
+ }
5150
+
5151
+ $(scrollBody).css(
5152
+ scrollY && scroll.bCollapse ? 'max-height' : 'height',
5153
+ scrollY
5154
+ );
5155
+
5156
+ settings.nScrollHead = scrollHead;
5157
+ settings.nScrollBody = scrollBody;
5158
+ settings.nScrollFoot = scrollFoot;
5159
+
5160
+ // On redraw - align columns
5161
+ settings.aoDrawCallback.push( {
5162
+ "fn": _fnScrollDraw,
5163
+ "sName": "scrolling"
5164
+ } );
5165
+
5166
+ return scroller[0];
5167
+ }
5168
+
5169
+
5170
+
5171
+ /**
5172
+ * Update the header, footer and body tables for resizing - i.e. column
5173
+ * alignment.
5174
+ *
5175
+ * Welcome to the most horrible function DataTables. The process that this
5176
+ * function follows is basically:
5177
+ * 1. Re-create the table inside the scrolling div
5178
+ * 2. Take live measurements from the DOM
5179
+ * 3. Apply the measurements to align the columns
5180
+ * 4. Clean up
5181
+ *
5182
+ * @param {object} settings dataTables settings object
5183
+ * @memberof DataTable#oApi
5184
+ */
5185
+ function _fnScrollDraw ( settings )
5186
+ {
5187
+ // Given that this is such a monster function, a lot of variables are use
5188
+ // to try and keep the minimised size as small as possible
5189
+ var
5190
+ scroll = settings.oScroll,
5191
+ scrollX = scroll.sX,
5192
+ scrollXInner = scroll.sXInner,
5193
+ scrollY = scroll.sY,
5194
+ barWidth = scroll.iBarWidth,
5195
+ divHeader = $(settings.nScrollHead),
5196
+ divHeaderStyle = divHeader[0].style,
5197
+ divHeaderInner = divHeader.children('div'),
5198
+ divHeaderInnerStyle = divHeaderInner[0].style,
5199
+ divHeaderTable = divHeaderInner.children('table'),
5200
+ divBodyEl = settings.nScrollBody,
5201
+ divBody = $(divBodyEl),
5202
+ divBodyStyle = divBodyEl.style,
5203
+ divFooter = $(settings.nScrollFoot),
5204
+ divFooterInner = divFooter.children('div'),
5205
+ divFooterTable = divFooterInner.children('table'),
5206
+ header = $(settings.nTHead),
5207
+ table = $(settings.nTable),
5208
+ tableEl = table[0],
5209
+ tableStyle = tableEl.style,
5210
+ footer = settings.nTFoot ? $(settings.nTFoot) : null,
5211
+ browser = settings.oBrowser,
5212
+ ie67 = browser.bScrollOversize,
5213
+ dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
5214
+ headerTrgEls, footerTrgEls,
5215
+ headerSrcEls, footerSrcEls,
5216
+ headerCopy, footerCopy,
5217
+ headerWidths=[], footerWidths=[],
5218
+ headerContent=[], footerContent=[],
5219
+ idx, correction, sanityWidth,
5220
+ zeroOut = function(nSizer) {
5221
+ var style = nSizer.style;
5222
+ style.paddingTop = "0";
5223
+ style.paddingBottom = "0";
5224
+ style.borderTopWidth = "0";
5225
+ style.borderBottomWidth = "0";
5226
+ style.height = 0;
5227
+ };
5228
+
5229
+ // If the scrollbar visibility has changed from the last draw, we need to
5230
+ // adjust the column sizes as the table width will have changed to account
5231
+ // for the scrollbar
5232
+ var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
5233
+
5234
+ if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
5235
+ settings.scrollBarVis = scrollBarVis;
5236
+ _fnAdjustColumnSizing( settings );
5237
+ return; // adjust column sizing will call this function again
5238
+ }
5239
+ else {
5240
+ settings.scrollBarVis = scrollBarVis;
5241
+ }
5242
+
5243
+ /*
5244
+ * 1. Re-create the table inside the scrolling div
5245
+ */
5246
+
5247
+ // Remove the old minimised thead and tfoot elements in the inner table
5248
+ table.children('thead, tfoot').remove();
5249
+
5250
+ if ( footer ) {
5251
+ footerCopy = footer.clone().prependTo( table );
5252
+ footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
5253
+ footerSrcEls = footerCopy.find('tr');
5254
+ }
5255
+
5256
+ // Clone the current header and footer elements and then place it into the inner table
5257
+ headerCopy = header.clone().prependTo( table );
5258
+ headerTrgEls = header.find('tr'); // original header is in its own table
5259
+ headerSrcEls = headerCopy.find('tr');
5260
+ headerCopy.find('th, td').removeAttr('tabindex');
5261
+
5262
+
5263
+ /*
5264
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
5265
+ */
5266
+
5267
+ // Remove old sizing and apply the calculated column widths
5268
+ // Get the unique column headers in the newly created (cloned) header. We want to apply the
5269
+ // calculated sizes to this header
5270
+ if ( ! scrollX )
5271
+ {
5272
+ divBodyStyle.width = '100%';
5273
+ divHeader[0].style.width = '100%';
5274
+ }
5275
+
5276
+ $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
5277
+ idx = _fnVisibleToColumnIndex( settings, i );
5278
+ el.style.width = settings.aoColumns[idx].sWidth;
5279
+ } );
5280
+
5281
+ if ( footer ) {
5282
+ _fnApplyToChildren( function(n) {
5283
+ n.style.width = "";
5284
+ }, footerSrcEls );
5285
+ }
5286
+
5287
+ // Size the table as a whole
5288
+ sanityWidth = table.outerWidth();
5289
+ if ( scrollX === "" ) {
5290
+ // No x scrolling
5291
+ tableStyle.width = "100%";
5292
+
5293
+ // IE7 will make the width of the table when 100% include the scrollbar
5294
+ // - which is shouldn't. When there is a scrollbar we need to take this
5295
+ // into account.
5296
+ if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
5297
+ divBody.css('overflow-y') == "scroll")
5298
+ ) {
5299
+ tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
5300
+ }
5301
+
5302
+ // Recalculate the sanity width
5303
+ sanityWidth = table.outerWidth();
5304
+ }
5305
+ else if ( scrollXInner !== "" ) {
5306
+ // legacy x scroll inner has been given - use it
5307
+ tableStyle.width = _fnStringToCss(scrollXInner);
5308
+
5309
+ // Recalculate the sanity width
5310
+ sanityWidth = table.outerWidth();
5311
+ }
5312
+
5313
+ // Hidden header should have zero height, so remove padding and borders. Then
5314
+ // set the width based on the real headers
5315
+
5316
+ // Apply all styles in one pass
5317
+ _fnApplyToChildren( zeroOut, headerSrcEls );
5318
+
5319
+ // Read all widths in next pass
5320
+ _fnApplyToChildren( function(nSizer) {
5321
+ headerContent.push( nSizer.innerHTML );
5322
+ headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5323
+ }, headerSrcEls );
5324
+
5325
+ // Apply all widths in final pass
5326
+ _fnApplyToChildren( function(nToSize, i) {
5327
+ // Only apply widths to the DataTables detected header cells - this
5328
+ // prevents complex headers from having contradictory sizes applied
5329
+ if ( $.inArray( nToSize, dtHeaderCells ) !== -1 ) {
5330
+ nToSize.style.width = headerWidths[i];
5331
+ }
5332
+ }, headerTrgEls );
5333
+
5334
+ $(headerSrcEls).height(0);
5335
+
5336
+ /* Same again with the footer if we have one */
5337
+ if ( footer )
5338
+ {
5339
+ _fnApplyToChildren( zeroOut, footerSrcEls );
5340
+
5341
+ _fnApplyToChildren( function(nSizer) {
5342
+ footerContent.push( nSizer.innerHTML );
5343
+ footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
5344
+ }, footerSrcEls );
5345
+
5346
+ _fnApplyToChildren( function(nToSize, i) {
5347
+ nToSize.style.width = footerWidths[i];
5348
+ }, footerTrgEls );
5349
+
5350
+ $(footerSrcEls).height(0);
5351
+ }
5352
+
5353
+
5354
+ /*
5355
+ * 3. Apply the measurements
5356
+ */
5357
+
5358
+ // "Hide" the header and footer that we used for the sizing. We need to keep
5359
+ // the content of the cell so that the width applied to the header and body
5360
+ // both match, but we want to hide it completely. We want to also fix their
5361
+ // width to what they currently are
5362
+ _fnApplyToChildren( function(nSizer, i) {
5363
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
5364
+ nSizer.style.width = headerWidths[i];
5365
+ }, headerSrcEls );
5366
+
5367
+ if ( footer )
5368
+ {
5369
+ _fnApplyToChildren( function(nSizer, i) {
5370
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+footerContent[i]+'</div>';
5371
+ nSizer.style.width = footerWidths[i];
5372
+ }, footerSrcEls );
5373
+ }
5374
+
5375
+ // Sanity check that the table is of a sensible width. If not then we are going to get
5376
+ // misalignment - try to prevent this by not allowing the table to shrink below its min width
5377
+ if ( table.outerWidth() < sanityWidth )
5378
+ {
5379
+ // The min width depends upon if we have a vertical scrollbar visible or not */
5380
+ correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
5381
+ divBody.css('overflow-y') == "scroll")) ?
5382
+ sanityWidth+barWidth :
5383
+ sanityWidth;
5384
+
5385
+ // IE6/7 are a law unto themselves...
5386
+ if ( ie67 && (divBodyEl.scrollHeight >
5387
+ divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
5388
+ ) {
5389
+ tableStyle.width = _fnStringToCss( correction-barWidth );
5390
+ }
5391
+
5392
+ // And give the user a warning that we've stopped the table getting too small
5393
+ if ( scrollX === "" || scrollXInner !== "" ) {
5394
+ _fnLog( settings, 1, 'Possible column misalignment', 6 );
5395
+ }
5396
+ }
5397
+ else
5398
+ {
5399
+ correction = '100%';
5400
+ }
5401
+
5402
+ // Apply to the container elements
5403
+ divBodyStyle.width = _fnStringToCss( correction );
5404
+ divHeaderStyle.width = _fnStringToCss( correction );
5405
+
5406
+ if ( footer ) {
5407
+ settings.nScrollFoot.style.width = _fnStringToCss( correction );
5408
+ }
5409
+
5410
+
5411
+ /*
5412
+ * 4. Clean up
5413
+ */
5414
+ if ( ! scrollY ) {
5415
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
5416
+ * the scrollbar height from the visible display, rather than adding it on. We need to
5417
+ * set the height in order to sort this. Don't want to do it in any other browsers.
5418
+ */
5419
+ if ( ie67 ) {
5420
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
5421
+ }
5422
+ }
5423
+
5424
+ /* Finally set the width's of the header and footer tables */
5425
+ var iOuterWidth = table.outerWidth();
5426
+ divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
5427
+ divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
5428
+
5429
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
5430
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
5431
+ var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
5432
+ var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
5433
+ divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
5434
+
5435
+ if ( footer ) {
5436
+ divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
5437
+ divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
5438
+ divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
5439
+ }
5440
+
5441
+ // Correct DOM ordering for colgroup - comes before the thead
5442
+ table.children('colgroup').insertBefore( table.children('thead') );
5443
+
5444
+ /* Adjust the position of the header in case we loose the y-scrollbar */
5445
+ divBody.scroll();
5446
+
5447
+ // If sorting or filtering has occurred, jump the scrolling back to the top
5448
+ // only if we aren't holding the position
5449
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
5450
+ divBodyEl.scrollTop = 0;
5451
+ }
5452
+ }
5453
+
5454
+
5455
+
5456
+ /**
5457
+ * Apply a given function to the display child nodes of an element array (typically
5458
+ * TD children of TR rows
5459
+ * @param {function} fn Method to apply to the objects
5460
+ * @param array {nodes} an1 List of elements to look through for display children
5461
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
5462
+ * @memberof DataTable#oApi
5463
+ */
5464
+ function _fnApplyToChildren( fn, an1, an2 )
5465
+ {
5466
+ var index=0, i=0, iLen=an1.length;
5467
+ var nNode1, nNode2;
5468
+
5469
+ while ( i < iLen ) {
5470
+ nNode1 = an1[i].firstChild;
5471
+ nNode2 = an2 ? an2[i].firstChild : null;
5472
+
5473
+ while ( nNode1 ) {
5474
+ if ( nNode1.nodeType === 1 ) {
5475
+ if ( an2 ) {
5476
+ fn( nNode1, nNode2, index );
5477
+ }
5478
+ else {
5479
+ fn( nNode1, index );
5480
+ }
5481
+
5482
+ index++;
5483
+ }
5484
+
5485
+ nNode1 = nNode1.nextSibling;
5486
+ nNode2 = an2 ? nNode2.nextSibling : null;
5487
+ }
5488
+
5489
+ i++;
5490
+ }
5491
+ }
5492
+
5493
+
5494
+
5495
+ var __re_html_remove = /<.*?>/g;
5496
+
5497
+
5498
+ /**
5499
+ * Calculate the width of columns for the table
5500
+ * @param {object} oSettings dataTables settings object
5501
+ * @memberof DataTable#oApi
5502
+ */
5503
+ function _fnCalculateColumnWidths ( oSettings )
5504
+ {
5505
+ var
5506
+ table = oSettings.nTable,
5507
+ columns = oSettings.aoColumns,
5508
+ scroll = oSettings.oScroll,
5509
+ scrollY = scroll.sY,
5510
+ scrollX = scroll.sX,
5511
+ scrollXInner = scroll.sXInner,
5512
+ columnCount = columns.length,
5513
+ visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
5514
+ headerCells = $('th', oSettings.nTHead),
5515
+ tableWidthAttr = table.getAttribute('width'), // from DOM element
5516
+ tableContainer = table.parentNode,
5517
+ userInputs = false,
5518
+ i, column, columnIdx, width, outerWidth,
5519
+ browser = oSettings.oBrowser,
5520
+ ie67 = browser.bScrollOversize;
5521
+
5522
+ var styleWidth = table.style.width;
5523
+ if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
5524
+ tableWidthAttr = styleWidth;
5525
+ }
5526
+
5527
+ /* Convert any user input sizes into pixel sizes */
5528
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5529
+ column = columns[ visibleColumns[i] ];
5530
+
5531
+ if ( column.sWidth !== null ) {
5532
+ column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
5533
+
5534
+ userInputs = true;
5535
+ }
5536
+ }
5537
+
5538
+ /* If the number of columns in the DOM equals the number that we have to
5539
+ * process in DataTables, then we can use the offsets that are created by
5540
+ * the web- browser. No custom sizes can be set in order for this to happen,
5541
+ * nor scrolling used
5542
+ */
5543
+ if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
5544
+ columnCount == _fnVisbleColumns( oSettings ) &&
5545
+ columnCount == headerCells.length
5546
+ ) {
5547
+ for ( i=0 ; i<columnCount ; i++ ) {
5548
+ var colIdx = _fnVisibleToColumnIndex( oSettings, i );
5549
+
5550
+ if ( colIdx !== null ) {
5551
+ columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
5552
+ }
5553
+ }
5554
+ }
5555
+ else
5556
+ {
5557
+ // Otherwise construct a single row, worst case, table with the widest
5558
+ // node in the data, assign any user defined widths, then insert it into
5559
+ // the DOM and allow the browser to do all the hard work of calculating
5560
+ // table widths
5561
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
5562
+ .css( 'visibility', 'hidden' )
5563
+ .removeAttr( 'id' );
5564
+
5565
+ // Clean up the table body
5566
+ tmpTable.find('tbody tr').remove();
5567
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
5568
+
5569
+ // Clone the table header and footer - we can't use the header / footer
5570
+ // from the cloned table, since if scrolling is active, the table's
5571
+ // real header and footer are contained in different table tags
5572
+ tmpTable.find('thead, tfoot').remove();
5573
+ tmpTable
5574
+ .append( $(oSettings.nTHead).clone() )
5575
+ .append( $(oSettings.nTFoot).clone() );
5576
+
5577
+ // Remove any assigned widths from the footer (from scrolling)
5578
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
5579
+
5580
+ // Apply custom sizing to the cloned header
5581
+ headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
5582
+
5583
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5584
+ column = columns[ visibleColumns[i] ];
5585
+
5586
+ headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
5587
+ _fnStringToCss( column.sWidthOrig ) :
5588
+ '';
5589
+
5590
+ // For scrollX we need to force the column width otherwise the
5591
+ // browser will collapse it. If this width is smaller than the
5592
+ // width the column requires, then it will have no effect
5593
+ if ( column.sWidthOrig && scrollX ) {
5594
+ $( headerCells[i] ).append( $('<div/>').css( {
5595
+ width: column.sWidthOrig,
5596
+ margin: 0,
5597
+ padding: 0,
5598
+ border: 0,
5599
+ height: 1
5600
+ } ) );
5601
+ }
5602
+ }
5603
+
5604
+ // Find the widest cell for each column and put it into the table
5605
+ if ( oSettings.aoData.length ) {
5606
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5607
+ columnIdx = visibleColumns[i];
5608
+ column = columns[ columnIdx ];
5609
+
5610
+ $( _fnGetWidestNode( oSettings, columnIdx ) )
5611
+ .clone( false )
5612
+ .append( column.sContentPadding )
5613
+ .appendTo( tr );
5614
+ }
5615
+ }
5616
+
5617
+ // Tidy the temporary table - remove name attributes so there aren't
5618
+ // duplicated in the dom (radio elements for example)
5619
+ $('[name]', tmpTable).removeAttr('name');
5620
+
5621
+ // Table has been built, attach to the document so we can work with it.
5622
+ // A holding element is used, positioned at the top of the container
5623
+ // with minimal height, so it has no effect on if the container scrolls
5624
+ // or not. Otherwise it might trigger scrolling when it actually isn't
5625
+ // needed
5626
+ var holder = $('<div/>').css( scrollX || scrollY ?
5627
+ {
5628
+ position: 'absolute',
5629
+ top: 0,
5630
+ left: 0,
5631
+ height: 1,
5632
+ right: 0,
5633
+ overflow: 'hidden'
5634
+ } :
5635
+ {}
5636
+ )
5637
+ .append( tmpTable )
5638
+ .appendTo( tableContainer );
5639
+
5640
+ // When scrolling (X or Y) we want to set the width of the table as
5641
+ // appropriate. However, when not scrolling leave the table width as it
5642
+ // is. This results in slightly different, but I think correct behaviour
5643
+ if ( scrollX && scrollXInner ) {
5644
+ tmpTable.width( scrollXInner );
5645
+ }
5646
+ else if ( scrollX ) {
5647
+ tmpTable.css( 'width', 'auto' );
5648
+ tmpTable.removeAttr('width');
5649
+
5650
+ // If there is no width attribute or style, then allow the table to
5651
+ // collapse
5652
+ if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
5653
+ tmpTable.width( tableContainer.clientWidth );
5654
+ }
5655
+ }
5656
+ else if ( scrollY ) {
5657
+ tmpTable.width( tableContainer.clientWidth );
5658
+ }
5659
+ else if ( tableWidthAttr ) {
5660
+ tmpTable.width( tableWidthAttr );
5661
+ }
5662
+
5663
+ // Get the width of each column in the constructed table - we need to
5664
+ // know the inner width (so it can be assigned to the other table's
5665
+ // cells) and the outer width so we can calculate the full width of the
5666
+ // table. This is safe since DataTables requires a unique cell for each
5667
+ // column, but if ever a header can span multiple columns, this will
5668
+ // need to be modified.
5669
+ var total = 0;
5670
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
5671
+ var cell = $(headerCells[i]);
5672
+ var border = cell.outerWidth() - cell.width();
5673
+
5674
+ // Use getBounding... where possible (not IE8-) because it can give
5675
+ // sub-pixel accuracy, which we then want to round up!
5676
+ var bounding = browser.bBounding ?
5677
+ Math.ceil( headerCells[i].getBoundingClientRect().width ) :
5678
+ cell.outerWidth();
5679
+
5680
+ // Total is tracked to remove any sub-pixel errors as the outerWidth
5681
+ // of the table might not equal the total given here (IE!).
5682
+ total += bounding;
5683
+
5684
+ // Width for each column to use
5685
+ columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
5686
+ }
5687
+
5688
+ table.style.width = _fnStringToCss( total );
5689
+
5690
+ // Finished with the table - ditch it
5691
+ holder.remove();
5692
+ }
5693
+
5694
+ // If there is a width attr, we want to attach an event listener which
5695
+ // allows the table sizing to automatically adjust when the window is
5696
+ // resized. Use the width attr rather than CSS, since we can't know if the
5697
+ // CSS is a relative value or absolute - DOM read is always px.
5698
+ if ( tableWidthAttr ) {
5699
+ table.style.width = _fnStringToCss( tableWidthAttr );
5700
+ }
5701
+
5702
+ if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
5703
+ var bindResize = function () {
5704
+ $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
5705
+ _fnAdjustColumnSizing( oSettings );
5706
+ } ) );
5707
+ };
5708
+
5709
+ // IE6/7 will crash if we bind a resize event handler on page load.
5710
+ // To be removed in 1.11 which drops IE6/7 support
5711
+ if ( ie67 ) {
5712
+ setTimeout( bindResize, 1000 );
5713
+ }
5714
+ else {
5715
+ bindResize();
5716
+ }
5717
+
5718
+ oSettings._reszEvt = true;
5719
+ }
5720
+ }
5721
+
5722
+
5723
+ /**
5724
+ * Throttle the calls to a function. Arguments and context are maintained for
5725
+ * the throttled function
5726
+ * @param {function} fn Function to be called
5727
+ * @param {int} [freq=200] call frequency in mS
5728
+ * @returns {function} wrapped function
5729
+ * @memberof DataTable#oApi
5730
+ */
5731
+ var _fnThrottle = DataTable.util.throttle;
5732
+
5733
+
5734
+ /**
5735
+ * Convert a CSS unit width to pixels (e.g. 2em)
5736
+ * @param {string} width width to be converted
5737
+ * @param {node} parent parent to get the with for (required for relative widths) - optional
5738
+ * @returns {int} width in pixels
5739
+ * @memberof DataTable#oApi
5740
+ */
5741
+ function _fnConvertToWidth ( width, parent )
5742
+ {
5743
+ if ( ! width ) {
5744
+ return 0;
5745
+ }
5746
+
5747
+ var n = $('<div/>')
5748
+ .css( 'width', _fnStringToCss( width ) )
5749
+ .appendTo( parent || document.body );
5750
+
5751
+ var val = n[0].offsetWidth;
5752
+ n.remove();
5753
+
5754
+ return val;
5755
+ }
5756
+
5757
+
5758
+ /**
5759
+ * Get the widest node
5760
+ * @param {object} settings dataTables settings object
5761
+ * @param {int} colIdx column of interest
5762
+ * @returns {node} widest table node
5763
+ * @memberof DataTable#oApi
5764
+ */
5765
+ function _fnGetWidestNode( settings, colIdx )
5766
+ {
5767
+ var idx = _fnGetMaxLenString( settings, colIdx );
5768
+ if ( idx < 0 ) {
5769
+ return null;
5770
+ }
5771
+
5772
+ var data = settings.aoData[ idx ];
5773
+ return ! data.nTr ? // Might not have been created when deferred rendering
5774
+ $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
5775
+ data.anCells[ colIdx ];
5776
+ }
5777
+
5778
+
5779
+ /**
5780
+ * Get the maximum strlen for each data column
5781
+ * @param {object} settings dataTables settings object
5782
+ * @param {int} colIdx column of interest
5783
+ * @returns {string} max string length for each column
5784
+ * @memberof DataTable#oApi
5785
+ */
5786
+ function _fnGetMaxLenString( settings, colIdx )
5787
+ {
5788
+ var s, max=-1, maxIdx = -1;
5789
+
5790
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
5791
+ s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
5792
+ s = s.replace( __re_html_remove, '' );
5793
+ s = s.replace( /&nbsp;/g, ' ' );
5794
+
5795
+ if ( s.length > max ) {
5796
+ max = s.length;
5797
+ maxIdx = i;
5798
+ }
5799
+ }
5800
+
5801
+ return maxIdx;
5802
+ }
5803
+
5804
+
5805
+ /**
5806
+ * Append a CSS unit (only if required) to a string
5807
+ * @param {string} value to css-ify
5808
+ * @returns {string} value with css unit
5809
+ * @memberof DataTable#oApi
5810
+ */
5811
+ function _fnStringToCss( s )
5812
+ {
5813
+ if ( s === null ) {
5814
+ return '0px';
5815
+ }
5816
+
5817
+ if ( typeof s == 'number' ) {
5818
+ return s < 0 ?
5819
+ '0px' :
5820
+ s+'px';
5821
+ }
5822
+
5823
+ // Check it has a unit character already
5824
+ return s.match(/\d$/) ?
5825
+ s+'px' :
5826
+ s;
5827
+ }
5828
+
5829
+
5830
+
5831
+ function _fnSortFlatten ( settings )
5832
+ {
5833
+ var
5834
+ i, iLen, k, kLen,
5835
+ aSort = [],
5836
+ aiOrig = [],
5837
+ aoColumns = settings.aoColumns,
5838
+ aDataSort, iCol, sType, srcCol,
5839
+ fixed = settings.aaSortingFixed,
5840
+ fixedObj = $.isPlainObject( fixed ),
5841
+ nestedSort = [],
5842
+ add = function ( a ) {
5843
+ if ( a.length && ! $.isArray( a[0] ) ) {
5844
+ // 1D array
5845
+ nestedSort.push( a );
5846
+ }
5847
+ else {
5848
+ // 2D array
5849
+ $.merge( nestedSort, a );
5850
+ }
5851
+ };
5852
+
5853
+ // Build the sort array, with pre-fix and post-fix options if they have been
5854
+ // specified
5855
+ if ( $.isArray( fixed ) ) {
5856
+ add( fixed );
5857
+ }
5858
+
5859
+ if ( fixedObj && fixed.pre ) {
5860
+ add( fixed.pre );
5861
+ }
5862
+
5863
+ add( settings.aaSorting );
5864
+
5865
+ if (fixedObj && fixed.post ) {
5866
+ add( fixed.post );
5867
+ }
5868
+
5869
+ for ( i=0 ; i<nestedSort.length ; i++ )
5870
+ {
5871
+ srcCol = nestedSort[i][0];
5872
+ aDataSort = aoColumns[ srcCol ].aDataSort;
5873
+
5874
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
5875
+ {
5876
+ iCol = aDataSort[k];
5877
+ sType = aoColumns[ iCol ].sType || 'string';
5878
+
5879
+ if ( nestedSort[i]._idx === undefined ) {
5880
+ nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
5881
+ }
5882
+
5883
+ aSort.push( {
5884
+ src: srcCol,
5885
+ col: iCol,
5886
+ dir: nestedSort[i][1],
5887
+ index: nestedSort[i]._idx,
5888
+ type: sType,
5889
+ formatter: DataTable.ext.type.order[ sType+"-pre" ]
5890
+ } );
5891
+ }
5892
+ }
5893
+
5894
+ return aSort;
5895
+ }
5896
+
5897
+ /**
5898
+ * Change the order of the table
5899
+ * @param {object} oSettings dataTables settings object
5900
+ * @memberof DataTable#oApi
5901
+ * @todo This really needs split up!
5902
+ */
5903
+ function _fnSort ( oSettings )
5904
+ {
5905
+ var
5906
+ i, ien, iLen, j, jLen, k, kLen,
5907
+ sDataType, nTh,
5908
+ aiOrig = [],
5909
+ oExtSort = DataTable.ext.type.order,
5910
+ aoData = oSettings.aoData,
5911
+ aoColumns = oSettings.aoColumns,
5912
+ aDataSort, data, iCol, sType, oSort,
5913
+ formatters = 0,
5914
+ sortCol,
5915
+ displayMaster = oSettings.aiDisplayMaster,
5916
+ aSort;
5917
+
5918
+ // Resolve any column types that are unknown due to addition or invalidation
5919
+ // @todo Can this be moved into a 'data-ready' handler which is called when
5920
+ // data is going to be used in the table?
5921
+ _fnColumnTypes( oSettings );
5922
+
5923
+ aSort = _fnSortFlatten( oSettings );
5924
+
5925
+ for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
5926
+ sortCol = aSort[i];
5927
+
5928
+ // Track if we can use the fast sort algorithm
5929
+ if ( sortCol.formatter ) {
5930
+ formatters++;
5931
+ }
5932
+
5933
+ // Load the data needed for the sort, for each cell
5934
+ _fnSortData( oSettings, sortCol.col );
5935
+ }
5936
+
5937
+ /* No sorting required if server-side or no sorting array */
5938
+ if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
5939
+ {
5940
+ // Create a value - key array of the current row positions such that we can use their
5941
+ // current position during the sort, if values match, in order to perform stable sorting
5942
+ for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
5943
+ aiOrig[ displayMaster[i] ] = i;
5944
+ }
5945
+
5946
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
5947
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
5948
+ * follow on it's own, but this is what we want (example two column sorting):
5949
+ * fnLocalSorting = function(a,b){
5950
+ * var iTest;
5951
+ * iTest = oSort['string-asc']('data11', 'data12');
5952
+ * if (iTest !== 0)
5953
+ * return iTest;
5954
+ * iTest = oSort['numeric-desc']('data21', 'data22');
5955
+ * if (iTest !== 0)
5956
+ * return iTest;
5957
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
5958
+ * }
5959
+ * Basically we have a test for each sorting column, if the data in that column is equal,
5960
+ * test the next column. If all columns match, then we use a numeric sort on the row
5961
+ * positions in the original data array to provide a stable sort.
5962
+ *
5963
+ * Note - I know it seems excessive to have two sorting methods, but the first is around
5964
+ * 15% faster, so the second is only maintained for backwards compatibility with sorting
5965
+ * methods which do not have a pre-sort formatting function.
5966
+ */
5967
+ if ( formatters === aSort.length ) {
5968
+ // All sort types have formatting functions
5969
+ displayMaster.sort( function ( a, b ) {
5970
+ var
5971
+ x, y, k, test, sort,
5972
+ len=aSort.length,
5973
+ dataA = aoData[a]._aSortData,
5974
+ dataB = aoData[b]._aSortData;
5975
+
5976
+ for ( k=0 ; k<len ; k++ ) {
5977
+ sort = aSort[k];
5978
+
5979
+ x = dataA[ sort.col ];
5980
+ y = dataB[ sort.col ];
5981
+
5982
+ test = x<y ? -1 : x>y ? 1 : 0;
5983
+ if ( test !== 0 ) {
5984
+ return sort.dir === 'asc' ? test : -test;
5985
+ }
5986
+ }
5987
+
5988
+ x = aiOrig[a];
5989
+ y = aiOrig[b];
5990
+ return x<y ? -1 : x>y ? 1 : 0;
5991
+ } );
5992
+ }
5993
+ else {
5994
+ // Depreciated - remove in 1.11 (providing a plug-in option)
5995
+ // Not all sort types have formatting methods, so we have to call their sorting
5996
+ // methods.
5997
+ displayMaster.sort( function ( a, b ) {
5998
+ var
5999
+ x, y, k, l, test, sort, fn,
6000
+ len=aSort.length,
6001
+ dataA = aoData[a]._aSortData,
6002
+ dataB = aoData[b]._aSortData;
6003
+
6004
+ for ( k=0 ; k<len ; k++ ) {
6005
+ sort = aSort[k];
6006
+
6007
+ x = dataA[ sort.col ];
6008
+ y = dataB[ sort.col ];
6009
+
6010
+ fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
6011
+ test = fn( x, y );
6012
+ if ( test !== 0 ) {
6013
+ return test;
6014
+ }
6015
+ }
6016
+
6017
+ x = aiOrig[a];
6018
+ y = aiOrig[b];
6019
+ return x<y ? -1 : x>y ? 1 : 0;
6020
+ } );
6021
+ }
6022
+ }
6023
+
6024
+ /* Tell the draw function that we have sorted the data */
6025
+ oSettings.bSorted = true;
6026
+ }
6027
+
6028
+
6029
+ function _fnSortAria ( settings )
6030
+ {
6031
+ var label;
6032
+ var nextSort;
6033
+ var columns = settings.aoColumns;
6034
+ var aSort = _fnSortFlatten( settings );
6035
+ var oAria = settings.oLanguage.oAria;
6036
+
6037
+ // ARIA attributes - need to loop all columns, to update all (removing old
6038
+ // attributes as needed)
6039
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
6040
+ {
6041
+ var col = columns[i];
6042
+ var asSorting = col.asSorting;
6043
+ var sTitle = col.sTitle.replace( /<.*?>/g, "" );
6044
+ var th = col.nTh;
6045
+
6046
+ // IE7 is throwing an error when setting these properties with jQuery's
6047
+ // attr() and removeAttr() methods...
6048
+ th.removeAttribute('aria-sort');
6049
+
6050
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
6051
+ if ( col.bSortable ) {
6052
+ if ( aSort.length > 0 && aSort[0].col == i ) {
6053
+ th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
6054
+ nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
6055
+ }
6056
+ else {
6057
+ nextSort = asSorting[0];
6058
+ }
6059
+
6060
+ label = sTitle + ( nextSort === "asc" ?
6061
+ oAria.sSortAscending :
6062
+ oAria.sSortDescending
6063
+ );
6064
+ }
6065
+ else {
6066
+ label = sTitle;
6067
+ }
6068
+
6069
+ th.setAttribute('aria-label', label);
6070
+ }
6071
+ }
6072
+
6073
+
6074
+ /**
6075
+ * Function to run on user sort request
6076
+ * @param {object} settings dataTables settings object
6077
+ * @param {node} attachTo node to attach the handler to
6078
+ * @param {int} colIdx column sorting index
6079
+ * @param {boolean} [append=false] Append the requested sort to the existing
6080
+ * sort if true (i.e. multi-column sort)
6081
+ * @param {function} [callback] callback function
6082
+ * @memberof DataTable#oApi
6083
+ */
6084
+ function _fnSortListener ( settings, colIdx, append, callback )
6085
+ {
6086
+ var col = settings.aoColumns[ colIdx ];
6087
+ var sorting = settings.aaSorting;
6088
+ var asSorting = col.asSorting;
6089
+ var nextSortIdx;
6090
+ var next = function ( a, overflow ) {
6091
+ var idx = a._idx;
6092
+ if ( idx === undefined ) {
6093
+ idx = $.inArray( a[1], asSorting );
6094
+ }
6095
+
6096
+ return idx+1 < asSorting.length ?
6097
+ idx+1 :
6098
+ overflow ?
6099
+ null :
6100
+ 0;
6101
+ };
6102
+
6103
+ // Convert to 2D array if needed
6104
+ if ( typeof sorting[0] === 'number' ) {
6105
+ sorting = settings.aaSorting = [ sorting ];
6106
+ }
6107
+
6108
+ // If appending the sort then we are multi-column sorting
6109
+ if ( append && settings.oFeatures.bSortMulti ) {
6110
+ // Are we already doing some kind of sort on this column?
6111
+ var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
6112
+
6113
+ if ( sortIdx !== -1 ) {
6114
+ // Yes, modify the sort
6115
+ nextSortIdx = next( sorting[sortIdx], true );
6116
+
6117
+ if ( nextSortIdx === null && sorting.length === 1 ) {
6118
+ nextSortIdx = 0; // can't remove sorting completely
6119
+ }
6120
+
6121
+ if ( nextSortIdx === null ) {
6122
+ sorting.splice( sortIdx, 1 );
6123
+ }
6124
+ else {
6125
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
6126
+ sorting[sortIdx]._idx = nextSortIdx;
6127
+ }
6128
+ }
6129
+ else {
6130
+ // No sort on this column yet
6131
+ sorting.push( [ colIdx, asSorting[0], 0 ] );
6132
+ sorting[sorting.length-1]._idx = 0;
6133
+ }
6134
+ }
6135
+ else if ( sorting.length && sorting[0][0] == colIdx ) {
6136
+ // Single column - already sorting on this column, modify the sort
6137
+ nextSortIdx = next( sorting[0] );
6138
+
6139
+ sorting.length = 1;
6140
+ sorting[0][1] = asSorting[ nextSortIdx ];
6141
+ sorting[0]._idx = nextSortIdx;
6142
+ }
6143
+ else {
6144
+ // Single column - sort only on this column
6145
+ sorting.length = 0;
6146
+ sorting.push( [ colIdx, asSorting[0] ] );
6147
+ sorting[0]._idx = 0;
6148
+ }
6149
+
6150
+ // Run the sort by calling a full redraw
6151
+ _fnReDraw( settings );
6152
+
6153
+ // callback used for async user interaction
6154
+ if ( typeof callback == 'function' ) {
6155
+ callback( settings );
6156
+ }
6157
+ }
6158
+
6159
+
6160
+ /**
6161
+ * Attach a sort handler (click) to a node
6162
+ * @param {object} settings dataTables settings object
6163
+ * @param {node} attachTo node to attach the handler to
6164
+ * @param {int} colIdx column sorting index
6165
+ * @param {function} [callback] callback function
6166
+ * @memberof DataTable#oApi
6167
+ */
6168
+ function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
6169
+ {
6170
+ var col = settings.aoColumns[ colIdx ];
6171
+
6172
+ _fnBindAction( attachTo, {}, function (e) {
6173
+ /* If the column is not sortable - don't to anything */
6174
+ if ( col.bSortable === false ) {
6175
+ return;
6176
+ }
6177
+
6178
+ // If processing is enabled use a timeout to allow the processing
6179
+ // display to be shown - otherwise to it synchronously
6180
+ if ( settings.oFeatures.bProcessing ) {
6181
+ _fnProcessingDisplay( settings, true );
6182
+
6183
+ setTimeout( function() {
6184
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
6185
+
6186
+ // In server-side processing, the draw callback will remove the
6187
+ // processing display
6188
+ if ( _fnDataSource( settings ) !== 'ssp' ) {
6189
+ _fnProcessingDisplay( settings, false );
6190
+ }
6191
+ }, 0 );
6192
+ }
6193
+ else {
6194
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
6195
+ }
6196
+ } );
6197
+ }
6198
+
6199
+
6200
+ /**
6201
+ * Set the sorting classes on table's body, Note: it is safe to call this function
6202
+ * when bSort and bSortClasses are false
6203
+ * @param {object} oSettings dataTables settings object
6204
+ * @memberof DataTable#oApi
6205
+ */
6206
+ function _fnSortingClasses( settings )
6207
+ {
6208
+ var oldSort = settings.aLastSort;
6209
+ var sortClass = settings.oClasses.sSortColumn;
6210
+ var sort = _fnSortFlatten( settings );
6211
+ var features = settings.oFeatures;
6212
+ var i, ien, colIdx;
6213
+
6214
+ if ( features.bSort && features.bSortClasses ) {
6215
+ // Remove old sorting classes
6216
+ for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
6217
+ colIdx = oldSort[i].src;
6218
+
6219
+ // Remove column sorting
6220
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
6221
+ .removeClass( sortClass + (i<2 ? i+1 : 3) );
6222
+ }
6223
+
6224
+ // Add new column sorting
6225
+ for ( i=0, ien=sort.length ; i<ien ; i++ ) {
6226
+ colIdx = sort[i].src;
6227
+
6228
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
6229
+ .addClass( sortClass + (i<2 ? i+1 : 3) );
6230
+ }
6231
+ }
6232
+
6233
+ settings.aLastSort = sort;
6234
+ }
6235
+
6236
+
6237
+ // Get the data to sort a column, be it from cache, fresh (populating the
6238
+ // cache), or from a sort formatter
6239
+ function _fnSortData( settings, idx )
6240
+ {
6241
+ // Custom sorting function - provided by the sort data type
6242
+ var column = settings.aoColumns[ idx ];
6243
+ var customSort = DataTable.ext.order[ column.sSortDataType ];
6244
+ var customData;
6245
+
6246
+ if ( customSort ) {
6247
+ customData = customSort.call( settings.oInstance, settings, idx,
6248
+ _fnColumnIndexToVisible( settings, idx )
6249
+ );
6250
+ }
6251
+
6252
+ // Use / populate cache
6253
+ var row, cellData;
6254
+ var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
6255
+
6256
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
6257
+ row = settings.aoData[i];
6258
+
6259
+ if ( ! row._aSortData ) {
6260
+ row._aSortData = [];
6261
+ }
6262
+
6263
+ if ( ! row._aSortData[idx] || customSort ) {
6264
+ cellData = customSort ?
6265
+ customData[i] : // If there was a custom sort function, use data from there
6266
+ _fnGetCellData( settings, i, idx, 'sort' );
6267
+
6268
+ row._aSortData[ idx ] = formatter ?
6269
+ formatter( cellData ) :
6270
+ cellData;
6271
+ }
6272
+ }
6273
+ }
6274
+
6275
+
6276
+
6277
+ /**
6278
+ * Save the state of a table
6279
+ * @param {object} oSettings dataTables settings object
6280
+ * @memberof DataTable#oApi
6281
+ */
6282
+ function _fnSaveState ( settings )
6283
+ {
6284
+ if ( !settings.oFeatures.bStateSave || settings.bDestroying )
6285
+ {
6286
+ return;
6287
+ }
6288
+
6289
+ /* Store the interesting variables */
6290
+ var state = {
6291
+ time: +new Date(),
6292
+ start: settings._iDisplayStart,
6293
+ length: settings._iDisplayLength,
6294
+ order: $.extend( true, [], settings.aaSorting ),
6295
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
6296
+ columns: $.map( settings.aoColumns, function ( col, i ) {
6297
+ return {
6298
+ visible: col.bVisible,
6299
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
6300
+ };
6301
+ } )
6302
+ };
6303
+
6304
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
6305
+
6306
+ settings.oSavedState = state;
6307
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
6308
+ }
6309
+
6310
+
6311
+ /**
6312
+ * Attempt to load a saved table state
6313
+ * @param {object} oSettings dataTables settings object
6314
+ * @param {object} oInit DataTables init object so we can override settings
6315
+ * @param {function} callback Callback to execute when the state has been loaded
6316
+ * @memberof DataTable#oApi
6317
+ */
6318
+ function _fnLoadState ( settings, oInit, callback )
6319
+ {
6320
+ var i, ien;
6321
+ var columns = settings.aoColumns;
6322
+ var loaded = function ( s ) {
6323
+ if ( ! s || ! s.time ) {
6324
+ callback();
6325
+ return;
6326
+ }
6327
+
6328
+ // Allow custom and plug-in manipulation functions to alter the saved data set and
6329
+ // cancelling of loading by returning false
6330
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
6331
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
6332
+ callback();
6333
+ return;
6334
+ }
6335
+
6336
+ // Reject old data
6337
+ var duration = settings.iStateDuration;
6338
+ if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
6339
+ callback();
6340
+ return;
6341
+ }
6342
+
6343
+ // Number of columns have changed - all bets are off, no restore of settings
6344
+ if ( s.columns && columns.length !== s.columns.length ) {
6345
+ callback();
6346
+ return;
6347
+ }
6348
+
6349
+ // Store the saved state so it might be accessed at any time
6350
+ settings.oLoadedState = $.extend( true, {}, s );
6351
+
6352
+ // Restore key features - todo - for 1.11 this needs to be done by
6353
+ // subscribed events
6354
+ if ( s.start !== undefined ) {
6355
+ settings._iDisplayStart = s.start;
6356
+ settings.iInitDisplayStart = s.start;
6357
+ }
6358
+ if ( s.length !== undefined ) {
6359
+ settings._iDisplayLength = s.length;
6360
+ }
6361
+
6362
+ // Order
6363
+ if ( s.order !== undefined ) {
6364
+ settings.aaSorting = [];
6365
+ $.each( s.order, function ( i, col ) {
6366
+ settings.aaSorting.push( col[0] >= columns.length ?
6367
+ [ 0, col[1] ] :
6368
+ col
6369
+ );
6370
+ } );
6371
+ }
6372
+
6373
+ // Search
6374
+ if ( s.search !== undefined ) {
6375
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
6376
+ }
6377
+
6378
+ // Columns
6379
+ //
6380
+ if ( s.columns ) {
6381
+ for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
6382
+ var col = s.columns[i];
6383
+
6384
+ // Visibility
6385
+ if ( col.visible !== undefined ) {
6386
+ columns[i].bVisible = col.visible;
6387
+ }
6388
+
6389
+ // Search
6390
+ if ( col.search !== undefined ) {
6391
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
6392
+ }
6393
+ }
6394
+ }
6395
+
6396
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
6397
+ callback();
6398
+ }
6399
+
6400
+ if ( ! settings.oFeatures.bStateSave ) {
6401
+ callback();
6402
+ return;
6403
+ }
6404
+
6405
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
6406
+
6407
+ if ( state !== undefined ) {
6408
+ loaded( state );
6409
+ }
6410
+ // otherwise, wait for the loaded callback to be executed
6411
+ }
6412
+
6413
+
6414
+ /**
6415
+ * Return the settings object for a particular table
6416
+ * @param {node} table table we are using as a dataTable
6417
+ * @returns {object} Settings object - or null if not found
6418
+ * @memberof DataTable#oApi
6419
+ */
6420
+ function _fnSettingsFromNode ( table )
6421
+ {
6422
+ var settings = DataTable.settings;
6423
+ var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
6424
+
6425
+ return idx !== -1 ?
6426
+ settings[ idx ] :
6427
+ null;
6428
+ }
6429
+
6430
+
6431
+ /**
6432
+ * Log an error message
6433
+ * @param {object} settings dataTables settings object
6434
+ * @param {int} level log error messages, or display them to the user
6435
+ * @param {string} msg error message
6436
+ * @param {int} tn Technical note id to get more information about the error.
6437
+ * @memberof DataTable#oApi
6438
+ */
6439
+ function _fnLog( settings, level, msg, tn )
6440
+ {
6441
+ msg = 'DataTables warning: '+
6442
+ (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
6443
+
6444
+ if ( tn ) {
6445
+ msg += '. For more information about this error, please see '+
6446
+ 'http://datatables.net/tn/'+tn;
6447
+ }
6448
+
6449
+ if ( ! level ) {
6450
+ // Backwards compatibility pre 1.10
6451
+ var ext = DataTable.ext;
6452
+ var type = ext.sErrMode || ext.errMode;
6453
+
6454
+ if ( settings ) {
6455
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
6456
+ }
6457
+
6458
+ if ( type == 'alert' ) {
6459
+ alert( msg );
6460
+ }
6461
+ else if ( type == 'throw' ) {
6462
+ throw new Error(msg);
6463
+ }
6464
+ else if ( typeof type == 'function' ) {
6465
+ type( settings, tn, msg );
6466
+ }
6467
+ }
6468
+ else if ( window.console && console.log ) {
6469
+ console.log( msg );
6470
+ }
6471
+ }
6472
+
6473
+
6474
+ /**
6475
+ * See if a property is defined on one object, if so assign it to the other object
6476
+ * @param {object} ret target object
6477
+ * @param {object} src source object
6478
+ * @param {string} name property
6479
+ * @param {string} [mappedName] name to map too - optional, name used if not given
6480
+ * @memberof DataTable#oApi
6481
+ */
6482
+ function _fnMap( ret, src, name, mappedName )
6483
+ {
6484
+ if ( $.isArray( name ) ) {
6485
+ $.each( name, function (i, val) {
6486
+ if ( $.isArray( val ) ) {
6487
+ _fnMap( ret, src, val[0], val[1] );
6488
+ }
6489
+ else {
6490
+ _fnMap( ret, src, val );
6491
+ }
6492
+ } );
6493
+
6494
+ return;
6495
+ }
6496
+
6497
+ if ( mappedName === undefined ) {
6498
+ mappedName = name;
6499
+ }
6500
+
6501
+ if ( src[name] !== undefined ) {
6502
+ ret[mappedName] = src[name];
6503
+ }
6504
+ }
6505
+
6506
+
6507
+ /**
6508
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and
6509
+ * shallow copy arrays. The reason we need to do this, is that we don't want to
6510
+ * deep copy array init values (such as aaSorting) since the dev wouldn't be
6511
+ * able to override them, but we do want to deep copy arrays.
6512
+ * @param {object} out Object to extend
6513
+ * @param {object} extender Object from which the properties will be applied to
6514
+ * out
6515
+ * @param {boolean} breakRefs If true, then arrays will be sliced to take an
6516
+ * independent copy with the exception of the `data` or `aaData` parameters
6517
+ * if they are present. This is so you can pass in a collection to
6518
+ * DataTables and have that used as your data source without breaking the
6519
+ * references
6520
+ * @returns {object} out Reference, just for convenience - out === the return.
6521
+ * @memberof DataTable#oApi
6522
+ * @todo This doesn't take account of arrays inside the deep copied objects.
6523
+ */
6524
+ function _fnExtend( out, extender, breakRefs )
6525
+ {
6526
+ var val;
6527
+
6528
+ for ( var prop in extender ) {
6529
+ if ( extender.hasOwnProperty(prop) ) {
6530
+ val = extender[prop];
6531
+
6532
+ if ( $.isPlainObject( val ) ) {
6533
+ if ( ! $.isPlainObject( out[prop] ) ) {
6534
+ out[prop] = {};
6535
+ }
6536
+ $.extend( true, out[prop], val );
6537
+ }
6538
+ else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
6539
+ out[prop] = val.slice();
6540
+ }
6541
+ else {
6542
+ out[prop] = val;
6543
+ }
6544
+ }
6545
+ }
6546
+
6547
+ return out;
6548
+ }
6549
+
6550
+
6551
+ /**
6552
+ * Bind an event handers to allow a click or return key to activate the callback.
6553
+ * This is good for accessibility since a return on the keyboard will have the
6554
+ * same effect as a click, if the element has focus.
6555
+ * @param {element} n Element to bind the action to
6556
+ * @param {object} oData Data object to pass to the triggered function
6557
+ * @param {function} fn Callback function for when the event is triggered
6558
+ * @memberof DataTable#oApi
6559
+ */
6560
+ function _fnBindAction( n, oData, fn )
6561
+ {
6562
+ $(n)
6563
+ .on( 'click.DT', oData, function (e) {
6564
+ n.blur(); // Remove focus outline for mouse users
6565
+ fn(e);
6566
+ } )
6567
+ .on( 'keypress.DT', oData, function (e){
6568
+ if ( e.which === 13 ) {
6569
+ e.preventDefault();
6570
+ fn(e);
6571
+ }
6572
+ } )
6573
+ .on( 'selectstart.DT', function () {
6574
+ /* Take the brutal approach to cancelling text selection */
6575
+ return false;
6576
+ } );
6577
+ }
6578
+
6579
+
6580
+ /**
6581
+ * Register a callback function. Easily allows a callback function to be added to
6582
+ * an array store of callback functions that can then all be called together.
6583
+ * @param {object} oSettings dataTables settings object
6584
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
6585
+ * @param {function} fn Function to be called back
6586
+ * @param {string} sName Identifying name for the callback (i.e. a label)
6587
+ * @memberof DataTable#oApi
6588
+ */
6589
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
6590
+ {
6591
+ if ( fn )
6592
+ {
6593
+ oSettings[sStore].push( {
6594
+ "fn": fn,
6595
+ "sName": sName
6596
+ } );
6597
+ }
6598
+ }
6599
+
6600
+
6601
+ /**
6602
+ * Fire callback functions and trigger events. Note that the loop over the
6603
+ * callback array store is done backwards! Further note that you do not want to
6604
+ * fire off triggers in time sensitive applications (for example cell creation)
6605
+ * as its slow.
6606
+ * @param {object} settings dataTables settings object
6607
+ * @param {string} callbackArr Name of the array storage for the callbacks in
6608
+ * oSettings
6609
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
6610
+ * null no trigger is fired
6611
+ * @param {array} args Array of arguments to pass to the callback function /
6612
+ * trigger
6613
+ * @memberof DataTable#oApi
6614
+ */
6615
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
6616
+ {
6617
+ var ret = [];
6618
+
6619
+ if ( callbackArr ) {
6620
+ ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
6621
+ return val.fn.apply( settings.oInstance, args );
6622
+ } );
6623
+ }
6624
+
6625
+ if ( eventName !== null ) {
6626
+ var e = $.Event( eventName+'.dt' );
6627
+
6628
+ $(settings.nTable).trigger( e, args );
6629
+
6630
+ ret.push( e.result );
6631
+ }
6632
+
6633
+ return ret;
6634
+ }
6635
+
6636
+
6637
+ function _fnLengthOverflow ( settings )
6638
+ {
6639
+ var
6640
+ start = settings._iDisplayStart,
6641
+ end = settings.fnDisplayEnd(),
6642
+ len = settings._iDisplayLength;
6643
+
6644
+ /* If we have space to show extra rows (backing up from the end point - then do so */
6645
+ if ( start >= end )
6646
+ {
6647
+ start = end - len;
6648
+ }
6649
+
6650
+ // Keep the start record on the current page
6651
+ start -= (start % len);
6652
+
6653
+ if ( len === -1 || start < 0 )
6654
+ {
6655
+ start = 0;
6656
+ }
6657
+
6658
+ settings._iDisplayStart = start;
6659
+ }
6660
+
6661
+
6662
+ function _fnRenderer( settings, type )
6663
+ {
6664
+ var renderer = settings.renderer;
6665
+ var host = DataTable.ext.renderer[type];
6666
+
6667
+ if ( $.isPlainObject( renderer ) && renderer[type] ) {
6668
+ // Specific renderer for this type. If available use it, otherwise use
6669
+ // the default.
6670
+ return host[renderer[type]] || host._;
6671
+ }
6672
+ else if ( typeof renderer === 'string' ) {
6673
+ // Common renderer - if there is one available for this type use it,
6674
+ // otherwise use the default
6675
+ return host[renderer] || host._;
6676
+ }
6677
+
6678
+ // Use the default
6679
+ return host._;
6680
+ }
6681
+
6682
+
6683
+ /**
6684
+ * Detect the data source being used for the table. Used to simplify the code
6685
+ * a little (ajax) and to make it compress a little smaller.
6686
+ *
6687
+ * @param {object} settings dataTables settings object
6688
+ * @returns {string} Data source
6689
+ * @memberof DataTable#oApi
6690
+ */
6691
+ function _fnDataSource ( settings )
6692
+ {
6693
+ if ( settings.oFeatures.bServerSide ) {
6694
+ return 'ssp';
6695
+ }
6696
+ else if ( settings.ajax || settings.sAjaxSource ) {
6697
+ return 'ajax';
6698
+ }
6699
+ return 'dom';
6700
+ }
6701
+
6702
+
6703
+
6704
+
6705
+ /**
6706
+ * Computed structure of the DataTables API, defined by the options passed to
6707
+ * `DataTable.Api.register()` when building the API.
6708
+ *
6709
+ * The structure is built in order to speed creation and extension of the Api
6710
+ * objects since the extensions are effectively pre-parsed.
6711
+ *
6712
+ * The array is an array of objects with the following structure, where this
6713
+ * base array represents the Api prototype base:
6714
+ *
6715
+ * [
6716
+ * {
6717
+ * name: 'data' -- string - Property name
6718
+ * val: function () {}, -- function - Api method (or undefined if just an object
6719
+ * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6720
+ * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6721
+ * },
6722
+ * {
6723
+ * name: 'row'
6724
+ * val: {},
6725
+ * methodExt: [ ... ],
6726
+ * propExt: [
6727
+ * {
6728
+ * name: 'data'
6729
+ * val: function () {},
6730
+ * methodExt: [ ... ],
6731
+ * propExt: [ ... ]
6732
+ * },
6733
+ * ...
6734
+ * ]
6735
+ * }
6736
+ * ]
6737
+ *
6738
+ * @type {Array}
6739
+ * @ignore
6740
+ */
6741
+ var __apiStruct = [];
6742
+
6743
+
6744
+ /**
6745
+ * `Array.prototype` reference.
6746
+ *
6747
+ * @type object
6748
+ * @ignore
6749
+ */
6750
+ var __arrayProto = Array.prototype;
6751
+
6752
+
6753
+ /**
6754
+ * Abstraction for `context` parameter of the `Api` constructor to allow it to
6755
+ * take several different forms for ease of use.
6756
+ *
6757
+ * Each of the input parameter types will be converted to a DataTables settings
6758
+ * object where possible.
6759
+ *
6760
+ * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6761
+ * of:
6762
+ *
6763
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6764
+ * with be found and used.
6765
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6766
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6767
+ * * `object` - DataTables settings object
6768
+ * * `DataTables.Api` - API instance
6769
+ * @return {array|null} Matching DataTables settings objects. `null` or
6770
+ * `undefined` is returned if no matching DataTable is found.
6771
+ * @ignore
6772
+ */
6773
+ var _toSettings = function ( mixed )
6774
+ {
6775
+ var idx, jq;
6776
+ var settings = DataTable.settings;
6777
+ var tables = $.map( settings, function (el, i) {
6778
+ return el.nTable;
6779
+ } );
6780
+
6781
+ if ( ! mixed ) {
6782
+ return [];
6783
+ }
6784
+ else if ( mixed.nTable && mixed.oApi ) {
6785
+ // DataTables settings object
6786
+ return [ mixed ];
6787
+ }
6788
+ else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6789
+ // Table node
6790
+ idx = $.inArray( mixed, tables );
6791
+ return idx !== -1 ? [ settings[idx] ] : null;
6792
+ }
6793
+ else if ( mixed && typeof mixed.settings === 'function' ) {
6794
+ return mixed.settings().toArray();
6795
+ }
6796
+ else if ( typeof mixed === 'string' ) {
6797
+ // jQuery selector
6798
+ jq = $(mixed);
6799
+ }
6800
+ else if ( mixed instanceof $ ) {
6801
+ // jQuery object (also DataTables instance)
6802
+ jq = mixed;
6803
+ }
6804
+
6805
+ if ( jq ) {
6806
+ return jq.map( function(i) {
6807
+ idx = $.inArray( this, tables );
6808
+ return idx !== -1 ? settings[idx] : null;
6809
+ } ).toArray();
6810
+ }
6811
+ };
6812
+
6813
+
6814
+ /**
6815
+ * DataTables API class - used to control and interface with one or more
6816
+ * DataTables enhanced tables.
6817
+ *
6818
+ * The API class is heavily based on jQuery, presenting a chainable interface
6819
+ * that you can use to interact with tables. Each instance of the API class has
6820
+ * a "context" - i.e. the tables that it will operate on. This could be a single
6821
+ * table, all tables on a page or a sub-set thereof.
6822
+ *
6823
+ * Additionally the API is designed to allow you to easily work with the data in
6824
+ * the tables, retrieving and manipulating it as required. This is done by
6825
+ * presenting the API class as an array like interface. The contents of the
6826
+ * array depend upon the actions requested by each method (for example
6827
+ * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6828
+ * return an array of objects or arrays depending upon your table's
6829
+ * configuration). The API object has a number of array like methods (`push`,
6830
+ * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6831
+ * `unique` etc) to assist your working with the data held in a table.
6832
+ *
6833
+ * Most methods (those which return an Api instance) are chainable, which means
6834
+ * the return from a method call also has all of the methods available that the
6835
+ * top level object had. For example, these two calls are equivalent:
6836
+ *
6837
+ * // Not chained
6838
+ * api.row.add( {...} );
6839
+ * api.draw();
6840
+ *
6841
+ * // Chained
6842
+ * api.row.add( {...} ).draw();
6843
+ *
6844
+ * @class DataTable.Api
6845
+ * @param {array|object|string|jQuery} context DataTable identifier. This is
6846
+ * used to define which DataTables enhanced tables this API will operate on.
6847
+ * Can be one of:
6848
+ *
6849
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6850
+ * with be found and used.
6851
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6852
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6853
+ * * `object` - DataTables settings object
6854
+ * @param {array} [data] Data to initialise the Api instance with.
6855
+ *
6856
+ * @example
6857
+ * // Direct initialisation during DataTables construction
6858
+ * var api = $('#example').DataTable();
6859
+ *
6860
+ * @example
6861
+ * // Initialisation using a DataTables jQuery object
6862
+ * var api = $('#example').dataTable().api();
6863
+ *
6864
+ * @example
6865
+ * // Initialisation as a constructor
6866
+ * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6867
+ */
6868
+ _Api = function ( context, data )
6869
+ {
6870
+ if ( ! (this instanceof _Api) ) {
6871
+ return new _Api( context, data );
6872
+ }
6873
+
6874
+ var settings = [];
6875
+ var ctxSettings = function ( o ) {
6876
+ var a = _toSettings( o );
6877
+ if ( a ) {
6878
+ settings = settings.concat( a );
6879
+ }
6880
+ };
6881
+
6882
+ if ( $.isArray( context ) ) {
6883
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6884
+ ctxSettings( context[i] );
6885
+ }
6886
+ }
6887
+ else {
6888
+ ctxSettings( context );
6889
+ }
6890
+
6891
+ // Remove duplicates
6892
+ this.context = _unique( settings );
6893
+
6894
+ // Initial data
6895
+ if ( data ) {
6896
+ $.merge( this, data );
6897
+ }
6898
+
6899
+ // selector
6900
+ this.selector = {
6901
+ rows: null,
6902
+ cols: null,
6903
+ opts: null
6904
+ };
6905
+
6906
+ _Api.extend( this, this, __apiStruct );
6907
+ };
6908
+
6909
+ DataTable.Api = _Api;
6910
+
6911
+ // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
6912
+ // isPlainObject.
6913
+ $.extend( _Api.prototype, {
6914
+ any: function ()
6915
+ {
6916
+ return this.count() !== 0;
6917
+ },
6918
+
6919
+
6920
+ concat: __arrayProto.concat,
6921
+
6922
+
6923
+ context: [], // array of table settings objects
6924
+
6925
+
6926
+ count: function ()
6927
+ {
6928
+ return this.flatten().length;
6929
+ },
6930
+
6931
+
6932
+ each: function ( fn )
6933
+ {
6934
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
6935
+ fn.call( this, this[i], i, this );
6936
+ }
6937
+
6938
+ return this;
6939
+ },
6940
+
6941
+
6942
+ eq: function ( idx )
6943
+ {
6944
+ var ctx = this.context;
6945
+
6946
+ return ctx.length > idx ?
6947
+ new _Api( ctx[idx], this[idx] ) :
6948
+ null;
6949
+ },
6950
+
6951
+
6952
+ filter: function ( fn )
6953
+ {
6954
+ var a = [];
6955
+
6956
+ if ( __arrayProto.filter ) {
6957
+ a = __arrayProto.filter.call( this, fn, this );
6958
+ }
6959
+ else {
6960
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6961
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6962
+ if ( fn.call( this, this[i], i, this ) ) {
6963
+ a.push( this[i] );
6964
+ }
6965
+ }
6966
+ }
6967
+
6968
+ return new _Api( this.context, a );
6969
+ },
6970
+
6971
+
6972
+ flatten: function ()
6973
+ {
6974
+ var a = [];
6975
+ return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6976
+ },
6977
+
6978
+
6979
+ join: __arrayProto.join,
6980
+
6981
+
6982
+ indexOf: __arrayProto.indexOf || function (obj, start)
6983
+ {
6984
+ for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6985
+ if ( this[i] === obj ) {
6986
+ return i;
6987
+ }
6988
+ }
6989
+ return -1;
6990
+ },
6991
+
6992
+ iterator: function ( flatten, type, fn, alwaysNew ) {
6993
+ var
6994
+ a = [], ret,
6995
+ i, ien, j, jen,
6996
+ context = this.context,
6997
+ rows, items, item,
6998
+ selector = this.selector;
6999
+
7000
+ // Argument shifting
7001
+ if ( typeof flatten === 'string' ) {
7002
+ alwaysNew = fn;
7003
+ fn = type;
7004
+ type = flatten;
7005
+ flatten = false;
7006
+ }
7007
+
7008
+ for ( i=0, ien=context.length ; i<ien ; i++ ) {
7009
+ var apiInst = new _Api( context[i] );
7010
+
7011
+ if ( type === 'table' ) {
7012
+ ret = fn.call( apiInst, context[i], i );
7013
+
7014
+ if ( ret !== undefined ) {
7015
+ a.push( ret );
7016
+ }
7017
+ }
7018
+ else if ( type === 'columns' || type === 'rows' ) {
7019
+ // this has same length as context - one entry for each table
7020
+ ret = fn.call( apiInst, context[i], this[i], i );
7021
+
7022
+ if ( ret !== undefined ) {
7023
+ a.push( ret );
7024
+ }
7025
+ }
7026
+ else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
7027
+ // columns and rows share the same structure.
7028
+ // 'this' is an array of column indexes for each context
7029
+ items = this[i];
7030
+
7031
+ if ( type === 'column-rows' ) {
7032
+ rows = _selector_row_indexes( context[i], selector.opts );
7033
+ }
7034
+
7035
+ for ( j=0, jen=items.length ; j<jen ; j++ ) {
7036
+ item = items[j];
7037
+
7038
+ if ( type === 'cell' ) {
7039
+ ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
7040
+ }
7041
+ else {
7042
+ ret = fn.call( apiInst, context[i], item, i, j, rows );
7043
+ }
7044
+
7045
+ if ( ret !== undefined ) {
7046
+ a.push( ret );
7047
+ }
7048
+ }
7049
+ }
7050
+ }
7051
+
7052
+ if ( a.length || alwaysNew ) {
7053
+ var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
7054
+ var apiSelector = api.selector;
7055
+ apiSelector.rows = selector.rows;
7056
+ apiSelector.cols = selector.cols;
7057
+ apiSelector.opts = selector.opts;
7058
+ return api;
7059
+ }
7060
+ return this;
7061
+ },
7062
+
7063
+
7064
+ lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
7065
+ {
7066
+ // Bit cheeky...
7067
+ return this.indexOf.apply( this.toArray.reverse(), arguments );
7068
+ },
7069
+
7070
+
7071
+ length: 0,
7072
+
7073
+
7074
+ map: function ( fn )
7075
+ {
7076
+ var a = [];
7077
+
7078
+ if ( __arrayProto.map ) {
7079
+ a = __arrayProto.map.call( this, fn, this );
7080
+ }
7081
+ else {
7082
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
7083
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
7084
+ a.push( fn.call( this, this[i], i ) );
7085
+ }
7086
+ }
7087
+
7088
+ return new _Api( this.context, a );
7089
+ },
7090
+
7091
+
7092
+ pluck: function ( prop )
7093
+ {
7094
+ return this.map( function ( el ) {
7095
+ return el[ prop ];
7096
+ } );
7097
+ },
7098
+
7099
+ pop: __arrayProto.pop,
7100
+
7101
+
7102
+ push: __arrayProto.push,
7103
+
7104
+
7105
+ // Does not return an API instance
7106
+ reduce: __arrayProto.reduce || function ( fn, init )
7107
+ {
7108
+ return _fnReduce( this, fn, init, 0, this.length, 1 );
7109
+ },
7110
+
7111
+
7112
+ reduceRight: __arrayProto.reduceRight || function ( fn, init )
7113
+ {
7114
+ return _fnReduce( this, fn, init, this.length-1, -1, -1 );
7115
+ },
7116
+
7117
+
7118
+ reverse: __arrayProto.reverse,
7119
+
7120
+
7121
+ // Object with rows, columns and opts
7122
+ selector: null,
7123
+
7124
+
7125
+ shift: __arrayProto.shift,
7126
+
7127
+
7128
+ slice: function () {
7129
+ return new _Api( this.context, this );
7130
+ },
7131
+
7132
+
7133
+ sort: __arrayProto.sort, // ? name - order?
7134
+
7135
+
7136
+ splice: __arrayProto.splice,
7137
+
7138
+
7139
+ toArray: function ()
7140
+ {
7141
+ return __arrayProto.slice.call( this );
7142
+ },
7143
+
7144
+
7145
+ to$: function ()
7146
+ {
7147
+ return $( this );
7148
+ },
7149
+
7150
+
7151
+ toJQuery: function ()
7152
+ {
7153
+ return $( this );
7154
+ },
7155
+
7156
+
7157
+ unique: function ()
7158
+ {
7159
+ return new _Api( this.context, _unique(this) );
7160
+ },
7161
+
7162
+
7163
+ unshift: __arrayProto.unshift
7164
+ } );
7165
+
7166
+
7167
+ _Api.extend = function ( scope, obj, ext )
7168
+ {
7169
+ // Only extend API instances and static properties of the API
7170
+ if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
7171
+ return;
7172
+ }
7173
+
7174
+ var
7175
+ i, ien,
7176
+ j, jen,
7177
+ struct, inner,
7178
+ methodScoping = function ( scope, fn, struc ) {
7179
+ return function () {
7180
+ var ret = fn.apply( scope, arguments );
7181
+
7182
+ // Method extension
7183
+ _Api.extend( ret, ret, struc.methodExt );
7184
+ return ret;
7185
+ };
7186
+ };
7187
+
7188
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7189
+ struct = ext[i];
7190
+
7191
+ // Value
7192
+ obj[ struct.name ] = typeof struct.val === 'function' ?
7193
+ methodScoping( scope, struct.val, struct ) :
7194
+ $.isPlainObject( struct.val ) ?
7195
+ {} :
7196
+ struct.val;
7197
+
7198
+ obj[ struct.name ].__dt_wrapper = true;
7199
+
7200
+ // Property extension
7201
+ _Api.extend( scope, obj[ struct.name ], struct.propExt );
7202
+ }
7203
+ };
7204
+
7205
+
7206
+ // @todo - Is there need for an augment function?
7207
+ // _Api.augment = function ( inst, name )
7208
+ // {
7209
+ // // Find src object in the structure from the name
7210
+ // var parts = name.split('.');
7211
+
7212
+ // _Api.extend( inst, obj );
7213
+ // };
7214
+
7215
+
7216
+ // [
7217
+ // {
7218
+ // name: 'data' -- string - Property name
7219
+ // val: function () {}, -- function - Api method (or undefined if just an object
7220
+ // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7221
+ // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7222
+ // },
7223
+ // {
7224
+ // name: 'row'
7225
+ // val: {},
7226
+ // methodExt: [ ... ],
7227
+ // propExt: [
7228
+ // {
7229
+ // name: 'data'
7230
+ // val: function () {},
7231
+ // methodExt: [ ... ],
7232
+ // propExt: [ ... ]
7233
+ // },
7234
+ // ...
7235
+ // ]
7236
+ // }
7237
+ // ]
7238
+
7239
+ _Api.register = _api_register = function ( name, val )
7240
+ {
7241
+ if ( $.isArray( name ) ) {
7242
+ for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7243
+ _Api.register( name[j], val );
7244
+ }
7245
+ return;
7246
+ }
7247
+
7248
+ var
7249
+ i, ien,
7250
+ heir = name.split('.'),
7251
+ struct = __apiStruct,
7252
+ key, method;
7253
+
7254
+ var find = function ( src, name ) {
7255
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7256
+ if ( src[i].name === name ) {
7257
+ return src[i];
7258
+ }
7259
+ }
7260
+ return null;
7261
+ };
7262
+
7263
+ for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7264
+ method = heir[i].indexOf('()') !== -1;
7265
+ key = method ?
7266
+ heir[i].replace('()', '') :
7267
+ heir[i];
7268
+
7269
+ var src = find( struct, key );
7270
+ if ( ! src ) {
7271
+ src = {
7272
+ name: key,
7273
+ val: {},
7274
+ methodExt: [],
7275
+ propExt: []
7276
+ };
7277
+ struct.push( src );
7278
+ }
7279
+
7280
+ if ( i === ien-1 ) {
7281
+ src.val = val;
7282
+ }
7283
+ else {
7284
+ struct = method ?
7285
+ src.methodExt :
7286
+ src.propExt;
7287
+ }
7288
+ }
7289
+ };
7290
+
7291
+
7292
+ _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7293
+ _Api.register( pluralName, val );
7294
+
7295
+ _Api.register( singularName, function () {
7296
+ var ret = val.apply( this, arguments );
7297
+
7298
+ if ( ret === this ) {
7299
+ // Returned item is the API instance that was passed in, return it
7300
+ return this;
7301
+ }
7302
+ else if ( ret instanceof _Api ) {
7303
+ // New API instance returned, want the value from the first item
7304
+ // in the returned array for the singular result.
7305
+ return ret.length ?
7306
+ $.isArray( ret[0] ) ?
7307
+ new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7308
+ ret[0] :
7309
+ undefined;
7310
+ }
7311
+
7312
+ // Non-API return - just fire it back
7313
+ return ret;
7314
+ } );
7315
+ };
7316
+
7317
+
7318
+ /**
7319
+ * Selector for HTML tables. Apply the given selector to the give array of
7320
+ * DataTables settings objects.
7321
+ *
7322
+ * @param {string|integer} [selector] jQuery selector string or integer
7323
+ * @param {array} Array of DataTables settings objects to be filtered
7324
+ * @return {array}
7325
+ * @ignore
7326
+ */
7327
+ var __table_selector = function ( selector, a )
7328
+ {
7329
+ // Integer is used to pick out a table by index
7330
+ if ( typeof selector === 'number' ) {
7331
+ return [ a[ selector ] ];
7332
+ }
7333
+
7334
+ // Perform a jQuery selector on the table nodes
7335
+ var nodes = $.map( a, function (el, i) {
7336
+ return el.nTable;
7337
+ } );
7338
+
7339
+ return $(nodes)
7340
+ .filter( selector )
7341
+ .map( function (i) {
7342
+ // Need to translate back from the table node to the settings
7343
+ var idx = $.inArray( this, nodes );
7344
+ return a[ idx ];
7345
+ } )
7346
+ .toArray();
7347
+ };
7348
+
7349
+
7350
+
7351
+ /**
7352
+ * Context selector for the API's context (i.e. the tables the API instance
7353
+ * refers to.
7354
+ *
7355
+ * @name DataTable.Api#tables
7356
+ * @param {string|integer} [selector] Selector to pick which tables the iterator
7357
+ * should operate on. If not given, all tables in the current context are
7358
+ * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7359
+ * select multiple tables or as an integer to select a single table.
7360
+ * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7361
+ */
7362
+ _api_register( 'tables()', function ( selector ) {
7363
+ // A new instance is created if there was a selector specified
7364
+ return selector ?
7365
+ new _Api( __table_selector( selector, this.context ) ) :
7366
+ this;
7367
+ } );
7368
+
7369
+
7370
+ _api_register( 'table()', function ( selector ) {
7371
+ var tables = this.tables( selector );
7372
+ var ctx = tables.context;
7373
+
7374
+ // Truncate to the first matched table
7375
+ return ctx.length ?
7376
+ new _Api( ctx[0] ) :
7377
+ tables;
7378
+ } );
7379
+
7380
+
7381
+ _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7382
+ return this.iterator( 'table', function ( ctx ) {
7383
+ return ctx.nTable;
7384
+ }, 1 );
7385
+ } );
7386
+
7387
+
7388
+ _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7389
+ return this.iterator( 'table', function ( ctx ) {
7390
+ return ctx.nTBody;
7391
+ }, 1 );
7392
+ } );
7393
+
7394
+
7395
+ _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7396
+ return this.iterator( 'table', function ( ctx ) {
7397
+ return ctx.nTHead;
7398
+ }, 1 );
7399
+ } );
7400
+
7401
+
7402
+ _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7403
+ return this.iterator( 'table', function ( ctx ) {
7404
+ return ctx.nTFoot;
7405
+ }, 1 );
7406
+ } );
7407
+
7408
+
7409
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7410
+ return this.iterator( 'table', function ( ctx ) {
7411
+ return ctx.nTableWrapper;
7412
+ }, 1 );
7413
+ } );
7414
+
7415
+
7416
+
7417
+ /**
7418
+ * Redraw the tables in the current context.
7419
+ */
7420
+ _api_register( 'draw()', function ( paging ) {
7421
+ return this.iterator( 'table', function ( settings ) {
7422
+ if ( paging === 'page' ) {
7423
+ _fnDraw( settings );
7424
+ }
7425
+ else {
7426
+ if ( typeof paging === 'string' ) {
7427
+ paging = paging === 'full-hold' ?
7428
+ false :
7429
+ true;
7430
+ }
7431
+
7432
+ _fnReDraw( settings, paging===false );
7433
+ }
7434
+ } );
7435
+ } );
7436
+
7437
+
7438
+
7439
+ /**
7440
+ * Get the current page index.
7441
+ *
7442
+ * @return {integer} Current page index (zero based)
7443
+ *//**
7444
+ * Set the current page.
7445
+ *
7446
+ * Note that if you attempt to show a page which does not exist, DataTables will
7447
+ * not throw an error, but rather reset the paging.
7448
+ *
7449
+ * @param {integer|string} action The paging action to take. This can be one of:
7450
+ * * `integer` - The page index to jump to
7451
+ * * `string` - An action to take:
7452
+ * * `first` - Jump to first page.
7453
+ * * `next` - Jump to the next page
7454
+ * * `previous` - Jump to previous page
7455
+ * * `last` - Jump to the last page.
7456
+ * @returns {DataTables.Api} this
7457
+ */
7458
+ _api_register( 'page()', function ( action ) {
7459
+ if ( action === undefined ) {
7460
+ return this.page.info().page; // not an expensive call
7461
+ }
7462
+
7463
+ // else, have an action to take on all tables
7464
+ return this.iterator( 'table', function ( settings ) {
7465
+ _fnPageChange( settings, action );
7466
+ } );
7467
+ } );
7468
+
7469
+
7470
+ /**
7471
+ * Paging information for the first table in the current context.
7472
+ *
7473
+ * If you require paging information for another table, use the `table()` method
7474
+ * with a suitable selector.
7475
+ *
7476
+ * @return {object} Object with the following properties set:
7477
+ * * `page` - Current page index (zero based - i.e. the first page is `0`)
7478
+ * * `pages` - Total number of pages
7479
+ * * `start` - Display index for the first record shown on the current page
7480
+ * * `end` - Display index for the last record shown on the current page
7481
+ * * `length` - Display length (number of records). Note that generally `start
7482
+ * + length = end`, but this is not always true, for example if there are
7483
+ * only 2 records to show on the final page, with a length of 10.
7484
+ * * `recordsTotal` - Full data set length
7485
+ * * `recordsDisplay` - Data set length once the current filtering criterion
7486
+ * are applied.
7487
+ */
7488
+ _api_register( 'page.info()', function ( action ) {
7489
+ if ( this.context.length === 0 ) {
7490
+ return undefined;
7491
+ }
7492
+
7493
+ var
7494
+ settings = this.context[0],
7495
+ start = settings._iDisplayStart,
7496
+ len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
7497
+ visRecords = settings.fnRecordsDisplay(),
7498
+ all = len === -1;
7499
+
7500
+ return {
7501
+ "page": all ? 0 : Math.floor( start / len ),
7502
+ "pages": all ? 1 : Math.ceil( visRecords / len ),
7503
+ "start": start,
7504
+ "end": settings.fnDisplayEnd(),
7505
+ "length": len,
7506
+ "recordsTotal": settings.fnRecordsTotal(),
7507
+ "recordsDisplay": visRecords,
7508
+ "serverSide": _fnDataSource( settings ) === 'ssp'
7509
+ };
7510
+ } );
7511
+
7512
+
7513
+ /**
7514
+ * Get the current page length.
7515
+ *
7516
+ * @return {integer} Current page length. Note `-1` indicates that all records
7517
+ * are to be shown.
7518
+ *//**
7519
+ * Set the current page length.
7520
+ *
7521
+ * @param {integer} Page length to set. Use `-1` to show all records.
7522
+ * @returns {DataTables.Api} this
7523
+ */
7524
+ _api_register( 'page.len()', function ( len ) {
7525
+ // Note that we can't call this function 'length()' because `length`
7526
+ // is a Javascript property of functions which defines how many arguments
7527
+ // the function expects.
7528
+ if ( len === undefined ) {
7529
+ return this.context.length !== 0 ?
7530
+ this.context[0]._iDisplayLength :
7531
+ undefined;
7532
+ }
7533
+
7534
+ // else, set the page length
7535
+ return this.iterator( 'table', function ( settings ) {
7536
+ _fnLengthChange( settings, len );
7537
+ } );
7538
+ } );
7539
+
7540
+
7541
+
7542
+ var __reload = function ( settings, holdPosition, callback ) {
7543
+ // Use the draw event to trigger a callback
7544
+ if ( callback ) {
7545
+ var api = new _Api( settings );
7546
+
7547
+ api.one( 'draw', function () {
7548
+ callback( api.ajax.json() );
7549
+ } );
7550
+ }
7551
+
7552
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7553
+ _fnReDraw( settings, holdPosition );
7554
+ }
7555
+ else {
7556
+ _fnProcessingDisplay( settings, true );
7557
+
7558
+ // Cancel an existing request
7559
+ var xhr = settings.jqXHR;
7560
+ if ( xhr && xhr.readyState !== 4 ) {
7561
+ xhr.abort();
7562
+ }
7563
+
7564
+ // Trigger xhr
7565
+ _fnBuildAjax( settings, [], function( json ) {
7566
+ _fnClearTable( settings );
7567
+
7568
+ var data = _fnAjaxDataSrc( settings, json );
7569
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7570
+ _fnAddData( settings, data[i] );
7571
+ }
7572
+
7573
+ _fnReDraw( settings, holdPosition );
7574
+ _fnProcessingDisplay( settings, false );
7575
+ } );
7576
+ }
7577
+ };
7578
+
7579
+
7580
+ /**
7581
+ * Get the JSON response from the last Ajax request that DataTables made to the
7582
+ * server. Note that this returns the JSON from the first table in the current
7583
+ * context.
7584
+ *
7585
+ * @return {object} JSON received from the server.
7586
+ */
7587
+ _api_register( 'ajax.json()', function () {
7588
+ var ctx = this.context;
7589
+
7590
+ if ( ctx.length > 0 ) {
7591
+ return ctx[0].json;
7592
+ }
7593
+
7594
+ // else return undefined;
7595
+ } );
7596
+
7597
+
7598
+ /**
7599
+ * Get the data submitted in the last Ajax request
7600
+ */
7601
+ _api_register( 'ajax.params()', function () {
7602
+ var ctx = this.context;
7603
+
7604
+ if ( ctx.length > 0 ) {
7605
+ return ctx[0].oAjaxData;
7606
+ }
7607
+
7608
+ // else return undefined;
7609
+ } );
7610
+
7611
+
7612
+ /**
7613
+ * Reload tables from the Ajax data source. Note that this function will
7614
+ * automatically re-draw the table when the remote data has been loaded.
7615
+ *
7616
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7617
+ * position. A full re-sort and re-filter is performed when this method is
7618
+ * called, which is why the pagination reset is the default action.
7619
+ * @returns {DataTables.Api} this
7620
+ */
7621
+ _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7622
+ return this.iterator( 'table', function (settings) {
7623
+ __reload( settings, resetPaging===false, callback );
7624
+ } );
7625
+ } );
7626
+
7627
+
7628
+ /**
7629
+ * Get the current Ajax URL. Note that this returns the URL from the first
7630
+ * table in the current context.
7631
+ *
7632
+ * @return {string} Current Ajax source URL
7633
+ *//**
7634
+ * Set the Ajax URL. Note that this will set the URL for all tables in the
7635
+ * current context.
7636
+ *
7637
+ * @param {string} url URL to set.
7638
+ * @returns {DataTables.Api} this
7639
+ */
7640
+ _api_register( 'ajax.url()', function ( url ) {
7641
+ var ctx = this.context;
7642
+
7643
+ if ( url === undefined ) {
7644
+ // get
7645
+ if ( ctx.length === 0 ) {
7646
+ return undefined;
7647
+ }
7648
+ ctx = ctx[0];
7649
+
7650
+ return ctx.ajax ?
7651
+ $.isPlainObject( ctx.ajax ) ?
7652
+ ctx.ajax.url :
7653
+ ctx.ajax :
7654
+ ctx.sAjaxSource;
7655
+ }
7656
+
7657
+ // set
7658
+ return this.iterator( 'table', function ( settings ) {
7659
+ if ( $.isPlainObject( settings.ajax ) ) {
7660
+ settings.ajax.url = url;
7661
+ }
7662
+ else {
7663
+ settings.ajax = url;
7664
+ }
7665
+ // No need to consider sAjaxSource here since DataTables gives priority
7666
+ // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7667
+ // value of `sAjaxSource` redundant.
7668
+ } );
7669
+ } );
7670
+
7671
+
7672
+ /**
7673
+ * Load data from the newly set Ajax URL. Note that this method is only
7674
+ * available when `ajax.url()` is used to set a URL. Additionally, this method
7675
+ * has the same effect as calling `ajax.reload()` but is provided for
7676
+ * convenience when setting a new URL. Like `ajax.reload()` it will
7677
+ * automatically redraw the table once the remote data has been loaded.
7678
+ *
7679
+ * @returns {DataTables.Api} this
7680
+ */
7681
+ _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7682
+ // Same as a reload, but makes sense to present it for easy access after a
7683
+ // url change
7684
+ return this.iterator( 'table', function ( ctx ) {
7685
+ __reload( ctx, resetPaging===false, callback );
7686
+ } );
7687
+ } );
7688
+
7689
+
7690
+
7691
+
7692
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
7693
+ {
7694
+ var
7695
+ out = [], res,
7696
+ a, i, ien, j, jen,
7697
+ selectorType = typeof selector;
7698
+
7699
+ // Can't just check for isArray here, as an API or jQuery instance might be
7700
+ // given with their array like look
7701
+ if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7702
+ selector = [ selector ];
7703
+ }
7704
+
7705
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7706
+ // Only split on simple strings - complex expressions will be jQuery selectors
7707
+ a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
7708
+ selector[i].split(',') :
7709
+ [ selector[i] ];
7710
+
7711
+ for ( j=0, jen=a.length ; j<jen ; j++ ) {
7712
+ res = selectFn( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7713
+
7714
+ if ( res && res.length ) {
7715
+ out = out.concat( res );
7716
+ }
7717
+ }
7718
+ }
7719
+
7720
+ // selector extensions
7721
+ var ext = _ext.selector[ type ];
7722
+ if ( ext.length ) {
7723
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
7724
+ out = ext[i]( settings, opts, out );
7725
+ }
7726
+ }
7727
+
7728
+ return _unique( out );
7729
+ };
7730
+
7731
+
7732
+ var _selector_opts = function ( opts )
7733
+ {
7734
+ if ( ! opts ) {
7735
+ opts = {};
7736
+ }
7737
+
7738
+ // Backwards compatibility for 1.9- which used the terminology filter rather
7739
+ // than search
7740
+ if ( opts.filter && opts.search === undefined ) {
7741
+ opts.search = opts.filter;
7742
+ }
7743
+
7744
+ return $.extend( {
7745
+ search: 'none',
7746
+ order: 'current',
7747
+ page: 'all'
7748
+ }, opts );
7749
+ };
7750
+
7751
+
7752
+ var _selector_first = function ( inst )
7753
+ {
7754
+ // Reduce the API instance to the first item found
7755
+ for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7756
+ if ( inst[i].length > 0 ) {
7757
+ // Assign the first element to the first item in the instance
7758
+ // and truncate the instance and context
7759
+ inst[0] = inst[i];
7760
+ inst[0].length = 1;
7761
+ inst.length = 1;
7762
+ inst.context = [ inst.context[i] ];
7763
+
7764
+ return inst;
7765
+ }
7766
+ }
7767
+
7768
+ // Not found - return an empty instance
7769
+ inst.length = 0;
7770
+ return inst;
7771
+ };
7772
+
7773
+
7774
+ var _selector_row_indexes = function ( settings, opts )
7775
+ {
7776
+ var
7777
+ i, ien, tmp, a=[],
7778
+ displayFiltered = settings.aiDisplay,
7779
+ displayMaster = settings.aiDisplayMaster;
7780
+
7781
+ var
7782
+ search = opts.search, // none, applied, removed
7783
+ order = opts.order, // applied, current, index (original - compatibility with 1.9)
7784
+ page = opts.page; // all, current
7785
+
7786
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7787
+ // In server-side processing mode, most options are irrelevant since
7788
+ // rows not shown don't exist and the index order is the applied order
7789
+ // Removed is a special case - for consistency just return an empty
7790
+ // array
7791
+ return search === 'removed' ?
7792
+ [] :
7793
+ _range( 0, displayMaster.length );
7794
+ }
7795
+ else if ( page == 'current' ) {
7796
+ // Current page implies that order=current and fitler=applied, since it is
7797
+ // fairly senseless otherwise, regardless of what order and search actually
7798
+ // are
7799
+ for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7800
+ a.push( displayFiltered[i] );
7801
+ }
7802
+ }
7803
+ else if ( order == 'current' || order == 'applied' ) {
7804
+ a = search == 'none' ?
7805
+ displayMaster.slice() : // no search
7806
+ search == 'applied' ?
7807
+ displayFiltered.slice() : // applied search
7808
+ $.map( displayMaster, function (el, i) { // removed search
7809
+ return $.inArray( el, displayFiltered ) === -1 ? el : null;
7810
+ } );
7811
+ }
7812
+ else if ( order == 'index' || order == 'original' ) {
7813
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7814
+ if ( search == 'none' ) {
7815
+ a.push( i );
7816
+ }
7817
+ else { // applied | removed
7818
+ tmp = $.inArray( i, displayFiltered );
7819
+
7820
+ if ((tmp === -1 && search == 'removed') ||
7821
+ (tmp >= 0 && search == 'applied') )
7822
+ {
7823
+ a.push( i );
7824
+ }
7825
+ }
7826
+ }
7827
+ }
7828
+
7829
+ return a;
7830
+ };
7831
+
7832
+
7833
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7834
+ * Rows
7835
+ *
7836
+ * {} - no selector - use all available rows
7837
+ * {integer} - row aoData index
7838
+ * {node} - TR node
7839
+ * {string} - jQuery selector to apply to the TR elements
7840
+ * {array} - jQuery array of nodes, or simply an array of TR nodes
7841
+ *
7842
+ */
7843
+
7844
+
7845
+ var __row_selector = function ( settings, selector, opts )
7846
+ {
7847
+ var rows;
7848
+ var run = function ( sel ) {
7849
+ var selInt = _intVal( sel );
7850
+ var i, ien;
7851
+
7852
+ // Short cut - selector is a number and no options provided (default is
7853
+ // all records, so no need to check if the index is in there, since it
7854
+ // must be - dev error if the index doesn't exist).
7855
+ if ( selInt !== null && ! opts ) {
7856
+ return [ selInt ];
7857
+ }
7858
+
7859
+ if ( ! rows ) {
7860
+ rows = _selector_row_indexes( settings, opts );
7861
+ }
7862
+
7863
+ if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7864
+ // Selector - integer
7865
+ return [ selInt ];
7866
+ }
7867
+ else if ( sel === null || sel === undefined || sel === '' ) {
7868
+ // Selector - none
7869
+ return rows;
7870
+ }
7871
+
7872
+ // Selector - function
7873
+ if ( typeof sel === 'function' ) {
7874
+ return $.map( rows, function (idx) {
7875
+ var row = settings.aoData[ idx ];
7876
+ return sel( idx, row._aData, row.nTr ) ? idx : null;
7877
+ } );
7878
+ }
7879
+
7880
+ // Get nodes in the order from the `rows` array with null values removed
7881
+ var nodes = _removeEmpty(
7882
+ _pluck_order( settings.aoData, rows, 'nTr' )
7883
+ );
7884
+
7885
+ // Selector - node
7886
+ if ( sel.nodeName ) {
7887
+ if ( sel._DT_RowIndex !== undefined ) {
7888
+ return [ sel._DT_RowIndex ]; // Property added by DT for fast lookup
7889
+ }
7890
+ else if ( sel._DT_CellIndex ) {
7891
+ return [ sel._DT_CellIndex.row ];
7892
+ }
7893
+ else {
7894
+ var host = $(sel).closest('*[data-dt-row]');
7895
+ return host.length ?
7896
+ [ host.data('dt-row') ] :
7897
+ [];
7898
+ }
7899
+ }
7900
+
7901
+ // ID selector. Want to always be able to select rows by id, regardless
7902
+ // of if the tr element has been created or not, so can't rely upon
7903
+ // jQuery here - hence a custom implementation. This does not match
7904
+ // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
7905
+ // but to select it using a CSS selector engine (like Sizzle or
7906
+ // querySelect) it would need to need to be escaped for some characters.
7907
+ // DataTables simplifies this for row selectors since you can select
7908
+ // only a row. A # indicates an id any anything that follows is the id -
7909
+ // unescaped.
7910
+ if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
7911
+ // get row index from id
7912
+ var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
7913
+ if ( rowObj !== undefined ) {
7914
+ return [ rowObj.idx ];
7915
+ }
7916
+
7917
+ // need to fall through to jQuery in case there is DOM id that
7918
+ // matches
7919
+ }
7920
+
7921
+ // Selector - jQuery selector string, array of nodes or jQuery object/
7922
+ // As jQuery's .filter() allows jQuery objects to be passed in filter,
7923
+ // it also allows arrays, so this will cope with all three options
7924
+ return $(nodes)
7925
+ .filter( sel )
7926
+ .map( function () {
7927
+ return this._DT_RowIndex;
7928
+ } )
7929
+ .toArray();
7930
+ };
7931
+
7932
+ return _selector_run( 'row', selector, run, settings, opts );
7933
+ };
7934
+
7935
+
7936
+ _api_register( 'rows()', function ( selector, opts ) {
7937
+ // argument shifting
7938
+ if ( selector === undefined ) {
7939
+ selector = '';
7940
+ }
7941
+ else if ( $.isPlainObject( selector ) ) {
7942
+ opts = selector;
7943
+ selector = '';
7944
+ }
7945
+
7946
+ opts = _selector_opts( opts );
7947
+
7948
+ var inst = this.iterator( 'table', function ( settings ) {
7949
+ return __row_selector( settings, selector, opts );
7950
+ }, 1 );
7951
+
7952
+ // Want argument shifting here and in __row_selector?
7953
+ inst.selector.rows = selector;
7954
+ inst.selector.opts = opts;
7955
+
7956
+ return inst;
7957
+ } );
7958
+
7959
+ _api_register( 'rows().nodes()', function () {
7960
+ return this.iterator( 'row', function ( settings, row ) {
7961
+ return settings.aoData[ row ].nTr || undefined;
7962
+ }, 1 );
7963
+ } );
7964
+
7965
+ _api_register( 'rows().data()', function () {
7966
+ return this.iterator( true, 'rows', function ( settings, rows ) {
7967
+ return _pluck_order( settings.aoData, rows, '_aData' );
7968
+ }, 1 );
7969
+ } );
7970
+
7971
+ _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7972
+ return this.iterator( 'row', function ( settings, row ) {
7973
+ var r = settings.aoData[ row ];
7974
+ return type === 'search' ? r._aFilterData : r._aSortData;
7975
+ }, 1 );
7976
+ } );
7977
+
7978
+ _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7979
+ return this.iterator( 'row', function ( settings, row ) {
7980
+ _fnInvalidate( settings, row, src );
7981
+ } );
7982
+ } );
7983
+
7984
+ _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7985
+ return this.iterator( 'row', function ( settings, row ) {
7986
+ return row;
7987
+ }, 1 );
7988
+ } );
7989
+
7990
+ _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
7991
+ var a = [];
7992
+ var context = this.context;
7993
+
7994
+ // `iterator` will drop undefined values, but in this case we want them
7995
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
7996
+ for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
7997
+ var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
7998
+ a.push( (hash === true ? '#' : '' )+ id );
7999
+ }
8000
+ }
8001
+
8002
+ return new _Api( context, a );
8003
+ } );
8004
+
8005
+ _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
8006
+ var that = this;
8007
+
8008
+ this.iterator( 'row', function ( settings, row, thatIdx ) {
8009
+ var data = settings.aoData;
8010
+ var rowData = data[ row ];
8011
+ var i, ien, j, jen;
8012
+ var loopRow, loopCells;
8013
+
8014
+ data.splice( row, 1 );
8015
+
8016
+ // Update the cached indexes
8017
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8018
+ loopRow = data[i];
8019
+ loopCells = loopRow.anCells;
8020
+
8021
+ // Rows
8022
+ if ( loopRow.nTr !== null ) {
8023
+ loopRow.nTr._DT_RowIndex = i;
8024
+ }
8025
+
8026
+ // Cells
8027
+ if ( loopCells !== null ) {
8028
+ for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
8029
+ loopCells[j]._DT_CellIndex.row = i;
8030
+ }
8031
+ }
8032
+ }
8033
+
8034
+ // Delete from the display arrays
8035
+ _fnDeleteIndex( settings.aiDisplayMaster, row );
8036
+ _fnDeleteIndex( settings.aiDisplay, row );
8037
+ _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
8038
+
8039
+ // For server-side processing tables - subtract the deleted row from the count
8040
+ if ( settings._iRecordsDisplay > 0 ) {
8041
+ settings._iRecordsDisplay--;
8042
+ }
8043
+
8044
+ // Check for an 'overflow' they case for displaying the table
8045
+ _fnLengthOverflow( settings );
8046
+
8047
+ // Remove the row's ID reference if there is one
8048
+ var id = settings.rowIdFn( rowData._aData );
8049
+ if ( id !== undefined ) {
8050
+ delete settings.aIds[ id ];
8051
+ }
8052
+ } );
8053
+
8054
+ this.iterator( 'table', function ( settings ) {
8055
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
8056
+ settings.aoData[i].idx = i;
8057
+ }
8058
+ } );
8059
+
8060
+ return this;
8061
+ } );
8062
+
8063
+
8064
+ _api_register( 'rows.add()', function ( rows ) {
8065
+ var newRows = this.iterator( 'table', function ( settings ) {
8066
+ var row, i, ien;
8067
+ var out = [];
8068
+
8069
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8070
+ row = rows[i];
8071
+
8072
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8073
+ out.push( _fnAddTr( settings, row )[0] );
8074
+ }
8075
+ else {
8076
+ out.push( _fnAddData( settings, row ) );
8077
+ }
8078
+ }
8079
+
8080
+ return out;
8081
+ }, 1 );
8082
+
8083
+ // Return an Api.rows() extended instance, so rows().nodes() etc can be used
8084
+ var modRows = this.rows( -1 );
8085
+ modRows.pop();
8086
+ $.merge( modRows, newRows );
8087
+
8088
+ return modRows;
8089
+ } );
8090
+
8091
+
8092
+
8093
+
8094
+
8095
+ /**
8096
+ *
8097
+ */
8098
+ _api_register( 'row()', function ( selector, opts ) {
8099
+ return _selector_first( this.rows( selector, opts ) );
8100
+ } );
8101
+
8102
+
8103
+ _api_register( 'row().data()', function ( data ) {
8104
+ var ctx = this.context;
8105
+
8106
+ if ( data === undefined ) {
8107
+ // Get
8108
+ return ctx.length && this.length ?
8109
+ ctx[0].aoData[ this[0] ]._aData :
8110
+ undefined;
8111
+ }
8112
+
8113
+ // Set
8114
+ ctx[0].aoData[ this[0] ]._aData = data;
8115
+
8116
+ // Automatically invalidate
8117
+ _fnInvalidate( ctx[0], this[0], 'data' );
8118
+
8119
+ return this;
8120
+ } );
8121
+
8122
+
8123
+ _api_register( 'row().node()', function () {
8124
+ var ctx = this.context;
8125
+
8126
+ return ctx.length && this.length ?
8127
+ ctx[0].aoData[ this[0] ].nTr || null :
8128
+ null;
8129
+ } );
8130
+
8131
+
8132
+ _api_register( 'row.add()', function ( row ) {
8133
+ // Allow a jQuery object to be passed in - only a single row is added from
8134
+ // it though - the first element in the set
8135
+ if ( row instanceof $ && row.length ) {
8136
+ row = row[0];
8137
+ }
8138
+
8139
+ var rows = this.iterator( 'table', function ( settings ) {
8140
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
8141
+ return _fnAddTr( settings, row )[0];
8142
+ }
8143
+ return _fnAddData( settings, row );
8144
+ } );
8145
+
8146
+ // Return an Api.rows() extended instance, with the newly added row selected
8147
+ return this.row( rows[0] );
8148
+ } );
8149
+
8150
+
8151
+
8152
+ var __details_add = function ( ctx, row, data, klass )
8153
+ {
8154
+ // Convert to array of TR elements
8155
+ var rows = [];
8156
+ var addRow = function ( r, k ) {
8157
+ // Recursion to allow for arrays of jQuery objects
8158
+ if ( $.isArray( r ) || r instanceof $ ) {
8159
+ for ( var i=0, ien=r.length ; i<ien ; i++ ) {
8160
+ addRow( r[i], k );
8161
+ }
8162
+ return;
8163
+ }
8164
+
8165
+ // If we get a TR element, then just add it directly - up to the dev
8166
+ // to add the correct number of columns etc
8167
+ if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
8168
+ rows.push( r );
8169
+ }
8170
+ else {
8171
+ // Otherwise create a row with a wrapper
8172
+ var created = $('<tr><td/></tr>').addClass( k );
8173
+ $('td', created)
8174
+ .addClass( k )
8175
+ .html( r )
8176
+ [0].colSpan = _fnVisbleColumns( ctx );
8177
+
8178
+ rows.push( created[0] );
8179
+ }
8180
+ };
8181
+
8182
+ addRow( data, klass );
8183
+
8184
+ if ( row._details ) {
8185
+ row._details.detach();
8186
+ }
8187
+
8188
+ row._details = $(rows);
8189
+
8190
+ // If the children were already shown, that state should be retained
8191
+ if ( row._detailsShow ) {
8192
+ row._details.insertAfter( row.nTr );
8193
+ }
8194
+ };
8195
+
8196
+
8197
+ var __details_remove = function ( api, idx )
8198
+ {
8199
+ var ctx = api.context;
8200
+
8201
+ if ( ctx.length ) {
8202
+ var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
8203
+
8204
+ if ( row && row._details ) {
8205
+ row._details.remove();
8206
+
8207
+ row._detailsShow = undefined;
8208
+ row._details = undefined;
8209
+ }
8210
+ }
8211
+ };
8212
+
8213
+
8214
+ var __details_display = function ( api, show ) {
8215
+ var ctx = api.context;
8216
+
8217
+ if ( ctx.length && api.length ) {
8218
+ var row = ctx[0].aoData[ api[0] ];
8219
+
8220
+ if ( row._details ) {
8221
+ row._detailsShow = show;
8222
+
8223
+ if ( show ) {
8224
+ row._details.insertAfter( row.nTr );
8225
+ }
8226
+ else {
8227
+ row._details.detach();
8228
+ }
8229
+
8230
+ __details_events( ctx[0] );
8231
+ }
8232
+ }
8233
+ };
8234
+
8235
+
8236
+ var __details_events = function ( settings )
8237
+ {
8238
+ var api = new _Api( settings );
8239
+ var namespace = '.dt.DT_details';
8240
+ var drawEvent = 'draw'+namespace;
8241
+ var colvisEvent = 'column-visibility'+namespace;
8242
+ var destroyEvent = 'destroy'+namespace;
8243
+ var data = settings.aoData;
8244
+
8245
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
8246
+
8247
+ if ( _pluck( data, '_details' ).length > 0 ) {
8248
+ // On each draw, insert the required elements into the document
8249
+ api.on( drawEvent, function ( e, ctx ) {
8250
+ if ( settings !== ctx ) {
8251
+ return;
8252
+ }
8253
+
8254
+ api.rows( {page:'current'} ).eq(0).each( function (idx) {
8255
+ // Internal data grab
8256
+ var row = data[ idx ];
8257
+
8258
+ if ( row._detailsShow ) {
8259
+ row._details.insertAfter( row.nTr );
8260
+ }
8261
+ } );
8262
+ } );
8263
+
8264
+ // Column visibility change - update the colspan
8265
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
8266
+ if ( settings !== ctx ) {
8267
+ return;
8268
+ }
8269
+
8270
+ // Update the colspan for the details rows (note, only if it already has
8271
+ // a colspan)
8272
+ var row, visible = _fnVisbleColumns( ctx );
8273
+
8274
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8275
+ row = data[i];
8276
+
8277
+ if ( row._details ) {
8278
+ row._details.children('td[colspan]').attr('colspan', visible );
8279
+ }
8280
+ }
8281
+ } );
8282
+
8283
+ // Table destroyed - nuke any child rows
8284
+ api.on( destroyEvent, function ( e, ctx ) {
8285
+ if ( settings !== ctx ) {
8286
+ return;
8287
+ }
8288
+
8289
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8290
+ if ( data[i]._details ) {
8291
+ __details_remove( api, i );
8292
+ }
8293
+ }
8294
+ } );
8295
+ }
8296
+ };
8297
+
8298
+ // Strings for the method names to help minification
8299
+ var _emp = '';
8300
+ var _child_obj = _emp+'row().child';
8301
+ var _child_mth = _child_obj+'()';
8302
+
8303
+ // data can be:
8304
+ // tr
8305
+ // string
8306
+ // jQuery or array of any of the above
8307
+ _api_register( _child_mth, function ( data, klass ) {
8308
+ var ctx = this.context;
8309
+
8310
+ if ( data === undefined ) {
8311
+ // get
8312
+ return ctx.length && this.length ?
8313
+ ctx[0].aoData[ this[0] ]._details :
8314
+ undefined;
8315
+ }
8316
+ else if ( data === true ) {
8317
+ // show
8318
+ this.child.show();
8319
+ }
8320
+ else if ( data === false ) {
8321
+ // remove
8322
+ __details_remove( this );
8323
+ }
8324
+ else if ( ctx.length && this.length ) {
8325
+ // set
8326
+ __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8327
+ }
8328
+
8329
+ return this;
8330
+ } );
8331
+
8332
+
8333
+ _api_register( [
8334
+ _child_obj+'.show()',
8335
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
8336
+ ], function ( show ) { // it returns an object and this method is not executed)
8337
+ __details_display( this, true );
8338
+ return this;
8339
+ } );
8340
+
8341
+
8342
+ _api_register( [
8343
+ _child_obj+'.hide()',
8344
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
8345
+ ], function () { // it returns an object and this method is not executed)
8346
+ __details_display( this, false );
8347
+ return this;
8348
+ } );
8349
+
8350
+
8351
+ _api_register( [
8352
+ _child_obj+'.remove()',
8353
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
8354
+ ], function () { // it returns an object and this method is not executed)
8355
+ __details_remove( this );
8356
+ return this;
8357
+ } );
8358
+
8359
+
8360
+ _api_register( _child_obj+'.isShown()', function () {
8361
+ var ctx = this.context;
8362
+
8363
+ if ( ctx.length && this.length ) {
8364
+ // _detailsShown as false or undefined will fall through to return false
8365
+ return ctx[0].aoData[ this[0] ]._detailsShow || false;
8366
+ }
8367
+ return false;
8368
+ } );
8369
+
8370
+
8371
+
8372
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8373
+ * Columns
8374
+ *
8375
+ * {integer} - column index (>=0 count from left, <0 count from right)
8376
+ * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8377
+ * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8378
+ * "{string}:name" - column name
8379
+ * "{string}" - jQuery selector on column header nodes
8380
+ *
8381
+ */
8382
+
8383
+ // can be an array of these items, comma separated list, or an array of comma
8384
+ // separated lists
8385
+
8386
+ var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
8387
+
8388
+
8389
+ // r1 and r2 are redundant - but it means that the parameters match for the
8390
+ // iterator callback in columns().data()
8391
+ var __columnData = function ( settings, column, r1, r2, rows ) {
8392
+ var a = [];
8393
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8394
+ a.push( _fnGetCellData( settings, rows[row], column ) );
8395
+ }
8396
+ return a;
8397
+ };
8398
+
8399
+
8400
+ var __column_selector = function ( settings, selector, opts )
8401
+ {
8402
+ var
8403
+ columns = settings.aoColumns,
8404
+ names = _pluck( columns, 'sName' ),
8405
+ nodes = _pluck( columns, 'nTh' );
8406
+
8407
+ var run = function ( s ) {
8408
+ var selInt = _intVal( s );
8409
+
8410
+ // Selector - all
8411
+ if ( s === '' ) {
8412
+ return _range( columns.length );
8413
+ }
8414
+
8415
+ // Selector - index
8416
+ if ( selInt !== null ) {
8417
+ return [ selInt >= 0 ?
8418
+ selInt : // Count from left
8419
+ columns.length + selInt // Count from right (+ because its a negative value)
8420
+ ];
8421
+ }
8422
+
8423
+ // Selector = function
8424
+ if ( typeof s === 'function' ) {
8425
+ var rows = _selector_row_indexes( settings, opts );
8426
+
8427
+ return $.map( columns, function (col, idx) {
8428
+ return s(
8429
+ idx,
8430
+ __columnData( settings, idx, 0, 0, rows ),
8431
+ nodes[ idx ]
8432
+ ) ? idx : null;
8433
+ } );
8434
+ }
8435
+
8436
+ // jQuery or string selector
8437
+ var match = typeof s === 'string' ?
8438
+ s.match( __re_column_selector ) :
8439
+ '';
8440
+
8441
+ if ( match ) {
8442
+ switch( match[2] ) {
8443
+ case 'visIdx':
8444
+ case 'visible':
8445
+ var idx = parseInt( match[1], 10 );
8446
+ // Visible index given, convert to column index
8447
+ if ( idx < 0 ) {
8448
+ // Counting from the right
8449
+ var visColumns = $.map( columns, function (col,i) {
8450
+ return col.bVisible ? i : null;
8451
+ } );
8452
+ return [ visColumns[ visColumns.length + idx ] ];
8453
+ }
8454
+ // Counting from the left
8455
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
8456
+
8457
+ case 'name':
8458
+ // match by name. `names` is column index complete and in order
8459
+ return $.map( names, function (name, i) {
8460
+ return name === match[1] ? i : null;
8461
+ } );
8462
+
8463
+ default:
8464
+ return [];
8465
+ }
8466
+ }
8467
+
8468
+ // Cell in the table body
8469
+ if ( s.nodeName && s._DT_CellIndex ) {
8470
+ return [ s._DT_CellIndex.column ];
8471
+ }
8472
+
8473
+ // jQuery selector on the TH elements for the columns
8474
+ var jqResult = $( nodes )
8475
+ .filter( s )
8476
+ .map( function () {
8477
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8478
+ } )
8479
+ .toArray();
8480
+
8481
+ if ( jqResult.length || ! s.nodeName ) {
8482
+ return jqResult;
8483
+ }
8484
+
8485
+ // Otherwise a node which might have a `dt-column` data attribute, or be
8486
+ // a child or such an element
8487
+ var host = $(s).closest('*[data-dt-column]');
8488
+ return host.length ?
8489
+ [ host.data('dt-column') ] :
8490
+ [];
8491
+ };
8492
+
8493
+ return _selector_run( 'column', selector, run, settings, opts );
8494
+ };
8495
+
8496
+
8497
+ var __setColumnVis = function ( settings, column, vis ) {
8498
+ var
8499
+ cols = settings.aoColumns,
8500
+ col = cols[ column ],
8501
+ data = settings.aoData,
8502
+ row, cells, i, ien, tr;
8503
+
8504
+ // Get
8505
+ if ( vis === undefined ) {
8506
+ return col.bVisible;
8507
+ }
8508
+
8509
+ // Set
8510
+ // No change
8511
+ if ( col.bVisible === vis ) {
8512
+ return;
8513
+ }
8514
+
8515
+ if ( vis ) {
8516
+ // Insert column
8517
+ // Need to decide if we should use appendChild or insertBefore
8518
+ var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8519
+
8520
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8521
+ tr = data[i].nTr;
8522
+ cells = data[i].anCells;
8523
+
8524
+ if ( tr ) {
8525
+ // insertBefore can act like appendChild if 2nd arg is null
8526
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8527
+ }
8528
+ }
8529
+ }
8530
+ else {
8531
+ // Remove column
8532
+ $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8533
+ }
8534
+
8535
+ // Common actions
8536
+ col.bVisible = vis;
8537
+ _fnDrawHead( settings, settings.aoHeader );
8538
+ _fnDrawHead( settings, settings.aoFooter );
8539
+
8540
+ _fnSaveState( settings );
8541
+ };
8542
+
8543
+
8544
+ _api_register( 'columns()', function ( selector, opts ) {
8545
+ // argument shifting
8546
+ if ( selector === undefined ) {
8547
+ selector = '';
8548
+ }
8549
+ else if ( $.isPlainObject( selector ) ) {
8550
+ opts = selector;
8551
+ selector = '';
8552
+ }
8553
+
8554
+ opts = _selector_opts( opts );
8555
+
8556
+ var inst = this.iterator( 'table', function ( settings ) {
8557
+ return __column_selector( settings, selector, opts );
8558
+ }, 1 );
8559
+
8560
+ // Want argument shifting here and in _row_selector?
8561
+ inst.selector.cols = selector;
8562
+ inst.selector.opts = opts;
8563
+
8564
+ return inst;
8565
+ } );
8566
+
8567
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8568
+ return this.iterator( 'column', function ( settings, column ) {
8569
+ return settings.aoColumns[column].nTh;
8570
+ }, 1 );
8571
+ } );
8572
+
8573
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8574
+ return this.iterator( 'column', function ( settings, column ) {
8575
+ return settings.aoColumns[column].nTf;
8576
+ }, 1 );
8577
+ } );
8578
+
8579
+ _api_registerPlural( 'columns().data()', 'column().data()', function () {
8580
+ return this.iterator( 'column-rows', __columnData, 1 );
8581
+ } );
8582
+
8583
+ _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8584
+ return this.iterator( 'column', function ( settings, column ) {
8585
+ return settings.aoColumns[column].mData;
8586
+ }, 1 );
8587
+ } );
8588
+
8589
+ _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8590
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8591
+ return _pluck_order( settings.aoData, rows,
8592
+ type === 'search' ? '_aFilterData' : '_aSortData', column
8593
+ );
8594
+ }, 1 );
8595
+ } );
8596
+
8597
+ _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8598
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8599
+ return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8600
+ }, 1 );
8601
+ } );
8602
+
8603
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8604
+ var ret = this.iterator( 'column', function ( settings, column ) {
8605
+ if ( vis === undefined ) {
8606
+ return settings.aoColumns[ column ].bVisible;
8607
+ } // else
8608
+ __setColumnVis( settings, column, vis );
8609
+ } );
8610
+
8611
+ // Group the column visibility changes
8612
+ if ( vis !== undefined ) {
8613
+ // Second loop once the first is done for events
8614
+ this.iterator( 'column', function ( settings, column ) {
8615
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
8616
+ } );
8617
+
8618
+ if ( calc === undefined || calc ) {
8619
+ this.columns.adjust();
8620
+ }
8621
+ }
8622
+
8623
+ return ret;
8624
+ } );
8625
+
8626
+ _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8627
+ return this.iterator( 'column', function ( settings, column ) {
8628
+ return type === 'visible' ?
8629
+ _fnColumnIndexToVisible( settings, column ) :
8630
+ column;
8631
+ }, 1 );
8632
+ } );
8633
+
8634
+ _api_register( 'columns.adjust()', function () {
8635
+ return this.iterator( 'table', function ( settings ) {
8636
+ _fnAdjustColumnSizing( settings );
8637
+ }, 1 );
8638
+ } );
8639
+
8640
+ _api_register( 'column.index()', function ( type, idx ) {
8641
+ if ( this.context.length !== 0 ) {
8642
+ var ctx = this.context[0];
8643
+
8644
+ if ( type === 'fromVisible' || type === 'toData' ) {
8645
+ return _fnVisibleToColumnIndex( ctx, idx );
8646
+ }
8647
+ else if ( type === 'fromData' || type === 'toVisible' ) {
8648
+ return _fnColumnIndexToVisible( ctx, idx );
8649
+ }
8650
+ }
8651
+ } );
8652
+
8653
+ _api_register( 'column()', function ( selector, opts ) {
8654
+ return _selector_first( this.columns( selector, opts ) );
8655
+ } );
8656
+
8657
+
8658
+
8659
+ var __cell_selector = function ( settings, selector, opts )
8660
+ {
8661
+ var data = settings.aoData;
8662
+ var rows = _selector_row_indexes( settings, opts );
8663
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8664
+ var allCells = $( [].concat.apply([], cells) );
8665
+ var row;
8666
+ var columns = settings.aoColumns.length;
8667
+ var a, i, ien, j, o, host;
8668
+
8669
+ var run = function ( s ) {
8670
+ var fnSelector = typeof s === 'function';
8671
+
8672
+ if ( s === null || s === undefined || fnSelector ) {
8673
+ // All cells and function selectors
8674
+ a = [];
8675
+
8676
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8677
+ row = rows[i];
8678
+
8679
+ for ( j=0 ; j<columns ; j++ ) {
8680
+ o = {
8681
+ row: row,
8682
+ column: j
8683
+ };
8684
+
8685
+ if ( fnSelector ) {
8686
+ // Selector - function
8687
+ host = data[ row ];
8688
+
8689
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
8690
+ a.push( o );
8691
+ }
8692
+ }
8693
+ else {
8694
+ // Selector - all
8695
+ a.push( o );
8696
+ }
8697
+ }
8698
+ }
8699
+
8700
+ return a;
8701
+ }
8702
+
8703
+ // Selector - index
8704
+ if ( $.isPlainObject( s ) ) {
8705
+ return [s];
8706
+ }
8707
+
8708
+ // Selector - jQuery filtered cells
8709
+ var jqResult = allCells
8710
+ .filter( s )
8711
+ .map( function (i, el) {
8712
+ return { // use a new object, in case someone changes the values
8713
+ row: el._DT_CellIndex.row,
8714
+ column: el._DT_CellIndex.column
8715
+ };
8716
+ } )
8717
+ .toArray();
8718
+
8719
+ if ( jqResult.length || ! s.nodeName ) {
8720
+ return jqResult;
8721
+ }
8722
+
8723
+ // Otherwise the selector is a node, and there is one last option - the
8724
+ // element might be a child of an element which has dt-row and dt-column
8725
+ // data attributes
8726
+ host = $(s).closest('*[data-dt-row]');
8727
+ return host.length ?
8728
+ [ {
8729
+ row: host.data('dt-row'),
8730
+ column: host.data('dt-column')
8731
+ } ] :
8732
+ [];
8733
+ };
8734
+
8735
+ return _selector_run( 'cell', selector, run, settings, opts );
8736
+ };
8737
+
8738
+
8739
+
8740
+
8741
+ _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8742
+ // Argument shifting
8743
+ if ( $.isPlainObject( rowSelector ) ) {
8744
+ // Indexes
8745
+ if ( rowSelector.row === undefined ) {
8746
+ // Selector options in first parameter
8747
+ opts = rowSelector;
8748
+ rowSelector = null;
8749
+ }
8750
+ else {
8751
+ // Cell index objects in first parameter
8752
+ opts = columnSelector;
8753
+ columnSelector = null;
8754
+ }
8755
+ }
8756
+ if ( $.isPlainObject( columnSelector ) ) {
8757
+ opts = columnSelector;
8758
+ columnSelector = null;
8759
+ }
8760
+
8761
+ // Cell selector
8762
+ if ( columnSelector === null || columnSelector === undefined ) {
8763
+ return this.iterator( 'table', function ( settings ) {
8764
+ return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8765
+ } );
8766
+ }
8767
+
8768
+ // Row + column selector
8769
+ var columns = this.columns( columnSelector, opts );
8770
+ var rows = this.rows( rowSelector, opts );
8771
+ var a, i, ien, j, jen;
8772
+
8773
+ var cells = this.iterator( 'table', function ( settings, idx ) {
8774
+ a = [];
8775
+
8776
+ for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8777
+ for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8778
+ a.push( {
8779
+ row: rows[idx][i],
8780
+ column: columns[idx][j]
8781
+ } );
8782
+ }
8783
+ }
8784
+
8785
+ return a;
8786
+ }, 1 );
8787
+
8788
+ $.extend( cells.selector, {
8789
+ cols: columnSelector,
8790
+ rows: rowSelector,
8791
+ opts: opts
8792
+ } );
8793
+
8794
+ return cells;
8795
+ } );
8796
+
8797
+
8798
+ _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8799
+ return this.iterator( 'cell', function ( settings, row, column ) {
8800
+ var data = settings.aoData[ row ];
8801
+
8802
+ return data && data.anCells ?
8803
+ data.anCells[ column ] :
8804
+ undefined;
8805
+ }, 1 );
8806
+ } );
8807
+
8808
+
8809
+ _api_register( 'cells().data()', function () {
8810
+ return this.iterator( 'cell', function ( settings, row, column ) {
8811
+ return _fnGetCellData( settings, row, column );
8812
+ }, 1 );
8813
+ } );
8814
+
8815
+
8816
+ _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8817
+ type = type === 'search' ? '_aFilterData' : '_aSortData';
8818
+
8819
+ return this.iterator( 'cell', function ( settings, row, column ) {
8820
+ return settings.aoData[ row ][ type ][ column ];
8821
+ }, 1 );
8822
+ } );
8823
+
8824
+
8825
+ _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8826
+ return this.iterator( 'cell', function ( settings, row, column ) {
8827
+ return _fnGetCellData( settings, row, column, type );
8828
+ }, 1 );
8829
+ } );
8830
+
8831
+
8832
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8833
+ return this.iterator( 'cell', function ( settings, row, column ) {
8834
+ return {
8835
+ row: row,
8836
+ column: column,
8837
+ columnVisible: _fnColumnIndexToVisible( settings, column )
8838
+ };
8839
+ }, 1 );
8840
+ } );
8841
+
8842
+
8843
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8844
+ return this.iterator( 'cell', function ( settings, row, column ) {
8845
+ _fnInvalidate( settings, row, src, column );
8846
+ } );
8847
+ } );
8848
+
8849
+
8850
+
8851
+ _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8852
+ return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8853
+ } );
8854
+
8855
+
8856
+ _api_register( 'cell().data()', function ( data ) {
8857
+ var ctx = this.context;
8858
+ var cell = this[0];
8859
+
8860
+ if ( data === undefined ) {
8861
+ // Get
8862
+ return ctx.length && cell.length ?
8863
+ _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8864
+ undefined;
8865
+ }
8866
+
8867
+ // Set
8868
+ _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8869
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8870
+
8871
+ return this;
8872
+ } );
8873
+
8874
+
8875
+
8876
+ /**
8877
+ * Get current ordering (sorting) that has been applied to the table.
8878
+ *
8879
+ * @returns {array} 2D array containing the sorting information for the first
8880
+ * table in the current context. Each element in the parent array represents
8881
+ * a column being sorted upon (i.e. multi-sorting with two columns would have
8882
+ * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8883
+ * the column index that the sorting condition applies to, the second is the
8884
+ * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8885
+ * index of the sorting order from the `column.sorting` initialisation array.
8886
+ *//**
8887
+ * Set the ordering for the table.
8888
+ *
8889
+ * @param {integer} order Column index to sort upon.
8890
+ * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8891
+ * @returns {DataTables.Api} this
8892
+ *//**
8893
+ * Set the ordering for the table.
8894
+ *
8895
+ * @param {array} order 1D array of sorting information to be applied.
8896
+ * @param {array} [...] Optional additional sorting conditions
8897
+ * @returns {DataTables.Api} this
8898
+ *//**
8899
+ * Set the ordering for the table.
8900
+ *
8901
+ * @param {array} order 2D array of sorting information to be applied.
8902
+ * @returns {DataTables.Api} this
8903
+ */
8904
+ _api_register( 'order()', function ( order, dir ) {
8905
+ var ctx = this.context;
8906
+
8907
+ if ( order === undefined ) {
8908
+ // get
8909
+ return ctx.length !== 0 ?
8910
+ ctx[0].aaSorting :
8911
+ undefined;
8912
+ }
8913
+
8914
+ // set
8915
+ if ( typeof order === 'number' ) {
8916
+ // Simple column / direction passed in
8917
+ order = [ [ order, dir ] ];
8918
+ }
8919
+ else if ( order.length && ! $.isArray( order[0] ) ) {
8920
+ // Arguments passed in (list of 1D arrays)
8921
+ order = Array.prototype.slice.call( arguments );
8922
+ }
8923
+ // otherwise a 2D array was passed in
8924
+
8925
+ return this.iterator( 'table', function ( settings ) {
8926
+ settings.aaSorting = order.slice();
8927
+ } );
8928
+ } );
8929
+
8930
+
8931
+ /**
8932
+ * Attach a sort listener to an element for a given column
8933
+ *
8934
+ * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8935
+ * listener to. This can take the form of a single DOM node, a jQuery
8936
+ * collection of nodes or a jQuery selector which will identify the node(s).
8937
+ * @param {integer} column the column that a click on this node will sort on
8938
+ * @param {function} [callback] callback function when sort is run
8939
+ * @returns {DataTables.Api} this
8940
+ */
8941
+ _api_register( 'order.listener()', function ( node, column, callback ) {
8942
+ return this.iterator( 'table', function ( settings ) {
8943
+ _fnSortAttachListener( settings, node, column, callback );
8944
+ } );
8945
+ } );
8946
+
8947
+
8948
+ _api_register( 'order.fixed()', function ( set ) {
8949
+ if ( ! set ) {
8950
+ var ctx = this.context;
8951
+ var fixed = ctx.length ?
8952
+ ctx[0].aaSortingFixed :
8953
+ undefined;
8954
+
8955
+ return $.isArray( fixed ) ?
8956
+ { pre: fixed } :
8957
+ fixed;
8958
+ }
8959
+
8960
+ return this.iterator( 'table', function ( settings ) {
8961
+ settings.aaSortingFixed = $.extend( true, {}, set );
8962
+ } );
8963
+ } );
8964
+
8965
+
8966
+ // Order by the selected column(s)
8967
+ _api_register( [
8968
+ 'columns().order()',
8969
+ 'column().order()'
8970
+ ], function ( dir ) {
8971
+ var that = this;
8972
+
8973
+ return this.iterator( 'table', function ( settings, i ) {
8974
+ var sort = [];
8975
+
8976
+ $.each( that[i], function (j, col) {
8977
+ sort.push( [ col, dir ] );
8978
+ } );
8979
+
8980
+ settings.aaSorting = sort;
8981
+ } );
8982
+ } );
8983
+
8984
+
8985
+
8986
+ _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8987
+ var ctx = this.context;
8988
+
8989
+ if ( input === undefined ) {
8990
+ // get
8991
+ return ctx.length !== 0 ?
8992
+ ctx[0].oPreviousSearch.sSearch :
8993
+ undefined;
8994
+ }
8995
+
8996
+ // set
8997
+ return this.iterator( 'table', function ( settings ) {
8998
+ if ( ! settings.oFeatures.bFilter ) {
8999
+ return;
9000
+ }
9001
+
9002
+ _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
9003
+ "sSearch": input+"",
9004
+ "bRegex": regex === null ? false : regex,
9005
+ "bSmart": smart === null ? true : smart,
9006
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
9007
+ } ), 1 );
9008
+ } );
9009
+ } );
9010
+
9011
+
9012
+ _api_registerPlural(
9013
+ 'columns().search()',
9014
+ 'column().search()',
9015
+ function ( input, regex, smart, caseInsen ) {
9016
+ return this.iterator( 'column', function ( settings, column ) {
9017
+ var preSearch = settings.aoPreSearchCols;
9018
+
9019
+ if ( input === undefined ) {
9020
+ // get
9021
+ return preSearch[ column ].sSearch;
9022
+ }
9023
+
9024
+ // set
9025
+ if ( ! settings.oFeatures.bFilter ) {
9026
+ return;
9027
+ }
9028
+
9029
+ $.extend( preSearch[ column ], {
9030
+ "sSearch": input+"",
9031
+ "bRegex": regex === null ? false : regex,
9032
+ "bSmart": smart === null ? true : smart,
9033
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
9034
+ } );
9035
+
9036
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
9037
+ } );
9038
+ }
9039
+ );
9040
+
9041
+ /*
9042
+ * State API methods
9043
+ */
9044
+
9045
+ _api_register( 'state()', function () {
9046
+ return this.context.length ?
9047
+ this.context[0].oSavedState :
9048
+ null;
9049
+ } );
9050
+
9051
+
9052
+ _api_register( 'state.clear()', function () {
9053
+ return this.iterator( 'table', function ( settings ) {
9054
+ // Save an empty object
9055
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
9056
+ } );
9057
+ } );
9058
+
9059
+
9060
+ _api_register( 'state.loaded()', function () {
9061
+ return this.context.length ?
9062
+ this.context[0].oLoadedState :
9063
+ null;
9064
+ } );
9065
+
9066
+
9067
+ _api_register( 'state.save()', function () {
9068
+ return this.iterator( 'table', function ( settings ) {
9069
+ _fnSaveState( settings );
9070
+ } );
9071
+ } );
9072
+
9073
+
9074
+
9075
+ /**
9076
+ * Provide a common method for plug-ins to check the version of DataTables being
9077
+ * used, in order to ensure compatibility.
9078
+ *
9079
+ * @param {string} version Version string to check for, in the format "X.Y.Z".
9080
+ * Note that the formats "X" and "X.Y" are also acceptable.
9081
+ * @returns {boolean} true if this version of DataTables is greater or equal to
9082
+ * the required version, or false if this version of DataTales is not
9083
+ * suitable
9084
+ * @static
9085
+ * @dtopt API-Static
9086
+ *
9087
+ * @example
9088
+ * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
9089
+ */
9090
+ DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
9091
+ {
9092
+ var aThis = DataTable.version.split('.');
9093
+ var aThat = version.split('.');
9094
+ var iThis, iThat;
9095
+
9096
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
9097
+ iThis = parseInt( aThis[i], 10 ) || 0;
9098
+ iThat = parseInt( aThat[i], 10 ) || 0;
9099
+
9100
+ // Parts are the same, keep comparing
9101
+ if (iThis === iThat) {
9102
+ continue;
9103
+ }
9104
+
9105
+ // Parts are different, return immediately
9106
+ return iThis > iThat;
9107
+ }
9108
+
9109
+ return true;
9110
+ };
9111
+
9112
+
9113
+ /**
9114
+ * Check if a `<table>` node is a DataTable table already or not.
9115
+ *
9116
+ * @param {node|jquery|string} table Table node, jQuery object or jQuery
9117
+ * selector for the table to test. Note that if more than more than one
9118
+ * table is passed on, only the first will be checked
9119
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
9120
+ * @static
9121
+ * @dtopt API-Static
9122
+ *
9123
+ * @example
9124
+ * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
9125
+ * $('#example').dataTable();
9126
+ * }
9127
+ */
9128
+ DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
9129
+ {
9130
+ var t = $(table).get(0);
9131
+ var is = false;
9132
+
9133
+ if ( table instanceof DataTable.Api ) {
9134
+ return true;
9135
+ }
9136
+
9137
+ $.each( DataTable.settings, function (i, o) {
9138
+ var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
9139
+ var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
9140
+
9141
+ if ( o.nTable === t || head === t || foot === t ) {
9142
+ is = true;
9143
+ }
9144
+ } );
9145
+
9146
+ return is;
9147
+ };
9148
+
9149
+
9150
+ /**
9151
+ * Get all DataTable tables that have been initialised - optionally you can
9152
+ * select to get only currently visible tables.
9153
+ *
9154
+ * @param {boolean} [visible=false] Flag to indicate if you want all (default)
9155
+ * or visible tables only.
9156
+ * @returns {array} Array of `table` nodes (not DataTable instances) which are
9157
+ * DataTables
9158
+ * @static
9159
+ * @dtopt API-Static
9160
+ *
9161
+ * @example
9162
+ * $.each( $.fn.dataTable.tables(true), function () {
9163
+ * $(table).DataTable().columns.adjust();
9164
+ * } );
9165
+ */
9166
+ DataTable.tables = DataTable.fnTables = function ( visible )
9167
+ {
9168
+ var api = false;
9169
+
9170
+ if ( $.isPlainObject( visible ) ) {
9171
+ api = visible.api;
9172
+ visible = visible.visible;
9173
+ }
9174
+
9175
+ var a = $.map( DataTable.settings, function (o) {
9176
+ if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
9177
+ return o.nTable;
9178
+ }
9179
+ } );
9180
+
9181
+ return api ?
9182
+ new _Api( a ) :
9183
+ a;
9184
+ };
9185
+
9186
+
9187
+ /**
9188
+ * Convert from camel case parameters to Hungarian notation. This is made public
9189
+ * for the extensions to provide the same ability as DataTables core to accept
9190
+ * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
9191
+ * parameters.
9192
+ *
9193
+ * @param {object} src The model object which holds all parameters that can be
9194
+ * mapped.
9195
+ * @param {object} user The object to convert from camel case to Hungarian.
9196
+ * @param {boolean} force When set to `true`, properties which already have a
9197
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
9198
+ * won't be.
9199
+ */
9200
+ DataTable.camelToHungarian = _fnCamelToHungarian;
9201
+
9202
+
9203
+
9204
+ /**
9205
+ *
9206
+ */
9207
+ _api_register( '$()', function ( selector, opts ) {
9208
+ var
9209
+ rows = this.rows( opts ).nodes(), // Get all rows
9210
+ jqRows = $(rows);
9211
+
9212
+ return $( [].concat(
9213
+ jqRows.filter( selector ).toArray(),
9214
+ jqRows.find( selector ).toArray()
9215
+ ) );
9216
+ } );
9217
+
9218
+
9219
+ // jQuery functions to operate on the tables
9220
+ $.each( [ 'on', 'one', 'off' ], function (i, key) {
9221
+ _api_register( key+'()', function ( /* event, handler */ ) {
9222
+ var args = Array.prototype.slice.call(arguments);
9223
+
9224
+ // Add the `dt` namespace automatically if it isn't already present
9225
+ args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
9226
+ return ! e.match(/\.dt\b/) ?
9227
+ e+'.dt' :
9228
+ e;
9229
+ } ).join( ' ' );
9230
+
9231
+ var inst = $( this.tables().nodes() );
9232
+ inst[key].apply( inst, args );
9233
+ return this;
9234
+ } );
9235
+ } );
9236
+
9237
+
9238
+ _api_register( 'clear()', function () {
9239
+ return this.iterator( 'table', function ( settings ) {
9240
+ _fnClearTable( settings );
9241
+ } );
9242
+ } );
9243
+
9244
+
9245
+ _api_register( 'settings()', function () {
9246
+ return new _Api( this.context, this.context );
9247
+ } );
9248
+
9249
+
9250
+ _api_register( 'init()', function () {
9251
+ var ctx = this.context;
9252
+ return ctx.length ? ctx[0].oInit : null;
9253
+ } );
9254
+
9255
+
9256
+ _api_register( 'data()', function () {
9257
+ return this.iterator( 'table', function ( settings ) {
9258
+ return _pluck( settings.aoData, '_aData' );
9259
+ } ).flatten();
9260
+ } );
9261
+
9262
+
9263
+ _api_register( 'destroy()', function ( remove ) {
9264
+ remove = remove || false;
9265
+
9266
+ return this.iterator( 'table', function ( settings ) {
9267
+ var orig = settings.nTableWrapper.parentNode;
9268
+ var classes = settings.oClasses;
9269
+ var table = settings.nTable;
9270
+ var tbody = settings.nTBody;
9271
+ var thead = settings.nTHead;
9272
+ var tfoot = settings.nTFoot;
9273
+ var jqTable = $(table);
9274
+ var jqTbody = $(tbody);
9275
+ var jqWrapper = $(settings.nTableWrapper);
9276
+ var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
9277
+ var i, ien;
9278
+
9279
+ // Flag to note that the table is currently being destroyed - no action
9280
+ // should be taken
9281
+ settings.bDestroying = true;
9282
+
9283
+ // Fire off the destroy callbacks for plug-ins etc
9284
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
9285
+
9286
+ // If not being removed from the document, make all columns visible
9287
+ if ( ! remove ) {
9288
+ new _Api( settings ).columns().visible( true );
9289
+ }
9290
+
9291
+ // Blitz all `DT` namespaced events (these are internal events, the
9292
+ // lowercase, `dt` events are user subscribed and they are responsible
9293
+ // for removing them
9294
+ jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
9295
+ $(window).off('.DT-'+settings.sInstance);
9296
+
9297
+ // When scrolling we had to break the table up - restore it
9298
+ if ( table != thead.parentNode ) {
9299
+ jqTable.children('thead').detach();
9300
+ jqTable.append( thead );
9301
+ }
9302
+
9303
+ if ( tfoot && table != tfoot.parentNode ) {
9304
+ jqTable.children('tfoot').detach();
9305
+ jqTable.append( tfoot );
9306
+ }
9307
+
9308
+ settings.aaSorting = [];
9309
+ settings.aaSortingFixed = [];
9310
+ _fnSortingClasses( settings );
9311
+
9312
+ $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9313
+
9314
+ $('th, td', thead).removeClass( classes.sSortable+' '+
9315
+ classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9316
+ );
9317
+
9318
+ // Add the TR elements back into the table in their original order
9319
+ jqTbody.children().detach();
9320
+ jqTbody.append( rows );
9321
+
9322
+ // Remove the DataTables generated nodes, events and classes
9323
+ var removedMethod = remove ? 'remove' : 'detach';
9324
+ jqTable[ removedMethod ]();
9325
+ jqWrapper[ removedMethod ]();
9326
+
9327
+ // If we need to reattach the table to the document
9328
+ if ( ! remove && orig ) {
9329
+ // insertBefore acts like appendChild if !arg[1]
9330
+ orig.insertBefore( table, settings.nTableReinsertBefore );
9331
+
9332
+ // Restore the width of the original table - was read from the style property,
9333
+ // so we can restore directly to that
9334
+ jqTable
9335
+ .css( 'width', settings.sDestroyWidth )
9336
+ .removeClass( classes.sTable );
9337
+
9338
+ // If the were originally stripe classes - then we add them back here.
9339
+ // Note this is not fool proof (for example if not all rows had stripe
9340
+ // classes - but it's a good effort without getting carried away
9341
+ ien = settings.asDestroyStripes.length;
9342
+
9343
+ if ( ien ) {
9344
+ jqTbody.children().each( function (i) {
9345
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
9346
+ } );
9347
+ }
9348
+ }
9349
+
9350
+ /* Remove the settings object from the settings array */
9351
+ var idx = $.inArray( settings, DataTable.settings );
9352
+ if ( idx !== -1 ) {
9353
+ DataTable.settings.splice( idx, 1 );
9354
+ }
9355
+ } );
9356
+ } );
9357
+
9358
+
9359
+ // Add the `every()` method for rows, columns and cells in a compact form
9360
+ $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
9361
+ _api_register( type+'s().every()', function ( fn ) {
9362
+ var opts = this.selector.opts;
9363
+ var api = this;
9364
+
9365
+ return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
9366
+ // Rows and columns:
9367
+ // arg1 - index
9368
+ // arg2 - table counter
9369
+ // arg3 - loop counter
9370
+ // arg4 - undefined
9371
+ // Cells:
9372
+ // arg1 - row index
9373
+ // arg2 - column index
9374
+ // arg3 - table counter
9375
+ // arg4 - loop counter
9376
+ fn.call(
9377
+ api[ type ](
9378
+ arg1,
9379
+ type==='cell' ? arg2 : opts,
9380
+ type==='cell' ? opts : undefined
9381
+ ),
9382
+ arg1, arg2, arg3, arg4
9383
+ );
9384
+ } );
9385
+ } );
9386
+ } );
9387
+
9388
+
9389
+ // i18n method for extensions to be able to use the language object from the
9390
+ // DataTable
9391
+ _api_register( 'i18n()', function ( token, def, plural ) {
9392
+ var ctx = this.context[0];
9393
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
9394
+
9395
+ if ( resolved === undefined ) {
9396
+ resolved = def;
9397
+ }
9398
+
9399
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
9400
+ resolved = resolved[ plural ] !== undefined ?
9401
+ resolved[ plural ] :
9402
+ resolved._;
9403
+ }
9404
+
9405
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
9406
+ } );
9407
+
9408
+ /**
9409
+ * Version string for plug-ins to check compatibility. Allowed format is
9410
+ * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9411
+ * only for non-release builds. See http://semver.org/ for more information.
9412
+ * @member
9413
+ * @type string
9414
+ * @default Version number
9415
+ */
9416
+ DataTable.version = "1.10.16";
9417
+
9418
+ /**
9419
+ * Private data store, containing all of the settings objects that are
9420
+ * created for the tables on a given page.
9421
+ *
9422
+ * Note that the `DataTable.settings` object is aliased to
9423
+ * `jQuery.fn.dataTableExt` through which it may be accessed and
9424
+ * manipulated, or `jQuery.fn.dataTable.settings`.
9425
+ * @member
9426
+ * @type array
9427
+ * @default []
9428
+ * @private
9429
+ */
9430
+ DataTable.settings = [];
9431
+
9432
+ /**
9433
+ * Object models container, for the various models that DataTables has
9434
+ * available to it. These models define the objects that are used to hold
9435
+ * the active state and configuration of the table.
9436
+ * @namespace
9437
+ */
9438
+ DataTable.models = {};
9439
+
9440
+
9441
+
9442
+ /**
9443
+ * Template object for the way in which DataTables holds information about
9444
+ * search information for the global filter and individual column filters.
9445
+ * @namespace
9446
+ */
9447
+ DataTable.models.oSearch = {
9448
+ /**
9449
+ * Flag to indicate if the filtering should be case insensitive or not
9450
+ * @type boolean
9451
+ * @default true
9452
+ */
9453
+ "bCaseInsensitive": true,
9454
+
9455
+ /**
9456
+ * Applied search term
9457
+ * @type string
9458
+ * @default <i>Empty string</i>
9459
+ */
9460
+ "sSearch": "",
9461
+
9462
+ /**
9463
+ * Flag to indicate if the search term should be interpreted as a
9464
+ * regular expression (true) or not (false) and therefore and special
9465
+ * regex characters escaped.
9466
+ * @type boolean
9467
+ * @default false
9468
+ */
9469
+ "bRegex": false,
9470
+
9471
+ /**
9472
+ * Flag to indicate if DataTables is to use its smart filtering or not.
9473
+ * @type boolean
9474
+ * @default true
9475
+ */
9476
+ "bSmart": true
9477
+ };
9478
+
9479
+
9480
+
9481
+
9482
+ /**
9483
+ * Template object for the way in which DataTables holds information about
9484
+ * each individual row. This is the object format used for the settings
9485
+ * aoData array.
9486
+ * @namespace
9487
+ */
9488
+ DataTable.models.oRow = {
9489
+ /**
9490
+ * TR element for the row
9491
+ * @type node
9492
+ * @default null
9493
+ */
9494
+ "nTr": null,
9495
+
9496
+ /**
9497
+ * Array of TD elements for each row. This is null until the row has been
9498
+ * created.
9499
+ * @type array nodes
9500
+ * @default []
9501
+ */
9502
+ "anCells": null,
9503
+
9504
+ /**
9505
+ * Data object from the original data source for the row. This is either
9506
+ * an array if using the traditional form of DataTables, or an object if
9507
+ * using mData options. The exact type will depend on the passed in
9508
+ * data from the data source, or will be an array if using DOM a data
9509
+ * source.
9510
+ * @type array|object
9511
+ * @default []
9512
+ */
9513
+ "_aData": [],
9514
+
9515
+ /**
9516
+ * Sorting data cache - this array is ostensibly the same length as the
9517
+ * number of columns (although each index is generated only as it is
9518
+ * needed), and holds the data that is used for sorting each column in the
9519
+ * row. We do this cache generation at the start of the sort in order that
9520
+ * the formatting of the sort data need be done only once for each cell
9521
+ * per sort. This array should not be read from or written to by anything
9522
+ * other than the master sorting methods.
9523
+ * @type array
9524
+ * @default null
9525
+ * @private
9526
+ */
9527
+ "_aSortData": null,
9528
+
9529
+ /**
9530
+ * Per cell filtering data cache. As per the sort data cache, used to
9531
+ * increase the performance of the filtering in DataTables
9532
+ * @type array
9533
+ * @default null
9534
+ * @private
9535
+ */
9536
+ "_aFilterData": null,
9537
+
9538
+ /**
9539
+ * Filtering data cache. This is the same as the cell filtering cache, but
9540
+ * in this case a string rather than an array. This is easily computed with
9541
+ * a join on `_aFilterData`, but is provided as a cache so the join isn't
9542
+ * needed on every search (memory traded for performance)
9543
+ * @type array
9544
+ * @default null
9545
+ * @private
9546
+ */
9547
+ "_sFilterRow": null,
9548
+
9549
+ /**
9550
+ * Cache of the class name that DataTables has applied to the row, so we
9551
+ * can quickly look at this variable rather than needing to do a DOM check
9552
+ * on className for the nTr property.
9553
+ * @type string
9554
+ * @default <i>Empty string</i>
9555
+ * @private
9556
+ */
9557
+ "_sRowStripe": "",
9558
+
9559
+ /**
9560
+ * Denote if the original data source was from the DOM, or the data source
9561
+ * object. This is used for invalidating data, so DataTables can
9562
+ * automatically read data from the original source, unless uninstructed
9563
+ * otherwise.
9564
+ * @type string
9565
+ * @default null
9566
+ * @private
9567
+ */
9568
+ "src": null,
9569
+
9570
+ /**
9571
+ * Index in the aoData array. This saves an indexOf lookup when we have the
9572
+ * object, but want to know the index
9573
+ * @type integer
9574
+ * @default -1
9575
+ * @private
9576
+ */
9577
+ "idx": -1
9578
+ };
9579
+
9580
+
9581
+ /**
9582
+ * Template object for the column information object in DataTables. This object
9583
+ * is held in the settings aoColumns array and contains all the information that
9584
+ * DataTables needs about each individual column.
9585
+ *
9586
+ * Note that this object is related to {@link DataTable.defaults.column}
9587
+ * but this one is the internal data store for DataTables's cache of columns.
9588
+ * It should NOT be manipulated outside of DataTables. Any configuration should
9589
+ * be done through the initialisation options.
9590
+ * @namespace
9591
+ */
9592
+ DataTable.models.oColumn = {
9593
+ /**
9594
+ * Column index. This could be worked out on-the-fly with $.inArray, but it
9595
+ * is faster to just hold it as a variable
9596
+ * @type integer
9597
+ * @default null
9598
+ */
9599
+ "idx": null,
9600
+
9601
+ /**
9602
+ * A list of the columns that sorting should occur on when this column
9603
+ * is sorted. That this property is an array allows multi-column sorting
9604
+ * to be defined for a column (for example first name / last name columns
9605
+ * would benefit from this). The values are integers pointing to the
9606
+ * columns to be sorted on (typically it will be a single integer pointing
9607
+ * at itself, but that doesn't need to be the case).
9608
+ * @type array
9609
+ */
9610
+ "aDataSort": null,
9611
+
9612
+ /**
9613
+ * Define the sorting directions that are applied to the column, in sequence
9614
+ * as the column is repeatedly sorted upon - i.e. the first value is used
9615
+ * as the sorting direction when the column if first sorted (clicked on).
9616
+ * Sort it again (click again) and it will move on to the next index.
9617
+ * Repeat until loop.
9618
+ * @type array
9619
+ */
9620
+ "asSorting": null,
9621
+
9622
+ /**
9623
+ * Flag to indicate if the column is searchable, and thus should be included
9624
+ * in the filtering or not.
9625
+ * @type boolean
9626
+ */
9627
+ "bSearchable": null,
9628
+
9629
+ /**
9630
+ * Flag to indicate if the column is sortable or not.
9631
+ * @type boolean
9632
+ */
9633
+ "bSortable": null,
9634
+
9635
+ /**
9636
+ * Flag to indicate if the column is currently visible in the table or not
9637
+ * @type boolean
9638
+ */
9639
+ "bVisible": null,
9640
+
9641
+ /**
9642
+ * Store for manual type assignment using the `column.type` option. This
9643
+ * is held in store so we can manipulate the column's `sType` property.
9644
+ * @type string
9645
+ * @default null
9646
+ * @private
9647
+ */
9648
+ "_sManualType": null,
9649
+
9650
+ /**
9651
+ * Flag to indicate if HTML5 data attributes should be used as the data
9652
+ * source for filtering or sorting. True is either are.
9653
+ * @type boolean
9654
+ * @default false
9655
+ * @private
9656
+ */
9657
+ "_bAttrSrc": false,
9658
+
9659
+ /**
9660
+ * Developer definable function that is called whenever a cell is created (Ajax source,
9661
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9662
+ * allowing you to modify the DOM element (add background colour for example) when the
9663
+ * element is available.
9664
+ * @type function
9665
+ * @param {element} nTd The TD node that has been created
9666
+ * @param {*} sData The Data for the cell
9667
+ * @param {array|object} oData The data for the whole row
9668
+ * @param {int} iRow The row index for the aoData data store
9669
+ * @default null
9670
+ */
9671
+ "fnCreatedCell": null,
9672
+
9673
+ /**
9674
+ * Function to get data from a cell in a column. You should <b>never</b>
9675
+ * access data directly through _aData internally in DataTables - always use
9676
+ * the method attached to this property. It allows mData to function as
9677
+ * required. This function is automatically assigned by the column
9678
+ * initialisation method
9679
+ * @type function
9680
+ * @param {array|object} oData The data array/object for the array
9681
+ * (i.e. aoData[]._aData)
9682
+ * @param {string} sSpecific The specific data type you want to get -
9683
+ * 'display', 'type' 'filter' 'sort'
9684
+ * @returns {*} The data for the cell from the given row's data
9685
+ * @default null
9686
+ */
9687
+ "fnGetData": null,
9688
+
9689
+ /**
9690
+ * Function to set data for a cell in the column. You should <b>never</b>
9691
+ * set the data directly to _aData internally in DataTables - always use
9692
+ * this method. It allows mData to function as required. This function
9693
+ * is automatically assigned by the column initialisation method
9694
+ * @type function
9695
+ * @param {array|object} oData The data array/object for the array
9696
+ * (i.e. aoData[]._aData)
9697
+ * @param {*} sValue Value to set
9698
+ * @default null
9699
+ */
9700
+ "fnSetData": null,
9701
+
9702
+ /**
9703
+ * Property to read the value for the cells in the column from the data
9704
+ * source array / object. If null, then the default content is used, if a
9705
+ * function is given then the return from the function is used.
9706
+ * @type function|int|string|null
9707
+ * @default null
9708
+ */
9709
+ "mData": null,
9710
+
9711
+ /**
9712
+ * Partner property to mData which is used (only when defined) to get
9713
+ * the data - i.e. it is basically the same as mData, but without the
9714
+ * 'set' option, and also the data fed to it is the result from mData.
9715
+ * This is the rendering method to match the data method of mData.
9716
+ * @type function|int|string|null
9717
+ * @default null
9718
+ */
9719
+ "mRender": null,
9720
+
9721
+ /**
9722
+ * Unique header TH/TD element for this column - this is what the sorting
9723
+ * listener is attached to (if sorting is enabled.)
9724
+ * @type node
9725
+ * @default null
9726
+ */
9727
+ "nTh": null,
9728
+
9729
+ /**
9730
+ * Unique footer TH/TD element for this column (if there is one). Not used
9731
+ * in DataTables as such, but can be used for plug-ins to reference the
9732
+ * footer for each column.
9733
+ * @type node
9734
+ * @default null
9735
+ */
9736
+ "nTf": null,
9737
+
9738
+ /**
9739
+ * The class to apply to all TD elements in the table's TBODY for the column
9740
+ * @type string
9741
+ * @default null
9742
+ */
9743
+ "sClass": null,
9744
+
9745
+ /**
9746
+ * When DataTables calculates the column widths to assign to each column,
9747
+ * it finds the longest string in each column and then constructs a
9748
+ * temporary table and reads the widths from that. The problem with this
9749
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
9750
+ * string - thus the calculation can go wrong (doing it properly and putting
9751
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
9752
+ * a "work around" we provide this option. It will append its value to the
9753
+ * text that is found to be the longest string for the column - i.e. padding.
9754
+ * @type string
9755
+ */
9756
+ "sContentPadding": null,
9757
+
9758
+ /**
9759
+ * Allows a default value to be given for a column's data, and will be used
9760
+ * whenever a null data source is encountered (this can be because mData
9761
+ * is set to null, or because the data source itself is null).
9762
+ * @type string
9763
+ * @default null
9764
+ */
9765
+ "sDefaultContent": null,
9766
+
9767
+ /**
9768
+ * Name for the column, allowing reference to the column by name as well as
9769
+ * by index (needs a lookup to work by name).
9770
+ * @type string
9771
+ */
9772
+ "sName": null,
9773
+
9774
+ /**
9775
+ * Custom sorting data type - defines which of the available plug-ins in
9776
+ * afnSortData the custom sorting will use - if any is defined.
9777
+ * @type string
9778
+ * @default std
9779
+ */
9780
+ "sSortDataType": 'std',
9781
+
9782
+ /**
9783
+ * Class to be applied to the header element when sorting on this column
9784
+ * @type string
9785
+ * @default null
9786
+ */
9787
+ "sSortingClass": null,
9788
+
9789
+ /**
9790
+ * Class to be applied to the header element when sorting on this column -
9791
+ * when jQuery UI theming is used.
9792
+ * @type string
9793
+ * @default null
9794
+ */
9795
+ "sSortingClassJUI": null,
9796
+
9797
+ /**
9798
+ * Title of the column - what is seen in the TH element (nTh).
9799
+ * @type string
9800
+ */
9801
+ "sTitle": null,
9802
+
9803
+ /**
9804
+ * Column sorting and filtering type
9805
+ * @type string
9806
+ * @default null
9807
+ */
9808
+ "sType": null,
9809
+
9810
+ /**
9811
+ * Width of the column
9812
+ * @type string
9813
+ * @default null
9814
+ */
9815
+ "sWidth": null,
9816
+
9817
+ /**
9818
+ * Width of the column when it was first "encountered"
9819
+ * @type string
9820
+ * @default null
9821
+ */
9822
+ "sWidthOrig": null
9823
+ };
9824
+
9825
+
9826
+ /*
9827
+ * Developer note: The properties of the object below are given in Hungarian
9828
+ * notation, that was used as the interface for DataTables prior to v1.10, however
9829
+ * from v1.10 onwards the primary interface is camel case. In order to avoid
9830
+ * breaking backwards compatibility utterly with this change, the Hungarian
9831
+ * version is still, internally the primary interface, but is is not documented
9832
+ * - hence the @name tags in each doc comment. This allows a Javascript function
9833
+ * to create a map from Hungarian notation to camel case (going the other direction
9834
+ * would require each property to be listed, which would at around 3K to the size
9835
+ * of DataTables, while this method is about a 0.5K hit.
9836
+ *
9837
+ * Ultimately this does pave the way for Hungarian notation to be dropped
9838
+ * completely, but that is a massive amount of work and will break current
9839
+ * installs (therefore is on-hold until v2).
9840
+ */
9841
+
9842
+ /**
9843
+ * Initialisation options that can be given to DataTables at initialisation
9844
+ * time.
9845
+ * @namespace
9846
+ */
9847
+ DataTable.defaults = {
9848
+ /**
9849
+ * An array of data to use for the table, passed in at initialisation which
9850
+ * will be used in preference to any data which is already in the DOM. This is
9851
+ * particularly useful for constructing tables purely in Javascript, for
9852
+ * example with a custom Ajax call.
9853
+ * @type array
9854
+ * @default null
9855
+ *
9856
+ * @dtopt Option
9857
+ * @name DataTable.defaults.data
9858
+ *
9859
+ * @example
9860
+ * // Using a 2D array data source
9861
+ * $(document).ready( function () {
9862
+ * $('#example').dataTable( {
9863
+ * "data": [
9864
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9865
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9866
+ * ],
9867
+ * "columns": [
9868
+ * { "title": "Engine" },
9869
+ * { "title": "Browser" },
9870
+ * { "title": "Platform" },
9871
+ * { "title": "Version" },
9872
+ * { "title": "Grade" }
9873
+ * ]
9874
+ * } );
9875
+ * } );
9876
+ *
9877
+ * @example
9878
+ * // Using an array of objects as a data source (`data`)
9879
+ * $(document).ready( function () {
9880
+ * $('#example').dataTable( {
9881
+ * "data": [
9882
+ * {
9883
+ * "engine": "Trident",
9884
+ * "browser": "Internet Explorer 4.0",
9885
+ * "platform": "Win 95+",
9886
+ * "version": 4,
9887
+ * "grade": "X"
9888
+ * },
9889
+ * {
9890
+ * "engine": "Trident",
9891
+ * "browser": "Internet Explorer 5.0",
9892
+ * "platform": "Win 95+",
9893
+ * "version": 5,
9894
+ * "grade": "C"
9895
+ * }
9896
+ * ],
9897
+ * "columns": [
9898
+ * { "title": "Engine", "data": "engine" },
9899
+ * { "title": "Browser", "data": "browser" },
9900
+ * { "title": "Platform", "data": "platform" },
9901
+ * { "title": "Version", "data": "version" },
9902
+ * { "title": "Grade", "data": "grade" }
9903
+ * ]
9904
+ * } );
9905
+ * } );
9906
+ */
9907
+ "aaData": null,
9908
+
9909
+
9910
+ /**
9911
+ * If ordering is enabled, then DataTables will perform a first pass sort on
9912
+ * initialisation. You can define which column(s) the sort is performed
9913
+ * upon, and the sorting direction, with this variable. The `sorting` array
9914
+ * should contain an array for each column to be sorted initially containing
9915
+ * the column's index and a direction string ('asc' or 'desc').
9916
+ * @type array
9917
+ * @default [[0,'asc']]
9918
+ *
9919
+ * @dtopt Option
9920
+ * @name DataTable.defaults.order
9921
+ *
9922
+ * @example
9923
+ * // Sort by 3rd column first, and then 4th column
9924
+ * $(document).ready( function() {
9925
+ * $('#example').dataTable( {
9926
+ * "order": [[2,'asc'], [3,'desc']]
9927
+ * } );
9928
+ * } );
9929
+ *
9930
+ * // No initial sorting
9931
+ * $(document).ready( function() {
9932
+ * $('#example').dataTable( {
9933
+ * "order": []
9934
+ * } );
9935
+ * } );
9936
+ */
9937
+ "aaSorting": [[0,'asc']],
9938
+
9939
+
9940
+ /**
9941
+ * This parameter is basically identical to the `sorting` parameter, but
9942
+ * cannot be overridden by user interaction with the table. What this means
9943
+ * is that you could have a column (visible or hidden) which the sorting
9944
+ * will always be forced on first - any sorting after that (from the user)
9945
+ * will then be performed as required. This can be useful for grouping rows
9946
+ * together.
9947
+ * @type array
9948
+ * @default null
9949
+ *
9950
+ * @dtopt Option
9951
+ * @name DataTable.defaults.orderFixed
9952
+ *
9953
+ * @example
9954
+ * $(document).ready( function() {
9955
+ * $('#example').dataTable( {
9956
+ * "orderFixed": [[0,'asc']]
9957
+ * } );
9958
+ * } )
9959
+ */
9960
+ "aaSortingFixed": [],
9961
+
9962
+
9963
+ /**
9964
+ * DataTables can be instructed to load data to display in the table from a
9965
+ * Ajax source. This option defines how that Ajax call is made and where to.
9966
+ *
9967
+ * The `ajax` property has three different modes of operation, depending on
9968
+ * how it is defined. These are:
9969
+ *
9970
+ * * `string` - Set the URL from where the data should be loaded from.
9971
+ * * `object` - Define properties for `jQuery.ajax`.
9972
+ * * `function` - Custom data get function
9973
+ *
9974
+ * `string`
9975
+ * --------
9976
+ *
9977
+ * As a string, the `ajax` property simply defines the URL from which
9978
+ * DataTables will load data.
9979
+ *
9980
+ * `object`
9981
+ * --------
9982
+ *
9983
+ * As an object, the parameters in the object are passed to
9984
+ * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9985
+ * of the Ajax request. DataTables has a number of default parameters which
9986
+ * you can override using this option. Please refer to the jQuery
9987
+ * documentation for a full description of the options available, although
9988
+ * the following parameters provide additional options in DataTables or
9989
+ * require special consideration:
9990
+ *
9991
+ * * `data` - As with jQuery, `data` can be provided as an object, but it
9992
+ * can also be used as a function to manipulate the data DataTables sends
9993
+ * to the server. The function takes a single parameter, an object of
9994
+ * parameters with the values that DataTables has readied for sending. An
9995
+ * object may be returned which will be merged into the DataTables
9996
+ * defaults, or you can add the items to the object that was passed in and
9997
+ * not return anything from the function. This supersedes `fnServerParams`
9998
+ * from DataTables 1.9-.
9999
+ *
10000
+ * * `dataSrc` - By default DataTables will look for the property `data` (or
10001
+ * `aaData` for compatibility with DataTables 1.9-) when obtaining data
10002
+ * from an Ajax source or for server-side processing - this parameter
10003
+ * allows that property to be changed. You can use Javascript dotted
10004
+ * object notation to get a data source for multiple levels of nesting, or
10005
+ * it my be used as a function. As a function it takes a single parameter,
10006
+ * the JSON returned from the server, which can be manipulated as
10007
+ * required, with the returned value being that used by DataTables as the
10008
+ * data source for the table. This supersedes `sAjaxDataProp` from
10009
+ * DataTables 1.9-.
10010
+ *
10011
+ * * `success` - Should not be overridden it is used internally in
10012
+ * DataTables. To manipulate / transform the data returned by the server
10013
+ * use `ajax.dataSrc`, or use `ajax` as a function (see below).
10014
+ *
10015
+ * `function`
10016
+ * ----------
10017
+ *
10018
+ * As a function, making the Ajax call is left up to yourself allowing
10019
+ * complete control of the Ajax request. Indeed, if desired, a method other
10020
+ * than Ajax could be used to obtain the required data, such as Web storage
10021
+ * or an AIR database.
10022
+ *
10023
+ * The function is given four parameters and no return is required. The
10024
+ * parameters are:
10025
+ *
10026
+ * 1. _object_ - Data to send to the server
10027
+ * 2. _function_ - Callback function that must be executed when the required
10028
+ * data has been obtained. That data should be passed into the callback
10029
+ * as the only parameter
10030
+ * 3. _object_ - DataTables settings object for the table
10031
+ *
10032
+ * Note that this supersedes `fnServerData` from DataTables 1.9-.
10033
+ *
10034
+ * @type string|object|function
10035
+ * @default null
10036
+ *
10037
+ * @dtopt Option
10038
+ * @name DataTable.defaults.ajax
10039
+ * @since 1.10.0
10040
+ *
10041
+ * @example
10042
+ * // Get JSON data from a file via Ajax.
10043
+ * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
10044
+ * $('#example').dataTable( {
10045
+ * "ajax": "data.json"
10046
+ * } );
10047
+ *
10048
+ * @example
10049
+ * // Get JSON data from a file via Ajax, using `dataSrc` to change
10050
+ * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
10051
+ * $('#example').dataTable( {
10052
+ * "ajax": {
10053
+ * "url": "data.json",
10054
+ * "dataSrc": "tableData"
10055
+ * }
10056
+ * } );
10057
+ *
10058
+ * @example
10059
+ * // Get JSON data from a file via Ajax, using `dataSrc` to read data
10060
+ * // from a plain array rather than an array in an object
10061
+ * $('#example').dataTable( {
10062
+ * "ajax": {
10063
+ * "url": "data.json",
10064
+ * "dataSrc": ""
10065
+ * }
10066
+ * } );
10067
+ *
10068
+ * @example
10069
+ * // Manipulate the data returned from the server - add a link to data
10070
+ * // (note this can, should, be done using `render` for the column - this
10071
+ * // is just a simple example of how the data can be manipulated).
10072
+ * $('#example').dataTable( {
10073
+ * "ajax": {
10074
+ * "url": "data.json",
10075
+ * "dataSrc": function ( json ) {
10076
+ * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
10077
+ * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
10078
+ * }
10079
+ * return json;
10080
+ * }
10081
+ * }
10082
+ * } );
10083
+ *
10084
+ * @example
10085
+ * // Add data to the request
10086
+ * $('#example').dataTable( {
10087
+ * "ajax": {
10088
+ * "url": "data.json",
10089
+ * "data": function ( d ) {
10090
+ * return {
10091
+ * "extra_search": $('#extra').val()
10092
+ * };
10093
+ * }
10094
+ * }
10095
+ * } );
10096
+ *
10097
+ * @example
10098
+ * // Send request as POST
10099
+ * $('#example').dataTable( {
10100
+ * "ajax": {
10101
+ * "url": "data.json",
10102
+ * "type": "POST"
10103
+ * }
10104
+ * } );
10105
+ *
10106
+ * @example
10107
+ * // Get the data from localStorage (could interface with a form for
10108
+ * // adding, editing and removing rows).
10109
+ * $('#example').dataTable( {
10110
+ * "ajax": function (data, callback, settings) {
10111
+ * callback(
10112
+ * JSON.parse( localStorage.getItem('dataTablesData') )
10113
+ * );
10114
+ * }
10115
+ * } );
10116
+ */
10117
+ "ajax": null,
10118
+
10119
+
10120
+ /**
10121
+ * This parameter allows you to readily specify the entries in the length drop
10122
+ * down menu that DataTables shows when pagination is enabled. It can be
10123
+ * either a 1D array of options which will be used for both the displayed
10124
+ * option and the value, or a 2D array which will use the array in the first
10125
+ * position as the value, and the array in the second position as the
10126
+ * displayed options (useful for language strings such as 'All').
10127
+ *
10128
+ * Note that the `pageLength` property will be automatically set to the
10129
+ * first value given in this array, unless `pageLength` is also provided.
10130
+ * @type array
10131
+ * @default [ 10, 25, 50, 100 ]
10132
+ *
10133
+ * @dtopt Option
10134
+ * @name DataTable.defaults.lengthMenu
10135
+ *
10136
+ * @example
10137
+ * $(document).ready( function() {
10138
+ * $('#example').dataTable( {
10139
+ * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
10140
+ * } );
10141
+ * } );
10142
+ */
10143
+ "aLengthMenu": [ 10, 25, 50, 100 ],
10144
+
10145
+
10146
+ /**
10147
+ * The `columns` option in the initialisation parameter allows you to define
10148
+ * details about the way individual columns behave. For a full list of
10149
+ * column options that can be set, please see
10150
+ * {@link DataTable.defaults.column}. Note that if you use `columns` to
10151
+ * define your columns, you must have an entry in the array for every single
10152
+ * column that you have in your table (these can be null if you don't which
10153
+ * to specify any options).
10154
+ * @member
10155
+ *
10156
+ * @name DataTable.defaults.column
10157
+ */
10158
+ "aoColumns": null,
10159
+
10160
+ /**
10161
+ * Very similar to `columns`, `columnDefs` allows you to target a specific
10162
+ * column, multiple columns, or all columns, using the `targets` property of
10163
+ * each object in the array. This allows great flexibility when creating
10164
+ * tables, as the `columnDefs` arrays can be of any length, targeting the
10165
+ * columns you specifically want. `columnDefs` may use any of the column
10166
+ * options available: {@link DataTable.defaults.column}, but it _must_
10167
+ * have `targets` defined in each object in the array. Values in the `targets`
10168
+ * array may be:
10169
+ * <ul>
10170
+ * <li>a string - class name will be matched on the TH for the column</li>
10171
+ * <li>0 or a positive integer - column index counting from the left</li>
10172
+ * <li>a negative integer - column index counting from the right</li>
10173
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
10174
+ * </ul>
10175
+ * @member
10176
+ *
10177
+ * @name DataTable.defaults.columnDefs
10178
+ */
10179
+ "aoColumnDefs": null,
10180
+
10181
+
10182
+ /**
10183
+ * Basically the same as `search`, this parameter defines the individual column
10184
+ * filtering state at initialisation time. The array must be of the same size
10185
+ * as the number of columns, and each element be an object with the parameters
10186
+ * `search` and `escapeRegex` (the latter is optional). 'null' is also
10187
+ * accepted and the default will be used.
10188
+ * @type array
10189
+ * @default []
10190
+ *
10191
+ * @dtopt Option
10192
+ * @name DataTable.defaults.searchCols
10193
+ *
10194
+ * @example
10195
+ * $(document).ready( function() {
10196
+ * $('#example').dataTable( {
10197
+ * "searchCols": [
10198
+ * null,
10199
+ * { "search": "My filter" },
10200
+ * null,
10201
+ * { "search": "^[0-9]", "escapeRegex": false }
10202
+ * ]
10203
+ * } );
10204
+ * } )
10205
+ */
10206
+ "aoSearchCols": [],
10207
+
10208
+
10209
+ /**
10210
+ * An array of CSS classes that should be applied to displayed rows. This
10211
+ * array may be of any length, and DataTables will apply each class
10212
+ * sequentially, looping when required.
10213
+ * @type array
10214
+ * @default null <i>Will take the values determined by the `oClasses.stripe*`
10215
+ * options</i>
10216
+ *
10217
+ * @dtopt Option
10218
+ * @name DataTable.defaults.stripeClasses
10219
+ *
10220
+ * @example
10221
+ * $(document).ready( function() {
10222
+ * $('#example').dataTable( {
10223
+ * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
10224
+ * } );
10225
+ * } )
10226
+ */
10227
+ "asStripeClasses": null,
10228
+
10229
+
10230
+ /**
10231
+ * Enable or disable automatic column width calculation. This can be disabled
10232
+ * as an optimisation (it takes some time to calculate the widths) if the
10233
+ * tables widths are passed in using `columns`.
10234
+ * @type boolean
10235
+ * @default true
10236
+ *
10237
+ * @dtopt Features
10238
+ * @name DataTable.defaults.autoWidth
10239
+ *
10240
+ * @example
10241
+ * $(document).ready( function () {
10242
+ * $('#example').dataTable( {
10243
+ * "autoWidth": false
10244
+ * } );
10245
+ * } );
10246
+ */
10247
+ "bAutoWidth": true,
10248
+
10249
+
10250
+ /**
10251
+ * Deferred rendering can provide DataTables with a huge speed boost when you
10252
+ * are using an Ajax or JS data source for the table. This option, when set to
10253
+ * true, will cause DataTables to defer the creation of the table elements for
10254
+ * each row until they are needed for a draw - saving a significant amount of
10255
+ * time.
10256
+ * @type boolean
10257
+ * @default false
10258
+ *
10259
+ * @dtopt Features
10260
+ * @name DataTable.defaults.deferRender
10261
+ *
10262
+ * @example
10263
+ * $(document).ready( function() {
10264
+ * $('#example').dataTable( {
10265
+ * "ajax": "sources/arrays.txt",
10266
+ * "deferRender": true
10267
+ * } );
10268
+ * } );
10269
+ */
10270
+ "bDeferRender": false,
10271
+
10272
+
10273
+ /**
10274
+ * Replace a DataTable which matches the given selector and replace it with
10275
+ * one which has the properties of the new initialisation object passed. If no
10276
+ * table matches the selector, then the new DataTable will be constructed as
10277
+ * per normal.
10278
+ * @type boolean
10279
+ * @default false
10280
+ *
10281
+ * @dtopt Options
10282
+ * @name DataTable.defaults.destroy
10283
+ *
10284
+ * @example
10285
+ * $(document).ready( function() {
10286
+ * $('#example').dataTable( {
10287
+ * "srollY": "200px",
10288
+ * "paginate": false
10289
+ * } );
10290
+ *
10291
+ * // Some time later....
10292
+ * $('#example').dataTable( {
10293
+ * "filter": false,
10294
+ * "destroy": true
10295
+ * } );
10296
+ * } );
10297
+ */
10298
+ "bDestroy": false,
10299
+
10300
+
10301
+ /**
10302
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
10303
+ * that it allows the end user to input multiple words (space separated) and
10304
+ * will match a row containing those words, even if not in the order that was
10305
+ * specified (this allow matching across multiple columns). Note that if you
10306
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
10307
+ * default filtering input box and retain filtering abilities, please use
10308
+ * {@link DataTable.defaults.dom}.
10309
+ * @type boolean
10310
+ * @default true
10311
+ *
10312
+ * @dtopt Features
10313
+ * @name DataTable.defaults.searching
10314
+ *
10315
+ * @example
10316
+ * $(document).ready( function () {
10317
+ * $('#example').dataTable( {
10318
+ * "searching": false
10319
+ * } );
10320
+ * } );
10321
+ */
10322
+ "bFilter": true,
10323
+
10324
+
10325
+ /**
10326
+ * Enable or disable the table information display. This shows information
10327
+ * about the data that is currently visible on the page, including information
10328
+ * about filtered data if that action is being performed.
10329
+ * @type boolean
10330
+ * @default true
10331
+ *
10332
+ * @dtopt Features
10333
+ * @name DataTable.defaults.info
10334
+ *
10335
+ * @example
10336
+ * $(document).ready( function () {
10337
+ * $('#example').dataTable( {
10338
+ * "info": false
10339
+ * } );
10340
+ * } );
10341
+ */
10342
+ "bInfo": true,
10343
+
10344
+
10345
+ /**
10346
+ * Allows the end user to select the size of a formatted page from a select
10347
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10348
+ * @type boolean
10349
+ * @default true
10350
+ *
10351
+ * @dtopt Features
10352
+ * @name DataTable.defaults.lengthChange
10353
+ *
10354
+ * @example
10355
+ * $(document).ready( function () {
10356
+ * $('#example').dataTable( {
10357
+ * "lengthChange": false
10358
+ * } );
10359
+ * } );
10360
+ */
10361
+ "bLengthChange": true,
10362
+
10363
+
10364
+ /**
10365
+ * Enable or disable pagination.
10366
+ * @type boolean
10367
+ * @default true
10368
+ *
10369
+ * @dtopt Features
10370
+ * @name DataTable.defaults.paging
10371
+ *
10372
+ * @example
10373
+ * $(document).ready( function () {
10374
+ * $('#example').dataTable( {
10375
+ * "paging": false
10376
+ * } );
10377
+ * } );
10378
+ */
10379
+ "bPaginate": true,
10380
+
10381
+
10382
+ /**
10383
+ * Enable or disable the display of a 'processing' indicator when the table is
10384
+ * being processed (e.g. a sort). This is particularly useful for tables with
10385
+ * large amounts of data where it can take a noticeable amount of time to sort
10386
+ * the entries.
10387
+ * @type boolean
10388
+ * @default false
10389
+ *
10390
+ * @dtopt Features
10391
+ * @name DataTable.defaults.processing
10392
+ *
10393
+ * @example
10394
+ * $(document).ready( function () {
10395
+ * $('#example').dataTable( {
10396
+ * "processing": true
10397
+ * } );
10398
+ * } );
10399
+ */
10400
+ "bProcessing": false,
10401
+
10402
+
10403
+ /**
10404
+ * Retrieve the DataTables object for the given selector. Note that if the
10405
+ * table has already been initialised, this parameter will cause DataTables
10406
+ * to simply return the object that has already been set up - it will not take
10407
+ * account of any changes you might have made to the initialisation object
10408
+ * passed to DataTables (setting this parameter to true is an acknowledgement
10409
+ * that you understand this). `destroy` can be used to reinitialise a table if
10410
+ * you need.
10411
+ * @type boolean
10412
+ * @default false
10413
+ *
10414
+ * @dtopt Options
10415
+ * @name DataTable.defaults.retrieve
10416
+ *
10417
+ * @example
10418
+ * $(document).ready( function() {
10419
+ * initTable();
10420
+ * tableActions();
10421
+ * } );
10422
+ *
10423
+ * function initTable ()
10424
+ * {
10425
+ * return $('#example').dataTable( {
10426
+ * "scrollY": "200px",
10427
+ * "paginate": false,
10428
+ * "retrieve": true
10429
+ * } );
10430
+ * }
10431
+ *
10432
+ * function tableActions ()
10433
+ * {
10434
+ * var table = initTable();
10435
+ * // perform API operations with oTable
10436
+ * }
10437
+ */
10438
+ "bRetrieve": false,
10439
+
10440
+
10441
+ /**
10442
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
10443
+ * the table's viewport to the given height at all times (useful for layout).
10444
+ * However, this can look odd when filtering data down to a small data set,
10445
+ * and the footer is left "floating" further down. This parameter (when
10446
+ * enabled) will cause DataTables to collapse the table's viewport down when
10447
+ * the result set will fit within the given Y height.
10448
+ * @type boolean
10449
+ * @default false
10450
+ *
10451
+ * @dtopt Options
10452
+ * @name DataTable.defaults.scrollCollapse
10453
+ *
10454
+ * @example
10455
+ * $(document).ready( function() {
10456
+ * $('#example').dataTable( {
10457
+ * "scrollY": "200",
10458
+ * "scrollCollapse": true
10459
+ * } );
10460
+ * } );
10461
+ */
10462
+ "bScrollCollapse": false,
10463
+
10464
+
10465
+ /**
10466
+ * Configure DataTables to use server-side processing. Note that the
10467
+ * `ajax` parameter must also be given in order to give DataTables a
10468
+ * source to obtain the required data for each draw.
10469
+ * @type boolean
10470
+ * @default false
10471
+ *
10472
+ * @dtopt Features
10473
+ * @dtopt Server-side
10474
+ * @name DataTable.defaults.serverSide
10475
+ *
10476
+ * @example
10477
+ * $(document).ready( function () {
10478
+ * $('#example').dataTable( {
10479
+ * "serverSide": true,
10480
+ * "ajax": "xhr.php"
10481
+ * } );
10482
+ * } );
10483
+ */
10484
+ "bServerSide": false,
10485
+
10486
+
10487
+ /**
10488
+ * Enable or disable sorting of columns. Sorting of individual columns can be
10489
+ * disabled by the `sortable` option for each column.
10490
+ * @type boolean
10491
+ * @default true
10492
+ *
10493
+ * @dtopt Features
10494
+ * @name DataTable.defaults.ordering
10495
+ *
10496
+ * @example
10497
+ * $(document).ready( function () {
10498
+ * $('#example').dataTable( {
10499
+ * "ordering": false
10500
+ * } );
10501
+ * } );
10502
+ */
10503
+ "bSort": true,
10504
+
10505
+
10506
+ /**
10507
+ * Enable or display DataTables' ability to sort multiple columns at the
10508
+ * same time (activated by shift-click by the user).
10509
+ * @type boolean
10510
+ * @default true
10511
+ *
10512
+ * @dtopt Options
10513
+ * @name DataTable.defaults.orderMulti
10514
+ *
10515
+ * @example
10516
+ * // Disable multiple column sorting ability
10517
+ * $(document).ready( function () {
10518
+ * $('#example').dataTable( {
10519
+ * "orderMulti": false
10520
+ * } );
10521
+ * } );
10522
+ */
10523
+ "bSortMulti": true,
10524
+
10525
+
10526
+ /**
10527
+ * Allows control over whether DataTables should use the top (true) unique
10528
+ * cell that is found for a single column, or the bottom (false - default).
10529
+ * This is useful when using complex headers.
10530
+ * @type boolean
10531
+ * @default false
10532
+ *
10533
+ * @dtopt Options
10534
+ * @name DataTable.defaults.orderCellsTop
10535
+ *
10536
+ * @example
10537
+ * $(document).ready( function() {
10538
+ * $('#example').dataTable( {
10539
+ * "orderCellsTop": true
10540
+ * } );
10541
+ * } );
10542
+ */
10543
+ "bSortCellsTop": false,
10544
+
10545
+
10546
+ /**
10547
+ * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10548
+ * `sorting\_3` to the columns which are currently being sorted on. This is
10549
+ * presented as a feature switch as it can increase processing time (while
10550
+ * classes are removed and added) so for large data sets you might want to
10551
+ * turn this off.
10552
+ * @type boolean
10553
+ * @default true
10554
+ *
10555
+ * @dtopt Features
10556
+ * @name DataTable.defaults.orderClasses
10557
+ *
10558
+ * @example
10559
+ * $(document).ready( function () {
10560
+ * $('#example').dataTable( {
10561
+ * "orderClasses": false
10562
+ * } );
10563
+ * } );
10564
+ */
10565
+ "bSortClasses": true,
10566
+
10567
+
10568
+ /**
10569
+ * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10570
+ * used to save table display information such as pagination information,
10571
+ * display length, filtering and sorting. As such when the end user reloads
10572
+ * the page the display display will match what thy had previously set up.
10573
+ *
10574
+ * Due to the use of `localStorage` the default state saving is not supported
10575
+ * in IE6 or 7. If state saving is required in those browsers, use
10576
+ * `stateSaveCallback` to provide a storage solution such as cookies.
10577
+ * @type boolean
10578
+ * @default false
10579
+ *
10580
+ * @dtopt Features
10581
+ * @name DataTable.defaults.stateSave
10582
+ *
10583
+ * @example
10584
+ * $(document).ready( function () {
10585
+ * $('#example').dataTable( {
10586
+ * "stateSave": true
10587
+ * } );
10588
+ * } );
10589
+ */
10590
+ "bStateSave": false,
10591
+
10592
+
10593
+ /**
10594
+ * This function is called when a TR element is created (and all TD child
10595
+ * elements have been inserted), or registered if using a DOM source, allowing
10596
+ * manipulation of the TR element (adding classes etc).
10597
+ * @type function
10598
+ * @param {node} row "TR" element for the current row
10599
+ * @param {array} data Raw data array for this row
10600
+ * @param {int} dataIndex The index of this row in the internal aoData array
10601
+ *
10602
+ * @dtopt Callbacks
10603
+ * @name DataTable.defaults.createdRow
10604
+ *
10605
+ * @example
10606
+ * $(document).ready( function() {
10607
+ * $('#example').dataTable( {
10608
+ * "createdRow": function( row, data, dataIndex ) {
10609
+ * // Bold the grade for all 'A' grade browsers
10610
+ * if ( data[4] == "A" )
10611
+ * {
10612
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10613
+ * }
10614
+ * }
10615
+ * } );
10616
+ * } );
10617
+ */
10618
+ "fnCreatedRow": null,
10619
+
10620
+
10621
+ /**
10622
+ * This function is called on every 'draw' event, and allows you to
10623
+ * dynamically modify any aspect you want about the created DOM.
10624
+ * @type function
10625
+ * @param {object} settings DataTables settings object
10626
+ *
10627
+ * @dtopt Callbacks
10628
+ * @name DataTable.defaults.drawCallback
10629
+ *
10630
+ * @example
10631
+ * $(document).ready( function() {
10632
+ * $('#example').dataTable( {
10633
+ * "drawCallback": function( settings ) {
10634
+ * alert( 'DataTables has redrawn the table' );
10635
+ * }
10636
+ * } );
10637
+ * } );
10638
+ */
10639
+ "fnDrawCallback": null,
10640
+
10641
+
10642
+ /**
10643
+ * Identical to fnHeaderCallback() but for the table footer this function
10644
+ * allows you to modify the table footer on every 'draw' event.
10645
+ * @type function
10646
+ * @param {node} foot "TR" element for the footer
10647
+ * @param {array} data Full table data (as derived from the original HTML)
10648
+ * @param {int} start Index for the current display starting point in the
10649
+ * display array
10650
+ * @param {int} end Index for the current display ending point in the
10651
+ * display array
10652
+ * @param {array int} display Index array to translate the visual position
10653
+ * to the full data array
10654
+ *
10655
+ * @dtopt Callbacks
10656
+ * @name DataTable.defaults.footerCallback
10657
+ *
10658
+ * @example
10659
+ * $(document).ready( function() {
10660
+ * $('#example').dataTable( {
10661
+ * "footerCallback": function( tfoot, data, start, end, display ) {
10662
+ * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10663
+ * }
10664
+ * } );
10665
+ * } )
10666
+ */
10667
+ "fnFooterCallback": null,
10668
+
10669
+
10670
+ /**
10671
+ * When rendering large numbers in the information element for the table
10672
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10673
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
10674
+ * rendered as "1,000,000") to help readability for the end user. This
10675
+ * function will override the default method DataTables uses.
10676
+ * @type function
10677
+ * @member
10678
+ * @param {int} toFormat number to be formatted
10679
+ * @returns {string} formatted string for DataTables to show the number
10680
+ *
10681
+ * @dtopt Callbacks
10682
+ * @name DataTable.defaults.formatNumber
10683
+ *
10684
+ * @example
10685
+ * // Format a number using a single quote for the separator (note that
10686
+ * // this can also be done with the language.thousands option)
10687
+ * $(document).ready( function() {
10688
+ * $('#example').dataTable( {
10689
+ * "formatNumber": function ( toFormat ) {
10690
+ * return toFormat.toString().replace(
10691
+ * /\B(?=(\d{3})+(?!\d))/g, "'"
10692
+ * );
10693
+ * };
10694
+ * } );
10695
+ * } );
10696
+ */
10697
+ "fnFormatNumber": function ( toFormat ) {
10698
+ return toFormat.toString().replace(
10699
+ /\B(?=(\d{3})+(?!\d))/g,
10700
+ this.oLanguage.sThousands
10701
+ );
10702
+ },
10703
+
10704
+
10705
+ /**
10706
+ * This function is called on every 'draw' event, and allows you to
10707
+ * dynamically modify the header row. This can be used to calculate and
10708
+ * display useful information about the table.
10709
+ * @type function
10710
+ * @param {node} head "TR" element for the header
10711
+ * @param {array} data Full table data (as derived from the original HTML)
10712
+ * @param {int} start Index for the current display starting point in the
10713
+ * display array
10714
+ * @param {int} end Index for the current display ending point in the
10715
+ * display array
10716
+ * @param {array int} display Index array to translate the visual position
10717
+ * to the full data array
10718
+ *
10719
+ * @dtopt Callbacks
10720
+ * @name DataTable.defaults.headerCallback
10721
+ *
10722
+ * @example
10723
+ * $(document).ready( function() {
10724
+ * $('#example').dataTable( {
10725
+ * "fheaderCallback": function( head, data, start, end, display ) {
10726
+ * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10727
+ * }
10728
+ * } );
10729
+ * } )
10730
+ */
10731
+ "fnHeaderCallback": null,
10732
+
10733
+
10734
+ /**
10735
+ * The information element can be used to convey information about the current
10736
+ * state of the table. Although the internationalisation options presented by
10737
+ * DataTables are quite capable of dealing with most customisations, there may
10738
+ * be times where you wish to customise the string further. This callback
10739
+ * allows you to do exactly that.
10740
+ * @type function
10741
+ * @param {object} oSettings DataTables settings object
10742
+ * @param {int} start Starting position in data for the draw
10743
+ * @param {int} end End position in data for the draw
10744
+ * @param {int} max Total number of rows in the table (regardless of
10745
+ * filtering)
10746
+ * @param {int} total Total number of rows in the data set, after filtering
10747
+ * @param {string} pre The string that DataTables has formatted using it's
10748
+ * own rules
10749
+ * @returns {string} The string to be displayed in the information element.
10750
+ *
10751
+ * @dtopt Callbacks
10752
+ * @name DataTable.defaults.infoCallback
10753
+ *
10754
+ * @example
10755
+ * $('#example').dataTable( {
10756
+ * "infoCallback": function( settings, start, end, max, total, pre ) {
10757
+ * return start +" to "+ end;
10758
+ * }
10759
+ * } );
10760
+ */
10761
+ "fnInfoCallback": null,
10762
+
10763
+
10764
+ /**
10765
+ * Called when the table has been initialised. Normally DataTables will
10766
+ * initialise sequentially and there will be no need for this function,
10767
+ * however, this does not hold true when using external language information
10768
+ * since that is obtained using an async XHR call.
10769
+ * @type function
10770
+ * @param {object} settings DataTables settings object
10771
+ * @param {object} json The JSON object request from the server - only
10772
+ * present if client-side Ajax sourced data is used
10773
+ *
10774
+ * @dtopt Callbacks
10775
+ * @name DataTable.defaults.initComplete
10776
+ *
10777
+ * @example
10778
+ * $(document).ready( function() {
10779
+ * $('#example').dataTable( {
10780
+ * "initComplete": function(settings, json) {
10781
+ * alert( 'DataTables has finished its initialisation.' );
10782
+ * }
10783
+ * } );
10784
+ * } )
10785
+ */
10786
+ "fnInitComplete": null,
10787
+
10788
+
10789
+ /**
10790
+ * Called at the very start of each table draw and can be used to cancel the
10791
+ * draw by returning false, any other return (including undefined) results in
10792
+ * the full draw occurring).
10793
+ * @type function
10794
+ * @param {object} settings DataTables settings object
10795
+ * @returns {boolean} False will cancel the draw, anything else (including no
10796
+ * return) will allow it to complete.
10797
+ *
10798
+ * @dtopt Callbacks
10799
+ * @name DataTable.defaults.preDrawCallback
10800
+ *
10801
+ * @example
10802
+ * $(document).ready( function() {
10803
+ * $('#example').dataTable( {
10804
+ * "preDrawCallback": function( settings ) {
10805
+ * if ( $('#test').val() == 1 ) {
10806
+ * return false;
10807
+ * }
10808
+ * }
10809
+ * } );
10810
+ * } );
10811
+ */
10812
+ "fnPreDrawCallback": null,
10813
+
10814
+
10815
+ /**
10816
+ * This function allows you to 'post process' each row after it have been
10817
+ * generated for each table draw, but before it is rendered on screen. This
10818
+ * function might be used for setting the row class name etc.
10819
+ * @type function
10820
+ * @param {node} row "TR" element for the current row
10821
+ * @param {array} data Raw data array for this row
10822
+ * @param {int} displayIndex The display index for the current table draw
10823
+ * @param {int} displayIndexFull The index of the data in the full list of
10824
+ * rows (after filtering)
10825
+ *
10826
+ * @dtopt Callbacks
10827
+ * @name DataTable.defaults.rowCallback
10828
+ *
10829
+ * @example
10830
+ * $(document).ready( function() {
10831
+ * $('#example').dataTable( {
10832
+ * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10833
+ * // Bold the grade for all 'A' grade browsers
10834
+ * if ( data[4] == "A" ) {
10835
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10836
+ * }
10837
+ * }
10838
+ * } );
10839
+ * } );
10840
+ */
10841
+ "fnRowCallback": null,
10842
+
10843
+
10844
+ /**
10845
+ * __Deprecated__ The functionality provided by this parameter has now been
10846
+ * superseded by that provided through `ajax`, which should be used instead.
10847
+ *
10848
+ * This parameter allows you to override the default function which obtains
10849
+ * the data from the server so something more suitable for your application.
10850
+ * For example you could use POST data, or pull information from a Gears or
10851
+ * AIR database.
10852
+ * @type function
10853
+ * @member
10854
+ * @param {string} source HTTP source to obtain the data from (`ajax`)
10855
+ * @param {array} data A key/value pair object containing the data to send
10856
+ * to the server
10857
+ * @param {function} callback to be called on completion of the data get
10858
+ * process that will draw the data on the page.
10859
+ * @param {object} settings DataTables settings object
10860
+ *
10861
+ * @dtopt Callbacks
10862
+ * @dtopt Server-side
10863
+ * @name DataTable.defaults.serverData
10864
+ *
10865
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10866
+ */
10867
+ "fnServerData": null,
10868
+
10869
+
10870
+ /**
10871
+ * __Deprecated__ The functionality provided by this parameter has now been
10872
+ * superseded by that provided through `ajax`, which should be used instead.
10873
+ *
10874
+ * It is often useful to send extra data to the server when making an Ajax
10875
+ * request - for example custom filtering information, and this callback
10876
+ * function makes it trivial to send extra information to the server. The
10877
+ * passed in parameter is the data set that has been constructed by
10878
+ * DataTables, and you can add to this or modify it as you require.
10879
+ * @type function
10880
+ * @param {array} data Data array (array of objects which are name/value
10881
+ * pairs) that has been constructed by DataTables and will be sent to the
10882
+ * server. In the case of Ajax sourced data with server-side processing
10883
+ * this will be an empty array, for server-side processing there will be a
10884
+ * significant number of parameters!
10885
+ * @returns {undefined} Ensure that you modify the data array passed in,
10886
+ * as this is passed by reference.
10887
+ *
10888
+ * @dtopt Callbacks
10889
+ * @dtopt Server-side
10890
+ * @name DataTable.defaults.serverParams
10891
+ *
10892
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10893
+ */
10894
+ "fnServerParams": null,
10895
+
10896
+
10897
+ /**
10898
+ * Load the table state. With this function you can define from where, and how, the
10899
+ * state of a table is loaded. By default DataTables will load from `localStorage`
10900
+ * but you might wish to use a server-side database or cookies.
10901
+ * @type function
10902
+ * @member
10903
+ * @param {object} settings DataTables settings object
10904
+ * @param {object} callback Callback that can be executed when done. It
10905
+ * should be passed the loaded state object.
10906
+ * @return {object} The DataTables state object to be loaded
10907
+ *
10908
+ * @dtopt Callbacks
10909
+ * @name DataTable.defaults.stateLoadCallback
10910
+ *
10911
+ * @example
10912
+ * $(document).ready( function() {
10913
+ * $('#example').dataTable( {
10914
+ * "stateSave": true,
10915
+ * "stateLoadCallback": function (settings, callback) {
10916
+ * $.ajax( {
10917
+ * "url": "/state_load",
10918
+ * "dataType": "json",
10919
+ * "success": function (json) {
10920
+ * callback( json );
10921
+ * }
10922
+ * } );
10923
+ * }
10924
+ * } );
10925
+ * } );
10926
+ */
10927
+ "fnStateLoadCallback": function ( settings ) {
10928
+ try {
10929
+ return JSON.parse(
10930
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10931
+ 'DataTables_'+settings.sInstance+'_'+location.pathname
10932
+ )
10933
+ );
10934
+ } catch (e) {}
10935
+ },
10936
+
10937
+
10938
+ /**
10939
+ * Callback which allows modification of the saved state prior to loading that state.
10940
+ * This callback is called when the table is loading state from the stored data, but
10941
+ * prior to the settings object being modified by the saved state. Note that for
10942
+ * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10943
+ * a plug-in.
10944
+ * @type function
10945
+ * @param {object} settings DataTables settings object
10946
+ * @param {object} data The state object that is to be loaded
10947
+ *
10948
+ * @dtopt Callbacks
10949
+ * @name DataTable.defaults.stateLoadParams
10950
+ *
10951
+ * @example
10952
+ * // Remove a saved filter, so filtering is never loaded
10953
+ * $(document).ready( function() {
10954
+ * $('#example').dataTable( {
10955
+ * "stateSave": true,
10956
+ * "stateLoadParams": function (settings, data) {
10957
+ * data.oSearch.sSearch = "";
10958
+ * }
10959
+ * } );
10960
+ * } );
10961
+ *
10962
+ * @example
10963
+ * // Disallow state loading by returning false
10964
+ * $(document).ready( function() {
10965
+ * $('#example').dataTable( {
10966
+ * "stateSave": true,
10967
+ * "stateLoadParams": function (settings, data) {
10968
+ * return false;
10969
+ * }
10970
+ * } );
10971
+ * } );
10972
+ */
10973
+ "fnStateLoadParams": null,
10974
+
10975
+
10976
+ /**
10977
+ * Callback that is called when the state has been loaded from the state saving method
10978
+ * and the DataTables settings object has been modified as a result of the loaded state.
10979
+ * @type function
10980
+ * @param {object} settings DataTables settings object
10981
+ * @param {object} data The state object that was loaded
10982
+ *
10983
+ * @dtopt Callbacks
10984
+ * @name DataTable.defaults.stateLoaded
10985
+ *
10986
+ * @example
10987
+ * // Show an alert with the filtering value that was saved
10988
+ * $(document).ready( function() {
10989
+ * $('#example').dataTable( {
10990
+ * "stateSave": true,
10991
+ * "stateLoaded": function (settings, data) {
10992
+ * alert( 'Saved filter was: '+data.oSearch.sSearch );
10993
+ * }
10994
+ * } );
10995
+ * } );
10996
+ */
10997
+ "fnStateLoaded": null,
10998
+
10999
+
11000
+ /**
11001
+ * Save the table state. This function allows you to define where and how the state
11002
+ * information for the table is stored By default DataTables will use `localStorage`
11003
+ * but you might wish to use a server-side database or cookies.
11004
+ * @type function
11005
+ * @member
11006
+ * @param {object} settings DataTables settings object
11007
+ * @param {object} data The state object to be saved
11008
+ *
11009
+ * @dtopt Callbacks
11010
+ * @name DataTable.defaults.stateSaveCallback
11011
+ *
11012
+ * @example
11013
+ * $(document).ready( function() {
11014
+ * $('#example').dataTable( {
11015
+ * "stateSave": true,
11016
+ * "stateSaveCallback": function (settings, data) {
11017
+ * // Send an Ajax request to the server with the state object
11018
+ * $.ajax( {
11019
+ * "url": "/state_save",
11020
+ * "data": data,
11021
+ * "dataType": "json",
11022
+ * "method": "POST"
11023
+ * "success": function () {}
11024
+ * } );
11025
+ * }
11026
+ * } );
11027
+ * } );
11028
+ */
11029
+ "fnStateSaveCallback": function ( settings, data ) {
11030
+ try {
11031
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
11032
+ 'DataTables_'+settings.sInstance+'_'+location.pathname,
11033
+ JSON.stringify( data )
11034
+ );
11035
+ } catch (e) {}
11036
+ },
11037
+
11038
+
11039
+ /**
11040
+ * Callback which allows modification of the state to be saved. Called when the table
11041
+ * has changed state a new state save is required. This method allows modification of
11042
+ * the state saving object prior to actually doing the save, including addition or
11043
+ * other state properties or modification. Note that for plug-in authors, you should
11044
+ * use the `stateSaveParams` event to save parameters for a plug-in.
11045
+ * @type function
11046
+ * @param {object} settings DataTables settings object
11047
+ * @param {object} data The state object to be saved
11048
+ *
11049
+ * @dtopt Callbacks
11050
+ * @name DataTable.defaults.stateSaveParams
11051
+ *
11052
+ * @example
11053
+ * // Remove a saved filter, so filtering is never saved
11054
+ * $(document).ready( function() {
11055
+ * $('#example').dataTable( {
11056
+ * "stateSave": true,
11057
+ * "stateSaveParams": function (settings, data) {
11058
+ * data.oSearch.sSearch = "";
11059
+ * }
11060
+ * } );
11061
+ * } );
11062
+ */
11063
+ "fnStateSaveParams": null,
11064
+
11065
+
11066
+ /**
11067
+ * Duration for which the saved state information is considered valid. After this period
11068
+ * has elapsed the state will be returned to the default.
11069
+ * Value is given in seconds.
11070
+ * @type int
11071
+ * @default 7200 <i>(2 hours)</i>
11072
+ *
11073
+ * @dtopt Options
11074
+ * @name DataTable.defaults.stateDuration
11075
+ *
11076
+ * @example
11077
+ * $(document).ready( function() {
11078
+ * $('#example').dataTable( {
11079
+ * "stateDuration": 60*60*24; // 1 day
11080
+ * } );
11081
+ * } )
11082
+ */
11083
+ "iStateDuration": 7200,
11084
+
11085
+
11086
+ /**
11087
+ * When enabled DataTables will not make a request to the server for the first
11088
+ * page draw - rather it will use the data already on the page (no sorting etc
11089
+ * will be applied to it), thus saving on an XHR at load time. `deferLoading`
11090
+ * is used to indicate that deferred loading is required, but it is also used
11091
+ * to tell DataTables how many records there are in the full table (allowing
11092
+ * the information element and pagination to be displayed correctly). In the case
11093
+ * where a filtering is applied to the table on initial load, this can be
11094
+ * indicated by giving the parameter as an array, where the first element is
11095
+ * the number of records available after filtering and the second element is the
11096
+ * number of records without filtering (allowing the table information element
11097
+ * to be shown correctly).
11098
+ * @type int | array
11099
+ * @default null
11100
+ *
11101
+ * @dtopt Options
11102
+ * @name DataTable.defaults.deferLoading
11103
+ *
11104
+ * @example
11105
+ * // 57 records available in the table, no filtering applied
11106
+ * $(document).ready( function() {
11107
+ * $('#example').dataTable( {
11108
+ * "serverSide": true,
11109
+ * "ajax": "scripts/server_processing.php",
11110
+ * "deferLoading": 57
11111
+ * } );
11112
+ * } );
11113
+ *
11114
+ * @example
11115
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
11116
+ * $(document).ready( function() {
11117
+ * $('#example').dataTable( {
11118
+ * "serverSide": true,
11119
+ * "ajax": "scripts/server_processing.php",
11120
+ * "deferLoading": [ 57, 100 ],
11121
+ * "search": {
11122
+ * "search": "my_filter"
11123
+ * }
11124
+ * } );
11125
+ * } );
11126
+ */
11127
+ "iDeferLoading": null,
11128
+
11129
+
11130
+ /**
11131
+ * Number of rows to display on a single page when using pagination. If
11132
+ * feature enabled (`lengthChange`) then the end user will be able to override
11133
+ * this to a custom setting using a pop-up menu.
11134
+ * @type int
11135
+ * @default 10
11136
+ *
11137
+ * @dtopt Options
11138
+ * @name DataTable.defaults.pageLength
11139
+ *
11140
+ * @example
11141
+ * $(document).ready( function() {
11142
+ * $('#example').dataTable( {
11143
+ * "pageLength": 50
11144
+ * } );
11145
+ * } )
11146
+ */
11147
+ "iDisplayLength": 10,
11148
+
11149
+
11150
+ /**
11151
+ * Define the starting point for data display when using DataTables with
11152
+ * pagination. Note that this parameter is the number of records, rather than
11153
+ * the page number, so if you have 10 records per page and want to start on
11154
+ * the third page, it should be "20".
11155
+ * @type int
11156
+ * @default 0
11157
+ *
11158
+ * @dtopt Options
11159
+ * @name DataTable.defaults.displayStart
11160
+ *
11161
+ * @example
11162
+ * $(document).ready( function() {
11163
+ * $('#example').dataTable( {
11164
+ * "displayStart": 20
11165
+ * } );
11166
+ * } )
11167
+ */
11168
+ "iDisplayStart": 0,
11169
+
11170
+
11171
+ /**
11172
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
11173
+ * and filtering) by adding a `tabindex` attribute to the required elements. This
11174
+ * allows you to tab through the controls and press the enter key to activate them.
11175
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
11176
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
11177
+ * disable built-in keyboard navigation.
11178
+ * @type int
11179
+ * @default 0
11180
+ *
11181
+ * @dtopt Options
11182
+ * @name DataTable.defaults.tabIndex
11183
+ *
11184
+ * @example
11185
+ * $(document).ready( function() {
11186
+ * $('#example').dataTable( {
11187
+ * "tabIndex": 1
11188
+ * } );
11189
+ * } );
11190
+ */
11191
+ "iTabIndex": 0,
11192
+
11193
+
11194
+ /**
11195
+ * Classes that DataTables assigns to the various components and features
11196
+ * that it adds to the HTML table. This allows classes to be configured
11197
+ * during initialisation in addition to through the static
11198
+ * {@link DataTable.ext.oStdClasses} object).
11199
+ * @namespace
11200
+ * @name DataTable.defaults.classes
11201
+ */
11202
+ "oClasses": {},
11203
+
11204
+
11205
+ /**
11206
+ * All strings that DataTables uses in the user interface that it creates
11207
+ * are defined in this object, allowing you to modified them individually or
11208
+ * completely replace them all as required.
11209
+ * @namespace
11210
+ * @name DataTable.defaults.language
11211
+ */
11212
+ "oLanguage": {
11213
+ /**
11214
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
11215
+ * actually visible on the page, but will be read by screenreaders, and thus
11216
+ * must be internationalised as well).
11217
+ * @namespace
11218
+ * @name DataTable.defaults.language.aria
11219
+ */
11220
+ "oAria": {
11221
+ /**
11222
+ * ARIA label that is added to the table headers when the column may be
11223
+ * sorted ascending by activing the column (click or return when focused).
11224
+ * Note that the column header is prefixed to this string.
11225
+ * @type string
11226
+ * @default : activate to sort column ascending
11227
+ *
11228
+ * @dtopt Language
11229
+ * @name DataTable.defaults.language.aria.sortAscending
11230
+ *
11231
+ * @example
11232
+ * $(document).ready( function() {
11233
+ * $('#example').dataTable( {
11234
+ * "language": {
11235
+ * "aria": {
11236
+ * "sortAscending": " - click/return to sort ascending"
11237
+ * }
11238
+ * }
11239
+ * } );
11240
+ * } );
11241
+ */
11242
+ "sSortAscending": ": activate to sort column ascending",
11243
+
11244
+ /**
11245
+ * ARIA label that is added to the table headers when the column may be
11246
+ * sorted descending by activing the column (click or return when focused).
11247
+ * Note that the column header is prefixed to this string.
11248
+ * @type string
11249
+ * @default : activate to sort column ascending
11250
+ *
11251
+ * @dtopt Language
11252
+ * @name DataTable.defaults.language.aria.sortDescending
11253
+ *
11254
+ * @example
11255
+ * $(document).ready( function() {
11256
+ * $('#example').dataTable( {
11257
+ * "language": {
11258
+ * "aria": {
11259
+ * "sortDescending": " - click/return to sort descending"
11260
+ * }
11261
+ * }
11262
+ * } );
11263
+ * } );
11264
+ */
11265
+ "sSortDescending": ": activate to sort column descending"
11266
+ },
11267
+
11268
+ /**
11269
+ * Pagination string used by DataTables for the built-in pagination
11270
+ * control types.
11271
+ * @namespace
11272
+ * @name DataTable.defaults.language.paginate
11273
+ */
11274
+ "oPaginate": {
11275
+ /**
11276
+ * Text to use when using the 'full_numbers' type of pagination for the
11277
+ * button to take the user to the first page.
11278
+ * @type string
11279
+ * @default First
11280
+ *
11281
+ * @dtopt Language
11282
+ * @name DataTable.defaults.language.paginate.first
11283
+ *
11284
+ * @example
11285
+ * $(document).ready( function() {
11286
+ * $('#example').dataTable( {
11287
+ * "language": {
11288
+ * "paginate": {
11289
+ * "first": "First page"
11290
+ * }
11291
+ * }
11292
+ * } );
11293
+ * } );
11294
+ */
11295
+ "sFirst": "First",
11296
+
11297
+
11298
+ /**
11299
+ * Text to use when using the 'full_numbers' type of pagination for the
11300
+ * button to take the user to the last page.
11301
+ * @type string
11302
+ * @default Last
11303
+ *
11304
+ * @dtopt Language
11305
+ * @name DataTable.defaults.language.paginate.last
11306
+ *
11307
+ * @example
11308
+ * $(document).ready( function() {
11309
+ * $('#example').dataTable( {
11310
+ * "language": {
11311
+ * "paginate": {
11312
+ * "last": "Last page"
11313
+ * }
11314
+ * }
11315
+ * } );
11316
+ * } );
11317
+ */
11318
+ "sLast": "Last",
11319
+
11320
+
11321
+ /**
11322
+ * Text to use for the 'next' pagination button (to take the user to the
11323
+ * next page).
11324
+ * @type string
11325
+ * @default Next
11326
+ *
11327
+ * @dtopt Language
11328
+ * @name DataTable.defaults.language.paginate.next
11329
+ *
11330
+ * @example
11331
+ * $(document).ready( function() {
11332
+ * $('#example').dataTable( {
11333
+ * "language": {
11334
+ * "paginate": {
11335
+ * "next": "Next page"
11336
+ * }
11337
+ * }
11338
+ * } );
11339
+ * } );
11340
+ */
11341
+ "sNext": "Next",
11342
+
11343
+
11344
+ /**
11345
+ * Text to use for the 'previous' pagination button (to take the user to
11346
+ * the previous page).
11347
+ * @type string
11348
+ * @default Previous
11349
+ *
11350
+ * @dtopt Language
11351
+ * @name DataTable.defaults.language.paginate.previous
11352
+ *
11353
+ * @example
11354
+ * $(document).ready( function() {
11355
+ * $('#example').dataTable( {
11356
+ * "language": {
11357
+ * "paginate": {
11358
+ * "previous": "Previous page"
11359
+ * }
11360
+ * }
11361
+ * } );
11362
+ * } );
11363
+ */
11364
+ "sPrevious": "Previous"
11365
+ },
11366
+
11367
+ /**
11368
+ * This string is shown in preference to `zeroRecords` when the table is
11369
+ * empty of data (regardless of filtering). Note that this is an optional
11370
+ * parameter - if it is not given, the value of `zeroRecords` will be used
11371
+ * instead (either the default or given value).
11372
+ * @type string
11373
+ * @default No data available in table
11374
+ *
11375
+ * @dtopt Language
11376
+ * @name DataTable.defaults.language.emptyTable
11377
+ *
11378
+ * @example
11379
+ * $(document).ready( function() {
11380
+ * $('#example').dataTable( {
11381
+ * "language": {
11382
+ * "emptyTable": "No data available in table"
11383
+ * }
11384
+ * } );
11385
+ * } );
11386
+ */
11387
+ "sEmptyTable": "No data available in table",
11388
+
11389
+
11390
+ /**
11391
+ * This string gives information to the end user about the information
11392
+ * that is current on display on the page. The following tokens can be
11393
+ * used in the string and will be dynamically replaced as the table
11394
+ * display updates. This tokens can be placed anywhere in the string, or
11395
+ * removed as needed by the language requires:
11396
+ *
11397
+ * * `\_START\_` - Display index of the first record on the current page
11398
+ * * `\_END\_` - Display index of the last record on the current page
11399
+ * * `\_TOTAL\_` - Number of records in the table after filtering
11400
+ * * `\_MAX\_` - Number of records in the table without filtering
11401
+ * * `\_PAGE\_` - Current page number
11402
+ * * `\_PAGES\_` - Total number of pages of data in the table
11403
+ *
11404
+ * @type string
11405
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
11406
+ *
11407
+ * @dtopt Language
11408
+ * @name DataTable.defaults.language.info
11409
+ *
11410
+ * @example
11411
+ * $(document).ready( function() {
11412
+ * $('#example').dataTable( {
11413
+ * "language": {
11414
+ * "info": "Showing page _PAGE_ of _PAGES_"
11415
+ * }
11416
+ * } );
11417
+ * } );
11418
+ */
11419
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11420
+
11421
+
11422
+ /**
11423
+ * Display information string for when the table is empty. Typically the
11424
+ * format of this string should match `info`.
11425
+ * @type string
11426
+ * @default Showing 0 to 0 of 0 entries
11427
+ *
11428
+ * @dtopt Language
11429
+ * @name DataTable.defaults.language.infoEmpty
11430
+ *
11431
+ * @example
11432
+ * $(document).ready( function() {
11433
+ * $('#example').dataTable( {
11434
+ * "language": {
11435
+ * "infoEmpty": "No entries to show"
11436
+ * }
11437
+ * } );
11438
+ * } );
11439
+ */
11440
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11441
+
11442
+
11443
+ /**
11444
+ * When a user filters the information in a table, this string is appended
11445
+ * to the information (`info`) to give an idea of how strong the filtering
11446
+ * is. The variable _MAX_ is dynamically updated.
11447
+ * @type string
11448
+ * @default (filtered from _MAX_ total entries)
11449
+ *
11450
+ * @dtopt Language
11451
+ * @name DataTable.defaults.language.infoFiltered
11452
+ *
11453
+ * @example
11454
+ * $(document).ready( function() {
11455
+ * $('#example').dataTable( {
11456
+ * "language": {
11457
+ * "infoFiltered": " - filtering from _MAX_ records"
11458
+ * }
11459
+ * } );
11460
+ * } );
11461
+ */
11462
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
11463
+
11464
+
11465
+ /**
11466
+ * If can be useful to append extra information to the info string at times,
11467
+ * and this variable does exactly that. This information will be appended to
11468
+ * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11469
+ * being used) at all times.
11470
+ * @type string
11471
+ * @default <i>Empty string</i>
11472
+ *
11473
+ * @dtopt Language
11474
+ * @name DataTable.defaults.language.infoPostFix
11475
+ *
11476
+ * @example
11477
+ * $(document).ready( function() {
11478
+ * $('#example').dataTable( {
11479
+ * "language": {
11480
+ * "infoPostFix": "All records shown are derived from real information."
11481
+ * }
11482
+ * } );
11483
+ * } );
11484
+ */
11485
+ "sInfoPostFix": "",
11486
+
11487
+
11488
+ /**
11489
+ * This decimal place operator is a little different from the other
11490
+ * language options since DataTables doesn't output floating point
11491
+ * numbers, so it won't ever use this for display of a number. Rather,
11492
+ * what this parameter does is modify the sort methods of the table so
11493
+ * that numbers which are in a format which has a character other than
11494
+ * a period (`.`) as a decimal place will be sorted numerically.
11495
+ *
11496
+ * Note that numbers with different decimal places cannot be shown in
11497
+ * the same table and still be sortable, the table must be consistent.
11498
+ * However, multiple different tables on the page can use different
11499
+ * decimal place characters.
11500
+ * @type string
11501
+ * @default
11502
+ *
11503
+ * @dtopt Language
11504
+ * @name DataTable.defaults.language.decimal
11505
+ *
11506
+ * @example
11507
+ * $(document).ready( function() {
11508
+ * $('#example').dataTable( {
11509
+ * "language": {
11510
+ * "decimal": ","
11511
+ * "thousands": "."
11512
+ * }
11513
+ * } );
11514
+ * } );
11515
+ */
11516
+ "sDecimal": "",
11517
+
11518
+
11519
+ /**
11520
+ * DataTables has a build in number formatter (`formatNumber`) which is
11521
+ * used to format large numbers that are used in the table information.
11522
+ * By default a comma is used, but this can be trivially changed to any
11523
+ * character you wish with this parameter.
11524
+ * @type string
11525
+ * @default ,
11526
+ *
11527
+ * @dtopt Language
11528
+ * @name DataTable.defaults.language.thousands
11529
+ *
11530
+ * @example
11531
+ * $(document).ready( function() {
11532
+ * $('#example').dataTable( {
11533
+ * "language": {
11534
+ * "thousands": "'"
11535
+ * }
11536
+ * } );
11537
+ * } );
11538
+ */
11539
+ "sThousands": ",",
11540
+
11541
+
11542
+ /**
11543
+ * Detail the action that will be taken when the drop down menu for the
11544
+ * pagination length option is changed. The '_MENU_' variable is replaced
11545
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
11546
+ * with a custom select box if required.
11547
+ * @type string
11548
+ * @default Show _MENU_ entries
11549
+ *
11550
+ * @dtopt Language
11551
+ * @name DataTable.defaults.language.lengthMenu
11552
+ *
11553
+ * @example
11554
+ * // Language change only
11555
+ * $(document).ready( function() {
11556
+ * $('#example').dataTable( {
11557
+ * "language": {
11558
+ * "lengthMenu": "Display _MENU_ records"
11559
+ * }
11560
+ * } );
11561
+ * } );
11562
+ *
11563
+ * @example
11564
+ * // Language and options change
11565
+ * $(document).ready( function() {
11566
+ * $('#example').dataTable( {
11567
+ * "language": {
11568
+ * "lengthMenu": 'Display <select>'+
11569
+ * '<option value="10">10</option>'+
11570
+ * '<option value="20">20</option>'+
11571
+ * '<option value="30">30</option>'+
11572
+ * '<option value="40">40</option>'+
11573
+ * '<option value="50">50</option>'+
11574
+ * '<option value="-1">All</option>'+
11575
+ * '</select> records'
11576
+ * }
11577
+ * } );
11578
+ * } );
11579
+ */
11580
+ "sLengthMenu": "Show _MENU_ entries",
11581
+
11582
+
11583
+ /**
11584
+ * When using Ajax sourced data and during the first draw when DataTables is
11585
+ * gathering the data, this message is shown in an empty row in the table to
11586
+ * indicate to the end user the the data is being loaded. Note that this
11587
+ * parameter is not used when loading data by server-side processing, just
11588
+ * Ajax sourced data with client-side processing.
11589
+ * @type string
11590
+ * @default Loading...
11591
+ *
11592
+ * @dtopt Language
11593
+ * @name DataTable.defaults.language.loadingRecords
11594
+ *
11595
+ * @example
11596
+ * $(document).ready( function() {
11597
+ * $('#example').dataTable( {
11598
+ * "language": {
11599
+ * "loadingRecords": "Please wait - loading..."
11600
+ * }
11601
+ * } );
11602
+ * } );
11603
+ */
11604
+ "sLoadingRecords": "Loading...",
11605
+
11606
+
11607
+ /**
11608
+ * Text which is displayed when the table is processing a user action
11609
+ * (usually a sort command or similar).
11610
+ * @type string
11611
+ * @default Processing...
11612
+ *
11613
+ * @dtopt Language
11614
+ * @name DataTable.defaults.language.processing
11615
+ *
11616
+ * @example
11617
+ * $(document).ready( function() {
11618
+ * $('#example').dataTable( {
11619
+ * "language": {
11620
+ * "processing": "DataTables is currently busy"
11621
+ * }
11622
+ * } );
11623
+ * } );
11624
+ */
11625
+ "sProcessing": "Processing...",
11626
+
11627
+
11628
+ /**
11629
+ * Details the actions that will be taken when the user types into the
11630
+ * filtering input text box. The variable "_INPUT_", if used in the string,
11631
+ * is replaced with the HTML text box for the filtering input allowing
11632
+ * control over where it appears in the string. If "_INPUT_" is not given
11633
+ * then the input box is appended to the string automatically.
11634
+ * @type string
11635
+ * @default Search:
11636
+ *
11637
+ * @dtopt Language
11638
+ * @name DataTable.defaults.language.search
11639
+ *
11640
+ * @example
11641
+ * // Input text box will be appended at the end automatically
11642
+ * $(document).ready( function() {
11643
+ * $('#example').dataTable( {
11644
+ * "language": {
11645
+ * "search": "Filter records:"
11646
+ * }
11647
+ * } );
11648
+ * } );
11649
+ *
11650
+ * @example
11651
+ * // Specify where the filter should appear
11652
+ * $(document).ready( function() {
11653
+ * $('#example').dataTable( {
11654
+ * "language": {
11655
+ * "search": "Apply filter _INPUT_ to table"
11656
+ * }
11657
+ * } );
11658
+ * } );
11659
+ */
11660
+ "sSearch": "Search:",
11661
+
11662
+
11663
+ /**
11664
+ * Assign a `placeholder` attribute to the search `input` element
11665
+ * @type string
11666
+ * @default
11667
+ *
11668
+ * @dtopt Language
11669
+ * @name DataTable.defaults.language.searchPlaceholder
11670
+ */
11671
+ "sSearchPlaceholder": "",
11672
+
11673
+
11674
+ /**
11675
+ * All of the language information can be stored in a file on the
11676
+ * server-side, which DataTables will look up if this parameter is passed.
11677
+ * It must store the URL of the language file, which is in a JSON format,
11678
+ * and the object has the same properties as the oLanguage object in the
11679
+ * initialiser object (i.e. the above parameters). Please refer to one of
11680
+ * the example language files to see how this works in action.
11681
+ * @type string
11682
+ * @default <i>Empty string - i.e. disabled</i>
11683
+ *
11684
+ * @dtopt Language
11685
+ * @name DataTable.defaults.language.url
11686
+ *
11687
+ * @example
11688
+ * $(document).ready( function() {
11689
+ * $('#example').dataTable( {
11690
+ * "language": {
11691
+ * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11692
+ * }
11693
+ * } );
11694
+ * } );
11695
+ */
11696
+ "sUrl": "",
11697
+
11698
+
11699
+ /**
11700
+ * Text shown inside the table records when the is no information to be
11701
+ * displayed after filtering. `emptyTable` is shown when there is simply no
11702
+ * information in the table at all (regardless of filtering).
11703
+ * @type string
11704
+ * @default No matching records found
11705
+ *
11706
+ * @dtopt Language
11707
+ * @name DataTable.defaults.language.zeroRecords
11708
+ *
11709
+ * @example
11710
+ * $(document).ready( function() {
11711
+ * $('#example').dataTable( {
11712
+ * "language": {
11713
+ * "zeroRecords": "No records to display"
11714
+ * }
11715
+ * } );
11716
+ * } );
11717
+ */
11718
+ "sZeroRecords": "No matching records found"
11719
+ },
11720
+
11721
+
11722
+ /**
11723
+ * This parameter allows you to have define the global filtering state at
11724
+ * initialisation time. As an object the `search` parameter must be
11725
+ * defined, but all other parameters are optional. When `regex` is true,
11726
+ * the search string will be treated as a regular expression, when false
11727
+ * (default) it will be treated as a straight string. When `smart`
11728
+ * DataTables will use it's smart filtering methods (to word match at
11729
+ * any point in the data), when false this will not be done.
11730
+ * @namespace
11731
+ * @extends DataTable.models.oSearch
11732
+ *
11733
+ * @dtopt Options
11734
+ * @name DataTable.defaults.search
11735
+ *
11736
+ * @example
11737
+ * $(document).ready( function() {
11738
+ * $('#example').dataTable( {
11739
+ * "search": {"search": "Initial search"}
11740
+ * } );
11741
+ * } )
11742
+ */
11743
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
11744
+
11745
+
11746
+ /**
11747
+ * __Deprecated__ The functionality provided by this parameter has now been
11748
+ * superseded by that provided through `ajax`, which should be used instead.
11749
+ *
11750
+ * By default DataTables will look for the property `data` (or `aaData` for
11751
+ * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11752
+ * source or for server-side processing - this parameter allows that
11753
+ * property to be changed. You can use Javascript dotted object notation to
11754
+ * get a data source for multiple levels of nesting.
11755
+ * @type string
11756
+ * @default data
11757
+ *
11758
+ * @dtopt Options
11759
+ * @dtopt Server-side
11760
+ * @name DataTable.defaults.ajaxDataProp
11761
+ *
11762
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11763
+ */
11764
+ "sAjaxDataProp": "data",
11765
+
11766
+
11767
+ /**
11768
+ * __Deprecated__ The functionality provided by this parameter has now been
11769
+ * superseded by that provided through `ajax`, which should be used instead.
11770
+ *
11771
+ * You can instruct DataTables to load data from an external
11772
+ * source using this parameter (use aData if you want to pass data in you
11773
+ * already have). Simply provide a url a JSON object can be obtained from.
11774
+ * @type string
11775
+ * @default null
11776
+ *
11777
+ * @dtopt Options
11778
+ * @dtopt Server-side
11779
+ * @name DataTable.defaults.ajaxSource
11780
+ *
11781
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11782
+ */
11783
+ "sAjaxSource": null,
11784
+
11785
+
11786
+ /**
11787
+ * This initialisation variable allows you to specify exactly where in the
11788
+ * DOM you want DataTables to inject the various controls it adds to the page
11789
+ * (for example you might want the pagination controls at the top of the
11790
+ * table). DIV elements (with or without a custom class) can also be added to
11791
+ * aid styling. The follow syntax is used:
11792
+ * <ul>
11793
+ * <li>The following options are allowed:
11794
+ * <ul>
11795
+ * <li>'l' - Length changing</li>
11796
+ * <li>'f' - Filtering input</li>
11797
+ * <li>'t' - The table!</li>
11798
+ * <li>'i' - Information</li>
11799
+ * <li>'p' - Pagination</li>
11800
+ * <li>'r' - pRocessing</li>
11801
+ * </ul>
11802
+ * </li>
11803
+ * <li>The following constants are allowed:
11804
+ * <ul>
11805
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11806
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11807
+ * </ul>
11808
+ * </li>
11809
+ * <li>The following syntax is expected:
11810
+ * <ul>
11811
+ * <li>'&lt;' and '&gt;' - div elements</li>
11812
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
11813
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11814
+ * </ul>
11815
+ * </li>
11816
+ * <li>Examples:
11817
+ * <ul>
11818
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
11819
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11820
+ * </ul>
11821
+ * </li>
11822
+ * </ul>
11823
+ * @type string
11824
+ * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11825
+ * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11826
+ *
11827
+ * @dtopt Options
11828
+ * @name DataTable.defaults.dom
11829
+ *
11830
+ * @example
11831
+ * $(document).ready( function() {
11832
+ * $('#example').dataTable( {
11833
+ * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11834
+ * } );
11835
+ * } );
11836
+ */
11837
+ "sDom": "lfrtip",
11838
+
11839
+
11840
+ /**
11841
+ * Search delay option. This will throttle full table searches that use the
11842
+ * DataTables provided search input element (it does not effect calls to
11843
+ * `dt-api search()`, providing a delay before the search is made.
11844
+ * @type integer
11845
+ * @default 0
11846
+ *
11847
+ * @dtopt Options
11848
+ * @name DataTable.defaults.searchDelay
11849
+ *
11850
+ * @example
11851
+ * $(document).ready( function() {
11852
+ * $('#example').dataTable( {
11853
+ * "searchDelay": 200
11854
+ * } );
11855
+ * } )
11856
+ */
11857
+ "searchDelay": null,
11858
+
11859
+
11860
+ /**
11861
+ * DataTables features six different built-in options for the buttons to
11862
+ * display for pagination control:
11863
+ *
11864
+ * * `numbers` - Page number buttons only
11865
+ * * `simple` - 'Previous' and 'Next' buttons only
11866
+ * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11867
+ * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11868
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
11869
+ * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
11870
+ *
11871
+ * Further methods can be added using {@link DataTable.ext.oPagination}.
11872
+ * @type string
11873
+ * @default simple_numbers
11874
+ *
11875
+ * @dtopt Options
11876
+ * @name DataTable.defaults.pagingType
11877
+ *
11878
+ * @example
11879
+ * $(document).ready( function() {
11880
+ * $('#example').dataTable( {
11881
+ * "pagingType": "full_numbers"
11882
+ * } );
11883
+ * } )
11884
+ */
11885
+ "sPaginationType": "simple_numbers",
11886
+
11887
+
11888
+ /**
11889
+ * Enable horizontal scrolling. When a table is too wide to fit into a
11890
+ * certain layout, or you have a large number of columns in the table, you
11891
+ * can enable x-scrolling to show the table in a viewport, which can be
11892
+ * scrolled. This property can be `true` which will allow the table to
11893
+ * scroll horizontally when needed, or any CSS unit, or a number (in which
11894
+ * case it will be treated as a pixel measurement). Setting as simply `true`
11895
+ * is recommended.
11896
+ * @type boolean|string
11897
+ * @default <i>blank string - i.e. disabled</i>
11898
+ *
11899
+ * @dtopt Features
11900
+ * @name DataTable.defaults.scrollX
11901
+ *
11902
+ * @example
11903
+ * $(document).ready( function() {
11904
+ * $('#example').dataTable( {
11905
+ * "scrollX": true,
11906
+ * "scrollCollapse": true
11907
+ * } );
11908
+ * } );
11909
+ */
11910
+ "sScrollX": "",
11911
+
11912
+
11913
+ /**
11914
+ * This property can be used to force a DataTable to use more width than it
11915
+ * might otherwise do when x-scrolling is enabled. For example if you have a
11916
+ * table which requires to be well spaced, this parameter is useful for
11917
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
11918
+ * any CSS unit, or a number (in which case it will be treated as a pixel
11919
+ * measurement).
11920
+ * @type string
11921
+ * @default <i>blank string - i.e. disabled</i>
11922
+ *
11923
+ * @dtopt Options
11924
+ * @name DataTable.defaults.scrollXInner
11925
+ *
11926
+ * @example
11927
+ * $(document).ready( function() {
11928
+ * $('#example').dataTable( {
11929
+ * "scrollX": "100%",
11930
+ * "scrollXInner": "110%"
11931
+ * } );
11932
+ * } );
11933
+ */
11934
+ "sScrollXInner": "",
11935
+
11936
+
11937
+ /**
11938
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11939
+ * to the given height, and enable scrolling for any data which overflows the
11940
+ * current viewport. This can be used as an alternative to paging to display
11941
+ * a lot of data in a small area (although paging and scrolling can both be
11942
+ * enabled at the same time). This property can be any CSS unit, or a number
11943
+ * (in which case it will be treated as a pixel measurement).
11944
+ * @type string
11945
+ * @default <i>blank string - i.e. disabled</i>
11946
+ *
11947
+ * @dtopt Features
11948
+ * @name DataTable.defaults.scrollY
11949
+ *
11950
+ * @example
11951
+ * $(document).ready( function() {
11952
+ * $('#example').dataTable( {
11953
+ * "scrollY": "200px",
11954
+ * "paginate": false
11955
+ * } );
11956
+ * } );
11957
+ */
11958
+ "sScrollY": "",
11959
+
11960
+
11961
+ /**
11962
+ * __Deprecated__ The functionality provided by this parameter has now been
11963
+ * superseded by that provided through `ajax`, which should be used instead.
11964
+ *
11965
+ * Set the HTTP method that is used to make the Ajax call for server-side
11966
+ * processing or Ajax sourced data.
11967
+ * @type string
11968
+ * @default GET
11969
+ *
11970
+ * @dtopt Options
11971
+ * @dtopt Server-side
11972
+ * @name DataTable.defaults.serverMethod
11973
+ *
11974
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11975
+ */
11976
+ "sServerMethod": "GET",
11977
+
11978
+
11979
+ /**
11980
+ * DataTables makes use of renderers when displaying HTML elements for
11981
+ * a table. These renderers can be added or modified by plug-ins to
11982
+ * generate suitable mark-up for a site. For example the Bootstrap
11983
+ * integration plug-in for DataTables uses a paging button renderer to
11984
+ * display pagination buttons in the mark-up required by Bootstrap.
11985
+ *
11986
+ * For further information about the renderers available see
11987
+ * DataTable.ext.renderer
11988
+ * @type string|object
11989
+ * @default null
11990
+ *
11991
+ * @name DataTable.defaults.renderer
11992
+ *
11993
+ */
11994
+ "renderer": null,
11995
+
11996
+
11997
+ /**
11998
+ * Set the data property name that DataTables should use to get a row's id
11999
+ * to set as the `id` property in the node.
12000
+ * @type string
12001
+ * @default DT_RowId
12002
+ *
12003
+ * @name DataTable.defaults.rowId
12004
+ */
12005
+ "rowId": "DT_RowId"
12006
+ };
12007
+
12008
+ _fnHungarianMap( DataTable.defaults );
12009
+
12010
+
12011
+
12012
+ /*
12013
+ * Developer note - See note in model.defaults.js about the use of Hungarian
12014
+ * notation and camel case.
12015
+ */
12016
+
12017
+ /**
12018
+ * Column options that can be given to DataTables at initialisation time.
12019
+ * @namespace
12020
+ */
12021
+ DataTable.defaults.column = {
12022
+ /**
12023
+ * Define which column(s) an order will occur on for this column. This
12024
+ * allows a column's ordering to take multiple columns into account when
12025
+ * doing a sort or use the data from a different column. For example first
12026
+ * name / last name columns make sense to do a multi-column sort over the
12027
+ * two columns.
12028
+ * @type array|int
12029
+ * @default null <i>Takes the value of the column index automatically</i>
12030
+ *
12031
+ * @name DataTable.defaults.column.orderData
12032
+ * @dtopt Columns
12033
+ *
12034
+ * @example
12035
+ * // Using `columnDefs`
12036
+ * $(document).ready( function() {
12037
+ * $('#example').dataTable( {
12038
+ * "columnDefs": [
12039
+ * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
12040
+ * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
12041
+ * { "orderData": 2, "targets": [ 2 ] }
12042
+ * ]
12043
+ * } );
12044
+ * } );
12045
+ *
12046
+ * @example
12047
+ * // Using `columns`
12048
+ * $(document).ready( function() {
12049
+ * $('#example').dataTable( {
12050
+ * "columns": [
12051
+ * { "orderData": [ 0, 1 ] },
12052
+ * { "orderData": [ 1, 0 ] },
12053
+ * { "orderData": 2 },
12054
+ * null,
12055
+ * null
12056
+ * ]
12057
+ * } );
12058
+ * } );
12059
+ */
12060
+ "aDataSort": null,
12061
+ "iDataSort": -1,
12062
+
12063
+
12064
+ /**
12065
+ * You can control the default ordering direction, and even alter the
12066
+ * behaviour of the sort handler (i.e. only allow ascending ordering etc)
12067
+ * using this parameter.
12068
+ * @type array
12069
+ * @default [ 'asc', 'desc' ]
12070
+ *
12071
+ * @name DataTable.defaults.column.orderSequence
12072
+ * @dtopt Columns
12073
+ *
12074
+ * @example
12075
+ * // Using `columnDefs`
12076
+ * $(document).ready( function() {
12077
+ * $('#example').dataTable( {
12078
+ * "columnDefs": [
12079
+ * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
12080
+ * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
12081
+ * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
12082
+ * ]
12083
+ * } );
12084
+ * } );
12085
+ *
12086
+ * @example
12087
+ * // Using `columns`
12088
+ * $(document).ready( function() {
12089
+ * $('#example').dataTable( {
12090
+ * "columns": [
12091
+ * null,
12092
+ * { "orderSequence": [ "asc" ] },
12093
+ * { "orderSequence": [ "desc", "asc", "asc" ] },
12094
+ * { "orderSequence": [ "desc" ] },
12095
+ * null
12096
+ * ]
12097
+ * } );
12098
+ * } );
12099
+ */
12100
+ "asSorting": [ 'asc', 'desc' ],
12101
+
12102
+
12103
+ /**
12104
+ * Enable or disable filtering on the data in this column.
12105
+ * @type boolean
12106
+ * @default true
12107
+ *
12108
+ * @name DataTable.defaults.column.searchable
12109
+ * @dtopt Columns
12110
+ *
12111
+ * @example
12112
+ * // Using `columnDefs`
12113
+ * $(document).ready( function() {
12114
+ * $('#example').dataTable( {
12115
+ * "columnDefs": [
12116
+ * { "searchable": false, "targets": [ 0 ] }
12117
+ * ] } );
12118
+ * } );
12119
+ *
12120
+ * @example
12121
+ * // Using `columns`
12122
+ * $(document).ready( function() {
12123
+ * $('#example').dataTable( {
12124
+ * "columns": [
12125
+ * { "searchable": false },
12126
+ * null,
12127
+ * null,
12128
+ * null,
12129
+ * null
12130
+ * ] } );
12131
+ * } );
12132
+ */
12133
+ "bSearchable": true,
12134
+
12135
+
12136
+ /**
12137
+ * Enable or disable ordering on this column.
12138
+ * @type boolean
12139
+ * @default true
12140
+ *
12141
+ * @name DataTable.defaults.column.orderable
12142
+ * @dtopt Columns
12143
+ *
12144
+ * @example
12145
+ * // Using `columnDefs`
12146
+ * $(document).ready( function() {
12147
+ * $('#example').dataTable( {
12148
+ * "columnDefs": [
12149
+ * { "orderable": false, "targets": [ 0 ] }
12150
+ * ] } );
12151
+ * } );
12152
+ *
12153
+ * @example
12154
+ * // Using `columns`
12155
+ * $(document).ready( function() {
12156
+ * $('#example').dataTable( {
12157
+ * "columns": [
12158
+ * { "orderable": false },
12159
+ * null,
12160
+ * null,
12161
+ * null,
12162
+ * null
12163
+ * ] } );
12164
+ * } );
12165
+ */
12166
+ "bSortable": true,
12167
+
12168
+
12169
+ /**
12170
+ * Enable or disable the display of this column.
12171
+ * @type boolean
12172
+ * @default true
12173
+ *
12174
+ * @name DataTable.defaults.column.visible
12175
+ * @dtopt Columns
12176
+ *
12177
+ * @example
12178
+ * // Using `columnDefs`
12179
+ * $(document).ready( function() {
12180
+ * $('#example').dataTable( {
12181
+ * "columnDefs": [
12182
+ * { "visible": false, "targets": [ 0 ] }
12183
+ * ] } );
12184
+ * } );
12185
+ *
12186
+ * @example
12187
+ * // Using `columns`
12188
+ * $(document).ready( function() {
12189
+ * $('#example').dataTable( {
12190
+ * "columns": [
12191
+ * { "visible": false },
12192
+ * null,
12193
+ * null,
12194
+ * null,
12195
+ * null
12196
+ * ] } );
12197
+ * } );
12198
+ */
12199
+ "bVisible": true,
12200
+
12201
+
12202
+ /**
12203
+ * Developer definable function that is called whenever a cell is created (Ajax source,
12204
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
12205
+ * allowing you to modify the DOM element (add background colour for example) when the
12206
+ * element is available.
12207
+ * @type function
12208
+ * @param {element} td The TD node that has been created
12209
+ * @param {*} cellData The Data for the cell
12210
+ * @param {array|object} rowData The data for the whole row
12211
+ * @param {int} row The row index for the aoData data store
12212
+ * @param {int} col The column index for aoColumns
12213
+ *
12214
+ * @name DataTable.defaults.column.createdCell
12215
+ * @dtopt Columns
12216
+ *
12217
+ * @example
12218
+ * $(document).ready( function() {
12219
+ * $('#example').dataTable( {
12220
+ * "columnDefs": [ {
12221
+ * "targets": [3],
12222
+ * "createdCell": function (td, cellData, rowData, row, col) {
12223
+ * if ( cellData == "1.7" ) {
12224
+ * $(td).css('color', 'blue')
12225
+ * }
12226
+ * }
12227
+ * } ]
12228
+ * });
12229
+ * } );
12230
+ */
12231
+ "fnCreatedCell": null,
12232
+
12233
+
12234
+ /**
12235
+ * This parameter has been replaced by `data` in DataTables to ensure naming
12236
+ * consistency. `dataProp` can still be used, as there is backwards
12237
+ * compatibility in DataTables for this option, but it is strongly
12238
+ * recommended that you use `data` in preference to `dataProp`.
12239
+ * @name DataTable.defaults.column.dataProp
12240
+ */
12241
+
12242
+
12243
+ /**
12244
+ * This property can be used to read data from any data source property,
12245
+ * including deeply nested objects / properties. `data` can be given in a
12246
+ * number of different ways which effect its behaviour:
12247
+ *
12248
+ * * `integer` - treated as an array index for the data source. This is the
12249
+ * default that DataTables uses (incrementally increased for each column).
12250
+ * * `string` - read an object property from the data source. There are
12251
+ * three 'special' options that can be used in the string to alter how
12252
+ * DataTables reads the data from the source object:
12253
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
12254
+ * Javascript to read from nested objects, so to can the options
12255
+ * specified in `data`. For example: `browser.version` or
12256
+ * `browser.name`. If your object parameter name contains a period, use
12257
+ * `\\` to escape it - i.e. `first\\.name`.
12258
+ * * `[]` - Array notation. DataTables can automatically combine data
12259
+ * from and array source, joining the data with the characters provided
12260
+ * between the two brackets. For example: `name[, ]` would provide a
12261
+ * comma-space separated list from the source array. If no characters
12262
+ * are provided between the brackets, the original array source is
12263
+ * returned.
12264
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
12265
+ * execute a function of the name given. For example: `browser()` for a
12266
+ * simple function on the data source, `browser.version()` for a
12267
+ * function in a nested property or even `browser().version` to get an
12268
+ * object property if the function called returns an object. Note that
12269
+ * function notation is recommended for use in `render` rather than
12270
+ * `data` as it is much simpler to use as a renderer.
12271
+ * * `null` - use the original data source for the row rather than plucking
12272
+ * data directly from it. This action has effects on two other
12273
+ * initialisation options:
12274
+ * * `defaultContent` - When null is given as the `data` option and
12275
+ * `defaultContent` is specified for the column, the value defined by
12276
+ * `defaultContent` will be used for the cell.
12277
+ * * `render` - When null is used for the `data` option and the `render`
12278
+ * option is specified for the column, the whole data source for the
12279
+ * row is used for the renderer.
12280
+ * * `function` - the function given will be executed whenever DataTables
12281
+ * needs to set or get the data for a cell in the column. The function
12282
+ * takes three parameters:
12283
+ * * Parameters:
12284
+ * * `{array|object}` The data source for the row
12285
+ * * `{string}` The type call data requested - this will be 'set' when
12286
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined
12287
+ * when gathering data. Note that when `undefined` is given for the
12288
+ * type DataTables expects to get the raw data for the object back<
12289
+ * * `{*}` Data to set when the second parameter is 'set'.
12290
+ * * Return:
12291
+ * * The return value from the function is not required when 'set' is
12292
+ * the type of call, but otherwise the return is what will be used
12293
+ * for the data requested.
12294
+ *
12295
+ * Note that `data` is a getter and setter option. If you just require
12296
+ * formatting of data for output, you will likely want to use `render` which
12297
+ * is simply a getter and thus simpler to use.
12298
+ *
12299
+ * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
12300
+ * name change reflects the flexibility of this property and is consistent
12301
+ * with the naming of mRender. If 'mDataProp' is given, then it will still
12302
+ * be used by DataTables, as it automatically maps the old name to the new
12303
+ * if required.
12304
+ *
12305
+ * @type string|int|function|null
12306
+ * @default null <i>Use automatically calculated column index</i>
12307
+ *
12308
+ * @name DataTable.defaults.column.data
12309
+ * @dtopt Columns
12310
+ *
12311
+ * @example
12312
+ * // Read table data from objects
12313
+ * // JSON structure for each row:
12314
+ * // {
12315
+ * // "engine": {value},
12316
+ * // "browser": {value},
12317
+ * // "platform": {value},
12318
+ * // "version": {value},
12319
+ * // "grade": {value}
12320
+ * // }
12321
+ * $(document).ready( function() {
12322
+ * $('#example').dataTable( {
12323
+ * "ajaxSource": "sources/objects.txt",
12324
+ * "columns": [
12325
+ * { "data": "engine" },
12326
+ * { "data": "browser" },
12327
+ * { "data": "platform" },
12328
+ * { "data": "version" },
12329
+ * { "data": "grade" }
12330
+ * ]
12331
+ * } );
12332
+ * } );
12333
+ *
12334
+ * @example
12335
+ * // Read information from deeply nested objects
12336
+ * // JSON structure for each row:
12337
+ * // {
12338
+ * // "engine": {value},
12339
+ * // "browser": {value},
12340
+ * // "platform": {
12341
+ * // "inner": {value}
12342
+ * // },
12343
+ * // "details": [
12344
+ * // {value}, {value}
12345
+ * // ]
12346
+ * // }
12347
+ * $(document).ready( function() {
12348
+ * $('#example').dataTable( {
12349
+ * "ajaxSource": "sources/deep.txt",
12350
+ * "columns": [
12351
+ * { "data": "engine" },
12352
+ * { "data": "browser" },
12353
+ * { "data": "platform.inner" },
12354
+ * { "data": "platform.details.0" },
12355
+ * { "data": "platform.details.1" }
12356
+ * ]
12357
+ * } );
12358
+ * } );
12359
+ *
12360
+ * @example
12361
+ * // Using `data` as a function to provide different information for
12362
+ * // sorting, filtering and display. In this case, currency (price)
12363
+ * $(document).ready( function() {
12364
+ * $('#example').dataTable( {
12365
+ * "columnDefs": [ {
12366
+ * "targets": [ 0 ],
12367
+ * "data": function ( source, type, val ) {
12368
+ * if (type === 'set') {
12369
+ * source.price = val;
12370
+ * // Store the computed dislay and filter values for efficiency
12371
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12372
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12373
+ * return;
12374
+ * }
12375
+ * else if (type === 'display') {
12376
+ * return source.price_display;
12377
+ * }
12378
+ * else if (type === 'filter') {
12379
+ * return source.price_filter;
12380
+ * }
12381
+ * // 'sort', 'type' and undefined all just use the integer
12382
+ * return source.price;
12383
+ * }
12384
+ * } ]
12385
+ * } );
12386
+ * } );
12387
+ *
12388
+ * @example
12389
+ * // Using default content
12390
+ * $(document).ready( function() {
12391
+ * $('#example').dataTable( {
12392
+ * "columnDefs": [ {
12393
+ * "targets": [ 0 ],
12394
+ * "data": null,
12395
+ * "defaultContent": "Click to edit"
12396
+ * } ]
12397
+ * } );
12398
+ * } );
12399
+ *
12400
+ * @example
12401
+ * // Using array notation - outputting a list from an array
12402
+ * $(document).ready( function() {
12403
+ * $('#example').dataTable( {
12404
+ * "columnDefs": [ {
12405
+ * "targets": [ 0 ],
12406
+ * "data": "name[, ]"
12407
+ * } ]
12408
+ * } );
12409
+ * } );
12410
+ *
12411
+ */
12412
+ "mData": null,
12413
+
12414
+
12415
+ /**
12416
+ * This property is the rendering partner to `data` and it is suggested that
12417
+ * when you want to manipulate data for display (including filtering,
12418
+ * sorting etc) without altering the underlying data for the table, use this
12419
+ * property. `render` can be considered to be the the read only companion to
12420
+ * `data` which is read / write (then as such more complex). Like `data`
12421
+ * this option can be given in a number of different ways to effect its
12422
+ * behaviour:
12423
+ *
12424
+ * * `integer` - treated as an array index for the data source. This is the
12425
+ * default that DataTables uses (incrementally increased for each column).
12426
+ * * `string` - read an object property from the data source. There are
12427
+ * three 'special' options that can be used in the string to alter how
12428
+ * DataTables reads the data from the source object:
12429
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
12430
+ * Javascript to read from nested objects, so to can the options
12431
+ * specified in `data`. For example: `browser.version` or
12432
+ * `browser.name`. If your object parameter name contains a period, use
12433
+ * `\\` to escape it - i.e. `first\\.name`.
12434
+ * * `[]` - Array notation. DataTables can automatically combine data
12435
+ * from and array source, joining the data with the characters provided
12436
+ * between the two brackets. For example: `name[, ]` would provide a
12437
+ * comma-space separated list from the source array. If no characters
12438
+ * are provided between the brackets, the original array source is
12439
+ * returned.
12440
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
12441
+ * execute a function of the name given. For example: `browser()` for a
12442
+ * simple function on the data source, `browser.version()` for a
12443
+ * function in a nested property or even `browser().version` to get an
12444
+ * object property if the function called returns an object.
12445
+ * * `object` - use different data for the different data types requested by
12446
+ * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12447
+ * of the object is the data type the property refers to and the value can
12448
+ * defined using an integer, string or function using the same rules as
12449
+ * `render` normally does. Note that an `_` option _must_ be specified.
12450
+ * This is the default value to use if you haven't specified a value for
12451
+ * the data type requested by DataTables.
12452
+ * * `function` - the function given will be executed whenever DataTables
12453
+ * needs to set or get the data for a cell in the column. The function
12454
+ * takes three parameters:
12455
+ * * Parameters:
12456
+ * * {array|object} The data source for the row (based on `data`)
12457
+ * * {string} The type call data requested - this will be 'filter',
12458
+ * 'display', 'type' or 'sort'.
12459
+ * * {array|object} The full data source for the row (not based on
12460
+ * `data`)
12461
+ * * Return:
12462
+ * * The return value from the function is what will be used for the
12463
+ * data requested.
12464
+ *
12465
+ * @type string|int|function|object|null
12466
+ * @default null Use the data source value.
12467
+ *
12468
+ * @name DataTable.defaults.column.render
12469
+ * @dtopt Columns
12470
+ *
12471
+ * @example
12472
+ * // Create a comma separated list from an array of objects
12473
+ * $(document).ready( function() {
12474
+ * $('#example').dataTable( {
12475
+ * "ajaxSource": "sources/deep.txt",
12476
+ * "columns": [
12477
+ * { "data": "engine" },
12478
+ * { "data": "browser" },
12479
+ * {
12480
+ * "data": "platform",
12481
+ * "render": "[, ].name"
12482
+ * }
12483
+ * ]
12484
+ * } );
12485
+ * } );
12486
+ *
12487
+ * @example
12488
+ * // Execute a function to obtain data
12489
+ * $(document).ready( function() {
12490
+ * $('#example').dataTable( {
12491
+ * "columnDefs": [ {
12492
+ * "targets": [ 0 ],
12493
+ * "data": null, // Use the full data source object for the renderer's source
12494
+ * "render": "browserName()"
12495
+ * } ]
12496
+ * } );
12497
+ * } );
12498
+ *
12499
+ * @example
12500
+ * // As an object, extracting different data for the different types
12501
+ * // This would be used with a data source such as:
12502
+ * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12503
+ * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12504
+ * // (which has both forms) is used for filtering for if a user inputs either format, while
12505
+ * // the formatted phone number is the one that is shown in the table.
12506
+ * $(document).ready( function() {
12507
+ * $('#example').dataTable( {
12508
+ * "columnDefs": [ {
12509
+ * "targets": [ 0 ],
12510
+ * "data": null, // Use the full data source object for the renderer's source
12511
+ * "render": {
12512
+ * "_": "phone",
12513
+ * "filter": "phone_filter",
12514
+ * "display": "phone_display"
12515
+ * }
12516
+ * } ]
12517
+ * } );
12518
+ * } );
12519
+ *
12520
+ * @example
12521
+ * // Use as a function to create a link from the data source
12522
+ * $(document).ready( function() {
12523
+ * $('#example').dataTable( {
12524
+ * "columnDefs": [ {
12525
+ * "targets": [ 0 ],
12526
+ * "data": "download_link",
12527
+ * "render": function ( data, type, full ) {
12528
+ * return '<a href="'+data+'">Download</a>';
12529
+ * }
12530
+ * } ]
12531
+ * } );
12532
+ * } );
12533
+ */
12534
+ "mRender": null,
12535
+
12536
+
12537
+ /**
12538
+ * Change the cell type created for the column - either TD cells or TH cells. This
12539
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
12540
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12541
+ * @type string
12542
+ * @default td
12543
+ *
12544
+ * @name DataTable.defaults.column.cellType
12545
+ * @dtopt Columns
12546
+ *
12547
+ * @example
12548
+ * // Make the first column use TH cells
12549
+ * $(document).ready( function() {
12550
+ * $('#example').dataTable( {
12551
+ * "columnDefs": [ {
12552
+ * "targets": [ 0 ],
12553
+ * "cellType": "th"
12554
+ * } ]
12555
+ * } );
12556
+ * } );
12557
+ */
12558
+ "sCellType": "td",
12559
+
12560
+
12561
+ /**
12562
+ * Class to give to each cell in this column.
12563
+ * @type string
12564
+ * @default <i>Empty string</i>
12565
+ *
12566
+ * @name DataTable.defaults.column.class
12567
+ * @dtopt Columns
12568
+ *
12569
+ * @example
12570
+ * // Using `columnDefs`
12571
+ * $(document).ready( function() {
12572
+ * $('#example').dataTable( {
12573
+ * "columnDefs": [
12574
+ * { "class": "my_class", "targets": [ 0 ] }
12575
+ * ]
12576
+ * } );
12577
+ * } );
12578
+ *
12579
+ * @example
12580
+ * // Using `columns`
12581
+ * $(document).ready( function() {
12582
+ * $('#example').dataTable( {
12583
+ * "columns": [
12584
+ * { "class": "my_class" },
12585
+ * null,
12586
+ * null,
12587
+ * null,
12588
+ * null
12589
+ * ]
12590
+ * } );
12591
+ * } );
12592
+ */
12593
+ "sClass": "",
12594
+
12595
+ /**
12596
+ * When DataTables calculates the column widths to assign to each column,
12597
+ * it finds the longest string in each column and then constructs a
12598
+ * temporary table and reads the widths from that. The problem with this
12599
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
12600
+ * string - thus the calculation can go wrong (doing it properly and putting
12601
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
12602
+ * a "work around" we provide this option. It will append its value to the
12603
+ * text that is found to be the longest string for the column - i.e. padding.
12604
+ * Generally you shouldn't need this!
12605
+ * @type string
12606
+ * @default <i>Empty string<i>
12607
+ *
12608
+ * @name DataTable.defaults.column.contentPadding
12609
+ * @dtopt Columns
12610
+ *
12611
+ * @example
12612
+ * // Using `columns`
12613
+ * $(document).ready( function() {
12614
+ * $('#example').dataTable( {
12615
+ * "columns": [
12616
+ * null,
12617
+ * null,
12618
+ * null,
12619
+ * {
12620
+ * "contentPadding": "mmm"
12621
+ * }
12622
+ * ]
12623
+ * } );
12624
+ * } );
12625
+ */
12626
+ "sContentPadding": "",
12627
+
12628
+
12629
+ /**
12630
+ * Allows a default value to be given for a column's data, and will be used
12631
+ * whenever a null data source is encountered (this can be because `data`
12632
+ * is set to null, or because the data source itself is null).
12633
+ * @type string
12634
+ * @default null
12635
+ *
12636
+ * @name DataTable.defaults.column.defaultContent
12637
+ * @dtopt Columns
12638
+ *
12639
+ * @example
12640
+ * // Using `columnDefs`
12641
+ * $(document).ready( function() {
12642
+ * $('#example').dataTable( {
12643
+ * "columnDefs": [
12644
+ * {
12645
+ * "data": null,
12646
+ * "defaultContent": "Edit",
12647
+ * "targets": [ -1 ]
12648
+ * }
12649
+ * ]
12650
+ * } );
12651
+ * } );
12652
+ *
12653
+ * @example
12654
+ * // Using `columns`
12655
+ * $(document).ready( function() {
12656
+ * $('#example').dataTable( {
12657
+ * "columns": [
12658
+ * null,
12659
+ * null,
12660
+ * null,
12661
+ * {
12662
+ * "data": null,
12663
+ * "defaultContent": "Edit"
12664
+ * }
12665
+ * ]
12666
+ * } );
12667
+ * } );
12668
+ */
12669
+ "sDefaultContent": null,
12670
+
12671
+
12672
+ /**
12673
+ * This parameter is only used in DataTables' server-side processing. It can
12674
+ * be exceptionally useful to know what columns are being displayed on the
12675
+ * client side, and to map these to database fields. When defined, the names
12676
+ * also allow DataTables to reorder information from the server if it comes
12677
+ * back in an unexpected order (i.e. if you switch your columns around on the
12678
+ * client-side, your server-side code does not also need updating).
12679
+ * @type string
12680
+ * @default <i>Empty string</i>
12681
+ *
12682
+ * @name DataTable.defaults.column.name
12683
+ * @dtopt Columns
12684
+ *
12685
+ * @example
12686
+ * // Using `columnDefs`
12687
+ * $(document).ready( function() {
12688
+ * $('#example').dataTable( {
12689
+ * "columnDefs": [
12690
+ * { "name": "engine", "targets": [ 0 ] },
12691
+ * { "name": "browser", "targets": [ 1 ] },
12692
+ * { "name": "platform", "targets": [ 2 ] },
12693
+ * { "name": "version", "targets": [ 3 ] },
12694
+ * { "name": "grade", "targets": [ 4 ] }
12695
+ * ]
12696
+ * } );
12697
+ * } );
12698
+ *
12699
+ * @example
12700
+ * // Using `columns`
12701
+ * $(document).ready( function() {
12702
+ * $('#example').dataTable( {
12703
+ * "columns": [
12704
+ * { "name": "engine" },
12705
+ * { "name": "browser" },
12706
+ * { "name": "platform" },
12707
+ * { "name": "version" },
12708
+ * { "name": "grade" }
12709
+ * ]
12710
+ * } );
12711
+ * } );
12712
+ */
12713
+ "sName": "",
12714
+
12715
+
12716
+ /**
12717
+ * Defines a data source type for the ordering which can be used to read
12718
+ * real-time information from the table (updating the internally cached
12719
+ * version) prior to ordering. This allows ordering to occur on user
12720
+ * editable elements such as form inputs.
12721
+ * @type string
12722
+ * @default std
12723
+ *
12724
+ * @name DataTable.defaults.column.orderDataType
12725
+ * @dtopt Columns
12726
+ *
12727
+ * @example
12728
+ * // Using `columnDefs`
12729
+ * $(document).ready( function() {
12730
+ * $('#example').dataTable( {
12731
+ * "columnDefs": [
12732
+ * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12733
+ * { "type": "numeric", "targets": [ 3 ] },
12734
+ * { "orderDataType": "dom-select", "targets": [ 4 ] },
12735
+ * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12736
+ * ]
12737
+ * } );
12738
+ * } );
12739
+ *
12740
+ * @example
12741
+ * // Using `columns`
12742
+ * $(document).ready( function() {
12743
+ * $('#example').dataTable( {
12744
+ * "columns": [
12745
+ * null,
12746
+ * null,
12747
+ * { "orderDataType": "dom-text" },
12748
+ * { "orderDataType": "dom-text", "type": "numeric" },
12749
+ * { "orderDataType": "dom-select" },
12750
+ * { "orderDataType": "dom-checkbox" }
12751
+ * ]
12752
+ * } );
12753
+ * } );
12754
+ */
12755
+ "sSortDataType": "std",
12756
+
12757
+
12758
+ /**
12759
+ * The title of this column.
12760
+ * @type string
12761
+ * @default null <i>Derived from the 'TH' value for this column in the
12762
+ * original HTML table.</i>
12763
+ *
12764
+ * @name DataTable.defaults.column.title
12765
+ * @dtopt Columns
12766
+ *
12767
+ * @example
12768
+ * // Using `columnDefs`
12769
+ * $(document).ready( function() {
12770
+ * $('#example').dataTable( {
12771
+ * "columnDefs": [
12772
+ * { "title": "My column title", "targets": [ 0 ] }
12773
+ * ]
12774
+ * } );
12775
+ * } );
12776
+ *
12777
+ * @example
12778
+ * // Using `columns`
12779
+ * $(document).ready( function() {
12780
+ * $('#example').dataTable( {
12781
+ * "columns": [
12782
+ * { "title": "My column title" },
12783
+ * null,
12784
+ * null,
12785
+ * null,
12786
+ * null
12787
+ * ]
12788
+ * } );
12789
+ * } );
12790
+ */
12791
+ "sTitle": null,
12792
+
12793
+
12794
+ /**
12795
+ * The type allows you to specify how the data for this column will be
12796
+ * ordered. Four types (string, numeric, date and html (which will strip
12797
+ * HTML tags before ordering)) are currently available. Note that only date
12798
+ * formats understood by Javascript's Date() object will be accepted as type
12799
+ * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12800
+ * 'numeric', 'date' or 'html' (by default). Further types can be adding
12801
+ * through plug-ins.
12802
+ * @type string
12803
+ * @default null <i>Auto-detected from raw data</i>
12804
+ *
12805
+ * @name DataTable.defaults.column.type
12806
+ * @dtopt Columns
12807
+ *
12808
+ * @example
12809
+ * // Using `columnDefs`
12810
+ * $(document).ready( function() {
12811
+ * $('#example').dataTable( {
12812
+ * "columnDefs": [
12813
+ * { "type": "html", "targets": [ 0 ] }
12814
+ * ]
12815
+ * } );
12816
+ * } );
12817
+ *
12818
+ * @example
12819
+ * // Using `columns`
12820
+ * $(document).ready( function() {
12821
+ * $('#example').dataTable( {
12822
+ * "columns": [
12823
+ * { "type": "html" },
12824
+ * null,
12825
+ * null,
12826
+ * null,
12827
+ * null
12828
+ * ]
12829
+ * } );
12830
+ * } );
12831
+ */
12832
+ "sType": null,
12833
+
12834
+
12835
+ /**
12836
+ * Defining the width of the column, this parameter may take any CSS value
12837
+ * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12838
+ * been given a specific width through this interface ensuring that the table
12839
+ * remains readable.
12840
+ * @type string
12841
+ * @default null <i>Automatic</i>
12842
+ *
12843
+ * @name DataTable.defaults.column.width
12844
+ * @dtopt Columns
12845
+ *
12846
+ * @example
12847
+ * // Using `columnDefs`
12848
+ * $(document).ready( function() {
12849
+ * $('#example').dataTable( {
12850
+ * "columnDefs": [
12851
+ * { "width": "20%", "targets": [ 0 ] }
12852
+ * ]
12853
+ * } );
12854
+ * } );
12855
+ *
12856
+ * @example
12857
+ * // Using `columns`
12858
+ * $(document).ready( function() {
12859
+ * $('#example').dataTable( {
12860
+ * "columns": [
12861
+ * { "width": "20%" },
12862
+ * null,
12863
+ * null,
12864
+ * null,
12865
+ * null
12866
+ * ]
12867
+ * } );
12868
+ * } );
12869
+ */
12870
+ "sWidth": null
12871
+ };
12872
+
12873
+ _fnHungarianMap( DataTable.defaults.column );
12874
+
12875
+
12876
+
12877
+ /**
12878
+ * DataTables settings object - this holds all the information needed for a
12879
+ * given table, including configuration, data and current application of the
12880
+ * table options. DataTables does not have a single instance for each DataTable
12881
+ * with the settings attached to that instance, but rather instances of the
12882
+ * DataTable "class" are created on-the-fly as needed (typically by a
12883
+ * $().dataTable() call) and the settings object is then applied to that
12884
+ * instance.
12885
+ *
12886
+ * Note that this object is related to {@link DataTable.defaults} but this
12887
+ * one is the internal data store for DataTables's cache of columns. It should
12888
+ * NOT be manipulated outside of DataTables. Any configuration should be done
12889
+ * through the initialisation options.
12890
+ * @namespace
12891
+ * @todo Really should attach the settings object to individual instances so we
12892
+ * don't need to create new instances on each $().dataTable() call (if the
12893
+ * table already exists). It would also save passing oSettings around and
12894
+ * into every single function. However, this is a very significant
12895
+ * architecture change for DataTables and will almost certainly break
12896
+ * backwards compatibility with older installations. This is something that
12897
+ * will be done in 2.0.
12898
+ */
12899
+ DataTable.models.oSettings = {
12900
+ /**
12901
+ * Primary features of DataTables and their enablement state.
12902
+ * @namespace
12903
+ */
12904
+ "oFeatures": {
12905
+
12906
+ /**
12907
+ * Flag to say if DataTables should automatically try to calculate the
12908
+ * optimum table and columns widths (true) or not (false).
12909
+ * Note that this parameter will be set by the initialisation routine. To
12910
+ * set a default use {@link DataTable.defaults}.
12911
+ * @type boolean
12912
+ */
12913
+ "bAutoWidth": null,
12914
+
12915
+ /**
12916
+ * Delay the creation of TR and TD elements until they are actually
12917
+ * needed by a driven page draw. This can give a significant speed
12918
+ * increase for Ajax source and Javascript source data, but makes no
12919
+ * difference at all fro DOM and server-side processing tables.
12920
+ * Note that this parameter will be set by the initialisation routine. To
12921
+ * set a default use {@link DataTable.defaults}.
12922
+ * @type boolean
12923
+ */
12924
+ "bDeferRender": null,
12925
+
12926
+ /**
12927
+ * Enable filtering on the table or not. Note that if this is disabled
12928
+ * then there is no filtering at all on the table, including fnFilter.
12929
+ * To just remove the filtering input use sDom and remove the 'f' option.
12930
+ * Note that this parameter will be set by the initialisation routine. To
12931
+ * set a default use {@link DataTable.defaults}.
12932
+ * @type boolean
12933
+ */
12934
+ "bFilter": null,
12935
+
12936
+ /**
12937
+ * Table information element (the 'Showing x of y records' div) enable
12938
+ * flag.
12939
+ * Note that this parameter will be set by the initialisation routine. To
12940
+ * set a default use {@link DataTable.defaults}.
12941
+ * @type boolean
12942
+ */
12943
+ "bInfo": null,
12944
+
12945
+ /**
12946
+ * Present a user control allowing the end user to change the page size
12947
+ * when pagination is enabled.
12948
+ * Note that this parameter will be set by the initialisation routine. To
12949
+ * set a default use {@link DataTable.defaults}.
12950
+ * @type boolean
12951
+ */
12952
+ "bLengthChange": null,
12953
+
12954
+ /**
12955
+ * Pagination enabled or not. Note that if this is disabled then length
12956
+ * changing must also be disabled.
12957
+ * Note that this parameter will be set by the initialisation routine. To
12958
+ * set a default use {@link DataTable.defaults}.
12959
+ * @type boolean
12960
+ */
12961
+ "bPaginate": null,
12962
+
12963
+ /**
12964
+ * Processing indicator enable flag whenever DataTables is enacting a
12965
+ * user request - typically an Ajax request for server-side processing.
12966
+ * Note that this parameter will be set by the initialisation routine. To
12967
+ * set a default use {@link DataTable.defaults}.
12968
+ * @type boolean
12969
+ */
12970
+ "bProcessing": null,
12971
+
12972
+ /**
12973
+ * Server-side processing enabled flag - when enabled DataTables will
12974
+ * get all data from the server for every draw - there is no filtering,
12975
+ * sorting or paging done on the client-side.
12976
+ * Note that this parameter will be set by the initialisation routine. To
12977
+ * set a default use {@link DataTable.defaults}.
12978
+ * @type boolean
12979
+ */
12980
+ "bServerSide": null,
12981
+
12982
+ /**
12983
+ * Sorting enablement flag.
12984
+ * Note that this parameter will be set by the initialisation routine. To
12985
+ * set a default use {@link DataTable.defaults}.
12986
+ * @type boolean
12987
+ */
12988
+ "bSort": null,
12989
+
12990
+ /**
12991
+ * Multi-column sorting
12992
+ * Note that this parameter will be set by the initialisation routine. To
12993
+ * set a default use {@link DataTable.defaults}.
12994
+ * @type boolean
12995
+ */
12996
+ "bSortMulti": null,
12997
+
12998
+ /**
12999
+ * Apply a class to the columns which are being sorted to provide a
13000
+ * visual highlight or not. This can slow things down when enabled since
13001
+ * there is a lot of DOM interaction.
13002
+ * Note that this parameter will be set by the initialisation routine. To
13003
+ * set a default use {@link DataTable.defaults}.
13004
+ * @type boolean
13005
+ */
13006
+ "bSortClasses": null,
13007
+
13008
+ /**
13009
+ * State saving enablement flag.
13010
+ * Note that this parameter will be set by the initialisation routine. To
13011
+ * set a default use {@link DataTable.defaults}.
13012
+ * @type boolean
13013
+ */
13014
+ "bStateSave": null
13015
+ },
13016
+
13017
+
13018
+ /**
13019
+ * Scrolling settings for a table.
13020
+ * @namespace
13021
+ */
13022
+ "oScroll": {
13023
+ /**
13024
+ * When the table is shorter in height than sScrollY, collapse the
13025
+ * table container down to the height of the table (when true).
13026
+ * Note that this parameter will be set by the initialisation routine. To
13027
+ * set a default use {@link DataTable.defaults}.
13028
+ * @type boolean
13029
+ */
13030
+ "bCollapse": null,
13031
+
13032
+ /**
13033
+ * Width of the scrollbar for the web-browser's platform. Calculated
13034
+ * during table initialisation.
13035
+ * @type int
13036
+ * @default 0
13037
+ */
13038
+ "iBarWidth": 0,
13039
+
13040
+ /**
13041
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
13042
+ * disabled if an empty string.
13043
+ * Note that this parameter will be set by the initialisation routine. To
13044
+ * set a default use {@link DataTable.defaults}.
13045
+ * @type string
13046
+ */
13047
+ "sX": null,
13048
+
13049
+ /**
13050
+ * Width to expand the table to when using x-scrolling. Typically you
13051
+ * should not need to use this.
13052
+ * Note that this parameter will be set by the initialisation routine. To
13053
+ * set a default use {@link DataTable.defaults}.
13054
+ * @type string
13055
+ * @deprecated
13056
+ */
13057
+ "sXInner": null,
13058
+
13059
+ /**
13060
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
13061
+ * if an empty string.
13062
+ * Note that this parameter will be set by the initialisation routine. To
13063
+ * set a default use {@link DataTable.defaults}.
13064
+ * @type string
13065
+ */
13066
+ "sY": null
13067
+ },
13068
+
13069
+ /**
13070
+ * Language information for the table.
13071
+ * @namespace
13072
+ * @extends DataTable.defaults.oLanguage
13073
+ */
13074
+ "oLanguage": {
13075
+ /**
13076
+ * Information callback function. See
13077
+ * {@link DataTable.defaults.fnInfoCallback}
13078
+ * @type function
13079
+ * @default null
13080
+ */
13081
+ "fnInfoCallback": null
13082
+ },
13083
+
13084
+ /**
13085
+ * Browser support parameters
13086
+ * @namespace
13087
+ */
13088
+ "oBrowser": {
13089
+ /**
13090
+ * Indicate if the browser incorrectly calculates width:100% inside a
13091
+ * scrolling element (IE6/7)
13092
+ * @type boolean
13093
+ * @default false
13094
+ */
13095
+ "bScrollOversize": false,
13096
+
13097
+ /**
13098
+ * Determine if the vertical scrollbar is on the right or left of the
13099
+ * scrolling container - needed for rtl language layout, although not
13100
+ * all browsers move the scrollbar (Safari).
13101
+ * @type boolean
13102
+ * @default false
13103
+ */
13104
+ "bScrollbarLeft": false,
13105
+
13106
+ /**
13107
+ * Flag for if `getBoundingClientRect` is fully supported or not
13108
+ * @type boolean
13109
+ * @default false
13110
+ */
13111
+ "bBounding": false,
13112
+
13113
+ /**
13114
+ * Browser scrollbar width
13115
+ * @type integer
13116
+ * @default 0
13117
+ */
13118
+ "barWidth": 0
13119
+ },
13120
+
13121
+
13122
+ "ajax": null,
13123
+
13124
+
13125
+ /**
13126
+ * Array referencing the nodes which are used for the features. The
13127
+ * parameters of this object match what is allowed by sDom - i.e.
13128
+ * <ul>
13129
+ * <li>'l' - Length changing</li>
13130
+ * <li>'f' - Filtering input</li>
13131
+ * <li>'t' - The table!</li>
13132
+ * <li>'i' - Information</li>
13133
+ * <li>'p' - Pagination</li>
13134
+ * <li>'r' - pRocessing</li>
13135
+ * </ul>
13136
+ * @type array
13137
+ * @default []
13138
+ */
13139
+ "aanFeatures": [],
13140
+
13141
+ /**
13142
+ * Store data information - see {@link DataTable.models.oRow} for detailed
13143
+ * information.
13144
+ * @type array
13145
+ * @default []
13146
+ */
13147
+ "aoData": [],
13148
+
13149
+ /**
13150
+ * Array of indexes which are in the current display (after filtering etc)
13151
+ * @type array
13152
+ * @default []
13153
+ */
13154
+ "aiDisplay": [],
13155
+
13156
+ /**
13157
+ * Array of indexes for display - no filtering
13158
+ * @type array
13159
+ * @default []
13160
+ */
13161
+ "aiDisplayMaster": [],
13162
+
13163
+ /**
13164
+ * Map of row ids to data indexes
13165
+ * @type object
13166
+ * @default {}
13167
+ */
13168
+ "aIds": {},
13169
+
13170
+ /**
13171
+ * Store information about each column that is in use
13172
+ * @type array
13173
+ * @default []
13174
+ */
13175
+ "aoColumns": [],
13176
+
13177
+ /**
13178
+ * Store information about the table's header
13179
+ * @type array
13180
+ * @default []
13181
+ */
13182
+ "aoHeader": [],
13183
+
13184
+ /**
13185
+ * Store information about the table's footer
13186
+ * @type array
13187
+ * @default []
13188
+ */
13189
+ "aoFooter": [],
13190
+
13191
+ /**
13192
+ * Store the applied global search information in case we want to force a
13193
+ * research or compare the old search to a new one.
13194
+ * Note that this parameter will be set by the initialisation routine. To
13195
+ * set a default use {@link DataTable.defaults}.
13196
+ * @namespace
13197
+ * @extends DataTable.models.oSearch
13198
+ */
13199
+ "oPreviousSearch": {},
13200
+
13201
+ /**
13202
+ * Store the applied search for each column - see
13203
+ * {@link DataTable.models.oSearch} for the format that is used for the
13204
+ * filtering information for each column.
13205
+ * @type array
13206
+ * @default []
13207
+ */
13208
+ "aoPreSearchCols": [],
13209
+
13210
+ /**
13211
+ * Sorting that is applied to the table. Note that the inner arrays are
13212
+ * used in the following manner:
13213
+ * <ul>
13214
+ * <li>Index 0 - column number</li>
13215
+ * <li>Index 1 - current sorting direction</li>
13216
+ * </ul>
13217
+ * Note that this parameter will be set by the initialisation routine. To
13218
+ * set a default use {@link DataTable.defaults}.
13219
+ * @type array
13220
+ * @todo These inner arrays should really be objects
13221
+ */
13222
+ "aaSorting": null,
13223
+
13224
+ /**
13225
+ * Sorting that is always applied to the table (i.e. prefixed in front of
13226
+ * aaSorting).
13227
+ * Note that this parameter will be set by the initialisation routine. To
13228
+ * set a default use {@link DataTable.defaults}.
13229
+ * @type array
13230
+ * @default []
13231
+ */
13232
+ "aaSortingFixed": [],
13233
+
13234
+ /**
13235
+ * Classes to use for the striping of a table.
13236
+ * Note that this parameter will be set by the initialisation routine. To
13237
+ * set a default use {@link DataTable.defaults}.
13238
+ * @type array
13239
+ * @default []
13240
+ */
13241
+ "asStripeClasses": null,
13242
+
13243
+ /**
13244
+ * If restoring a table - we should restore its striping classes as well
13245
+ * @type array
13246
+ * @default []
13247
+ */
13248
+ "asDestroyStripes": [],
13249
+
13250
+ /**
13251
+ * If restoring a table - we should restore its width
13252
+ * @type int
13253
+ * @default 0
13254
+ */
13255
+ "sDestroyWidth": 0,
13256
+
13257
+ /**
13258
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
13259
+ * @type array
13260
+ * @default []
13261
+ */
13262
+ "aoRowCallback": [],
13263
+
13264
+ /**
13265
+ * Callback functions for the header on each draw.
13266
+ * @type array
13267
+ * @default []
13268
+ */
13269
+ "aoHeaderCallback": [],
13270
+
13271
+ /**
13272
+ * Callback function for the footer on each draw.
13273
+ * @type array
13274
+ * @default []
13275
+ */
13276
+ "aoFooterCallback": [],
13277
+
13278
+ /**
13279
+ * Array of callback functions for draw callback functions
13280
+ * @type array
13281
+ * @default []
13282
+ */
13283
+ "aoDrawCallback": [],
13284
+
13285
+ /**
13286
+ * Array of callback functions for row created function
13287
+ * @type array
13288
+ * @default []
13289
+ */
13290
+ "aoRowCreatedCallback": [],
13291
+
13292
+ /**
13293
+ * Callback functions for just before the table is redrawn. A return of
13294
+ * false will be used to cancel the draw.
13295
+ * @type array
13296
+ * @default []
13297
+ */
13298
+ "aoPreDrawCallback": [],
13299
+
13300
+ /**
13301
+ * Callback functions for when the table has been initialised.
13302
+ * @type array
13303
+ * @default []
13304
+ */
13305
+ "aoInitComplete": [],
13306
+
13307
+
13308
+ /**
13309
+ * Callbacks for modifying the settings to be stored for state saving, prior to
13310
+ * saving state.
13311
+ * @type array
13312
+ * @default []
13313
+ */
13314
+ "aoStateSaveParams": [],
13315
+
13316
+ /**
13317
+ * Callbacks for modifying the settings that have been stored for state saving
13318
+ * prior to using the stored values to restore the state.
13319
+ * @type array
13320
+ * @default []
13321
+ */
13322
+ "aoStateLoadParams": [],
13323
+
13324
+ /**
13325
+ * Callbacks for operating on the settings object once the saved state has been
13326
+ * loaded
13327
+ * @type array
13328
+ * @default []
13329
+ */
13330
+ "aoStateLoaded": [],
13331
+
13332
+ /**
13333
+ * Cache the table ID for quick access
13334
+ * @type string
13335
+ * @default <i>Empty string</i>
13336
+ */
13337
+ "sTableId": "",
13338
+
13339
+ /**
13340
+ * The TABLE node for the main table
13341
+ * @type node
13342
+ * @default null
13343
+ */
13344
+ "nTable": null,
13345
+
13346
+ /**
13347
+ * Permanent ref to the thead element
13348
+ * @type node
13349
+ * @default null
13350
+ */
13351
+ "nTHead": null,
13352
+
13353
+ /**
13354
+ * Permanent ref to the tfoot element - if it exists
13355
+ * @type node
13356
+ * @default null
13357
+ */
13358
+ "nTFoot": null,
13359
+
13360
+ /**
13361
+ * Permanent ref to the tbody element
13362
+ * @type node
13363
+ * @default null
13364
+ */
13365
+ "nTBody": null,
13366
+
13367
+ /**
13368
+ * Cache the wrapper node (contains all DataTables controlled elements)
13369
+ * @type node
13370
+ * @default null
13371
+ */
13372
+ "nTableWrapper": null,
13373
+
13374
+ /**
13375
+ * Indicate if when using server-side processing the loading of data
13376
+ * should be deferred until the second draw.
13377
+ * Note that this parameter will be set by the initialisation routine. To
13378
+ * set a default use {@link DataTable.defaults}.
13379
+ * @type boolean
13380
+ * @default false
13381
+ */
13382
+ "bDeferLoading": false,
13383
+
13384
+ /**
13385
+ * Indicate if all required information has been read in
13386
+ * @type boolean
13387
+ * @default false
13388
+ */
13389
+ "bInitialised": false,
13390
+
13391
+ /**
13392
+ * Information about open rows. Each object in the array has the parameters
13393
+ * 'nTr' and 'nParent'
13394
+ * @type array
13395
+ * @default []
13396
+ */
13397
+ "aoOpenRows": [],
13398
+
13399
+ /**
13400
+ * Dictate the positioning of DataTables' control elements - see
13401
+ * {@link DataTable.model.oInit.sDom}.
13402
+ * Note that this parameter will be set by the initialisation routine. To
13403
+ * set a default use {@link DataTable.defaults}.
13404
+ * @type string
13405
+ * @default null
13406
+ */
13407
+ "sDom": null,
13408
+
13409
+ /**
13410
+ * Search delay (in mS)
13411
+ * @type integer
13412
+ * @default null
13413
+ */
13414
+ "searchDelay": null,
13415
+
13416
+ /**
13417
+ * Which type of pagination should be used.
13418
+ * Note that this parameter will be set by the initialisation routine. To
13419
+ * set a default use {@link DataTable.defaults}.
13420
+ * @type string
13421
+ * @default two_button
13422
+ */
13423
+ "sPaginationType": "two_button",
13424
+
13425
+ /**
13426
+ * The state duration (for `stateSave`) in seconds.
13427
+ * Note that this parameter will be set by the initialisation routine. To
13428
+ * set a default use {@link DataTable.defaults}.
13429
+ * @type int
13430
+ * @default 0
13431
+ */
13432
+ "iStateDuration": 0,
13433
+
13434
+ /**
13435
+ * Array of callback functions for state saving. Each array element is an
13436
+ * object with the following parameters:
13437
+ * <ul>
13438
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13439
+ * and the JSON string to save that has been thus far created. Returns
13440
+ * a JSON string to be inserted into a json object
13441
+ * (i.e. '"param": [ 0, 1, 2]')</li>
13442
+ * <li>string:sName - name of callback</li>
13443
+ * </ul>
13444
+ * @type array
13445
+ * @default []
13446
+ */
13447
+ "aoStateSave": [],
13448
+
13449
+ /**
13450
+ * Array of callback functions for state loading. Each array element is an
13451
+ * object with the following parameters:
13452
+ * <ul>
13453
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13454
+ * and the object stored. May return false to cancel state loading</li>
13455
+ * <li>string:sName - name of callback</li>
13456
+ * </ul>
13457
+ * @type array
13458
+ * @default []
13459
+ */
13460
+ "aoStateLoad": [],
13461
+
13462
+ /**
13463
+ * State that was saved. Useful for back reference
13464
+ * @type object
13465
+ * @default null
13466
+ */
13467
+ "oSavedState": null,
13468
+
13469
+ /**
13470
+ * State that was loaded. Useful for back reference
13471
+ * @type object
13472
+ * @default null
13473
+ */
13474
+ "oLoadedState": null,
13475
+
13476
+ /**
13477
+ * Source url for AJAX data for the table.
13478
+ * Note that this parameter will be set by the initialisation routine. To
13479
+ * set a default use {@link DataTable.defaults}.
13480
+ * @type string
13481
+ * @default null
13482
+ */
13483
+ "sAjaxSource": null,
13484
+
13485
+ /**
13486
+ * Property from a given object from which to read the table data from. This
13487
+ * can be an empty string (when not server-side processing), in which case
13488
+ * it is assumed an an array is given directly.
13489
+ * Note that this parameter will be set by the initialisation routine. To
13490
+ * set a default use {@link DataTable.defaults}.
13491
+ * @type string
13492
+ */
13493
+ "sAjaxDataProp": null,
13494
+
13495
+ /**
13496
+ * Note if draw should be blocked while getting data
13497
+ * @type boolean
13498
+ * @default true
13499
+ */
13500
+ "bAjaxDataGet": true,
13501
+
13502
+ /**
13503
+ * The last jQuery XHR object that was used for server-side data gathering.
13504
+ * This can be used for working with the XHR information in one of the
13505
+ * callbacks
13506
+ * @type object
13507
+ * @default null
13508
+ */
13509
+ "jqXHR": null,
13510
+
13511
+ /**
13512
+ * JSON returned from the server in the last Ajax request
13513
+ * @type object
13514
+ * @default undefined
13515
+ */
13516
+ "json": undefined,
13517
+
13518
+ /**
13519
+ * Data submitted as part of the last Ajax request
13520
+ * @type object
13521
+ * @default undefined
13522
+ */
13523
+ "oAjaxData": undefined,
13524
+
13525
+ /**
13526
+ * Function to get the server-side data.
13527
+ * Note that this parameter will be set by the initialisation routine. To
13528
+ * set a default use {@link DataTable.defaults}.
13529
+ * @type function
13530
+ */
13531
+ "fnServerData": null,
13532
+
13533
+ /**
13534
+ * Functions which are called prior to sending an Ajax request so extra
13535
+ * parameters can easily be sent to the server
13536
+ * @type array
13537
+ * @default []
13538
+ */
13539
+ "aoServerParams": [],
13540
+
13541
+ /**
13542
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13543
+ * required).
13544
+ * Note that this parameter will be set by the initialisation routine. To
13545
+ * set a default use {@link DataTable.defaults}.
13546
+ * @type string
13547
+ */
13548
+ "sServerMethod": null,
13549
+
13550
+ /**
13551
+ * Format numbers for display.
13552
+ * Note that this parameter will be set by the initialisation routine. To
13553
+ * set a default use {@link DataTable.defaults}.
13554
+ * @type function
13555
+ */
13556
+ "fnFormatNumber": null,
13557
+
13558
+ /**
13559
+ * List of options that can be used for the user selectable length menu.
13560
+ * Note that this parameter will be set by the initialisation routine. To
13561
+ * set a default use {@link DataTable.defaults}.
13562
+ * @type array
13563
+ * @default []
13564
+ */
13565
+ "aLengthMenu": null,
13566
+
13567
+ /**
13568
+ * Counter for the draws that the table does. Also used as a tracker for
13569
+ * server-side processing
13570
+ * @type int
13571
+ * @default 0
13572
+ */
13573
+ "iDraw": 0,
13574
+
13575
+ /**
13576
+ * Indicate if a redraw is being done - useful for Ajax
13577
+ * @type boolean
13578
+ * @default false
13579
+ */
13580
+ "bDrawing": false,
13581
+
13582
+ /**
13583
+ * Draw index (iDraw) of the last error when parsing the returned data
13584
+ * @type int
13585
+ * @default -1
13586
+ */
13587
+ "iDrawError": -1,
13588
+
13589
+ /**
13590
+ * Paging display length
13591
+ * @type int
13592
+ * @default 10
13593
+ */
13594
+ "_iDisplayLength": 10,
13595
+
13596
+ /**
13597
+ * Paging start point - aiDisplay index
13598
+ * @type int
13599
+ * @default 0
13600
+ */
13601
+ "_iDisplayStart": 0,
13602
+
13603
+ /**
13604
+ * Server-side processing - number of records in the result set
13605
+ * (i.e. before filtering), Use fnRecordsTotal rather than
13606
+ * this property to get the value of the number of records, regardless of
13607
+ * the server-side processing setting.
13608
+ * @type int
13609
+ * @default 0
13610
+ * @private
13611
+ */
13612
+ "_iRecordsTotal": 0,
13613
+
13614
+ /**
13615
+ * Server-side processing - number of records in the current display set
13616
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
13617
+ * this property to get the value of the number of records, regardless of
13618
+ * the server-side processing setting.
13619
+ * @type boolean
13620
+ * @default 0
13621
+ * @private
13622
+ */
13623
+ "_iRecordsDisplay": 0,
13624
+
13625
+ /**
13626
+ * The classes to use for the table
13627
+ * @type object
13628
+ * @default {}
13629
+ */
13630
+ "oClasses": {},
13631
+
13632
+ /**
13633
+ * Flag attached to the settings object so you can check in the draw
13634
+ * callback if filtering has been done in the draw. Deprecated in favour of
13635
+ * events.
13636
+ * @type boolean
13637
+ * @default false
13638
+ * @deprecated
13639
+ */
13640
+ "bFiltered": false,
13641
+
13642
+ /**
13643
+ * Flag attached to the settings object so you can check in the draw
13644
+ * callback if sorting has been done in the draw. Deprecated in favour of
13645
+ * events.
13646
+ * @type boolean
13647
+ * @default false
13648
+ * @deprecated
13649
+ */
13650
+ "bSorted": false,
13651
+
13652
+ /**
13653
+ * Indicate that if multiple rows are in the header and there is more than
13654
+ * one unique cell per column, if the top one (true) or bottom one (false)
13655
+ * should be used for sorting / title by DataTables.
13656
+ * Note that this parameter will be set by the initialisation routine. To
13657
+ * set a default use {@link DataTable.defaults}.
13658
+ * @type boolean
13659
+ */
13660
+ "bSortCellsTop": null,
13661
+
13662
+ /**
13663
+ * Initialisation object that is used for the table
13664
+ * @type object
13665
+ * @default null
13666
+ */
13667
+ "oInit": null,
13668
+
13669
+ /**
13670
+ * Destroy callback functions - for plug-ins to attach themselves to the
13671
+ * destroy so they can clean up markup and events.
13672
+ * @type array
13673
+ * @default []
13674
+ */
13675
+ "aoDestroyCallback": [],
13676
+
13677
+
13678
+ /**
13679
+ * Get the number of records in the current record set, before filtering
13680
+ * @type function
13681
+ */
13682
+ "fnRecordsTotal": function ()
13683
+ {
13684
+ return _fnDataSource( this ) == 'ssp' ?
13685
+ this._iRecordsTotal * 1 :
13686
+ this.aiDisplayMaster.length;
13687
+ },
13688
+
13689
+ /**
13690
+ * Get the number of records in the current record set, after filtering
13691
+ * @type function
13692
+ */
13693
+ "fnRecordsDisplay": function ()
13694
+ {
13695
+ return _fnDataSource( this ) == 'ssp' ?
13696
+ this._iRecordsDisplay * 1 :
13697
+ this.aiDisplay.length;
13698
+ },
13699
+
13700
+ /**
13701
+ * Get the display end point - aiDisplay index
13702
+ * @type function
13703
+ */
13704
+ "fnDisplayEnd": function ()
13705
+ {
13706
+ var
13707
+ len = this._iDisplayLength,
13708
+ start = this._iDisplayStart,
13709
+ calc = start + len,
13710
+ records = this.aiDisplay.length,
13711
+ features = this.oFeatures,
13712
+ paginate = features.bPaginate;
13713
+
13714
+ if ( features.bServerSide ) {
13715
+ return paginate === false || len === -1 ?
13716
+ start + records :
13717
+ Math.min( start+len, this._iRecordsDisplay );
13718
+ }
13719
+ else {
13720
+ return ! paginate || calc>records || len===-1 ?
13721
+ records :
13722
+ calc;
13723
+ }
13724
+ },
13725
+
13726
+ /**
13727
+ * The DataTables object for this table
13728
+ * @type object
13729
+ * @default null
13730
+ */
13731
+ "oInstance": null,
13732
+
13733
+ /**
13734
+ * Unique identifier for each instance of the DataTables object. If there
13735
+ * is an ID on the table node, then it takes that value, otherwise an
13736
+ * incrementing internal counter is used.
13737
+ * @type string
13738
+ * @default null
13739
+ */
13740
+ "sInstance": null,
13741
+
13742
+ /**
13743
+ * tabindex attribute value that is added to DataTables control elements, allowing
13744
+ * keyboard navigation of the table and its controls.
13745
+ */
13746
+ "iTabIndex": 0,
13747
+
13748
+ /**
13749
+ * DIV container for the footer scrolling table if scrolling
13750
+ */
13751
+ "nScrollHead": null,
13752
+
13753
+ /**
13754
+ * DIV container for the footer scrolling table if scrolling
13755
+ */
13756
+ "nScrollFoot": null,
13757
+
13758
+ /**
13759
+ * Last applied sort
13760
+ * @type array
13761
+ * @default []
13762
+ */
13763
+ "aLastSort": [],
13764
+
13765
+ /**
13766
+ * Stored plug-in instances
13767
+ * @type object
13768
+ * @default {}
13769
+ */
13770
+ "oPlugins": {},
13771
+
13772
+ /**
13773
+ * Function used to get a row's id from the row's data
13774
+ * @type function
13775
+ * @default null
13776
+ */
13777
+ "rowIdFn": null,
13778
+
13779
+ /**
13780
+ * Data location where to store a row's id
13781
+ * @type string
13782
+ * @default null
13783
+ */
13784
+ "rowId": null
13785
+ };
13786
+
13787
+ /**
13788
+ * Extension object for DataTables that is used to provide all extension
13789
+ * options.
13790
+ *
13791
+ * Note that the `DataTable.ext` object is available through
13792
+ * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13793
+ * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13794
+ * @namespace
13795
+ * @extends DataTable.models.ext
13796
+ */
13797
+
13798
+
13799
+ /**
13800
+ * DataTables extensions
13801
+ *
13802
+ * This namespace acts as a collection area for plug-ins that can be used to
13803
+ * extend DataTables capabilities. Indeed many of the build in methods
13804
+ * use this method to provide their own capabilities (sorting methods for
13805
+ * example).
13806
+ *
13807
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13808
+ * reasons
13809
+ *
13810
+ * @namespace
13811
+ */
13812
+ DataTable.ext = _ext = {
13813
+ /**
13814
+ * Buttons. For use with the Buttons extension for DataTables. This is
13815
+ * defined here so other extensions can define buttons regardless of load
13816
+ * order. It is _not_ used by DataTables core.
13817
+ *
13818
+ * @type object
13819
+ * @default {}
13820
+ */
13821
+ buttons: {},
13822
+
13823
+
13824
+ /**
13825
+ * Element class names
13826
+ *
13827
+ * @type object
13828
+ * @default {}
13829
+ */
13830
+ classes: {},
13831
+
13832
+
13833
+ /**
13834
+ * DataTables build type (expanded by the download builder)
13835
+ *
13836
+ * @type string
13837
+ */
13838
+ builder: "-source-",
13839
+
13840
+
13841
+ /**
13842
+ * Error reporting.
13843
+ *
13844
+ * How should DataTables report an error. Can take the value 'alert',
13845
+ * 'throw', 'none' or a function.
13846
+ *
13847
+ * @type string|function
13848
+ * @default alert
13849
+ */
13850
+ errMode: "alert",
13851
+
13852
+
13853
+ /**
13854
+ * Feature plug-ins.
13855
+ *
13856
+ * This is an array of objects which describe the feature plug-ins that are
13857
+ * available to DataTables. These feature plug-ins are then available for
13858
+ * use through the `dom` initialisation option.
13859
+ *
13860
+ * Each feature plug-in is described by an object which must have the
13861
+ * following properties:
13862
+ *
13863
+ * * `fnInit` - function that is used to initialise the plug-in,
13864
+ * * `cFeature` - a character so the feature can be enabled by the `dom`
13865
+ * instillation option. This is case sensitive.
13866
+ *
13867
+ * The `fnInit` function has the following input parameters:
13868
+ *
13869
+ * 1. `{object}` DataTables settings object: see
13870
+ * {@link DataTable.models.oSettings}
13871
+ *
13872
+ * And the following return is expected:
13873
+ *
13874
+ * * {node|null} The element which contains your feature. Note that the
13875
+ * return may also be void if your plug-in does not require to inject any
13876
+ * DOM elements into DataTables control (`dom`) - for example this might
13877
+ * be useful when developing a plug-in which allows table control via
13878
+ * keyboard entry
13879
+ *
13880
+ * @type array
13881
+ *
13882
+ * @example
13883
+ * $.fn.dataTable.ext.features.push( {
13884
+ * "fnInit": function( oSettings ) {
13885
+ * return new TableTools( { "oDTSettings": oSettings } );
13886
+ * },
13887
+ * "cFeature": "T"
13888
+ * } );
13889
+ */
13890
+ feature: [],
13891
+
13892
+
13893
+ /**
13894
+ * Row searching.
13895
+ *
13896
+ * This method of searching is complimentary to the default type based
13897
+ * searching, and a lot more comprehensive as it allows you complete control
13898
+ * over the searching logic. Each element in this array is a function
13899
+ * (parameters described below) that is called for every row in the table,
13900
+ * and your logic decides if it should be included in the searching data set
13901
+ * or not.
13902
+ *
13903
+ * Searching functions have the following input parameters:
13904
+ *
13905
+ * 1. `{object}` DataTables settings object: see
13906
+ * {@link DataTable.models.oSettings}
13907
+ * 2. `{array|object}` Data for the row to be processed (same as the
13908
+ * original format that was passed in as the data source, or an array
13909
+ * from a DOM data source
13910
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13911
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
13912
+ *
13913
+ * And the following return is expected:
13914
+ *
13915
+ * * {boolean} Include the row in the searched result set (true) or not
13916
+ * (false)
13917
+ *
13918
+ * Note that as with the main search ability in DataTables, technically this
13919
+ * is "filtering", since it is subtractive. However, for consistency in
13920
+ * naming we call it searching here.
13921
+ *
13922
+ * @type array
13923
+ * @default []
13924
+ *
13925
+ * @example
13926
+ * // The following example shows custom search being applied to the
13927
+ * // fourth column (i.e. the data[3] index) based on two input values
13928
+ * // from the end-user, matching the data in a certain range.
13929
+ * $.fn.dataTable.ext.search.push(
13930
+ * function( settings, data, dataIndex ) {
13931
+ * var min = document.getElementById('min').value * 1;
13932
+ * var max = document.getElementById('max').value * 1;
13933
+ * var version = data[3] == "-" ? 0 : data[3]*1;
13934
+ *
13935
+ * if ( min == "" && max == "" ) {
13936
+ * return true;
13937
+ * }
13938
+ * else if ( min == "" && version < max ) {
13939
+ * return true;
13940
+ * }
13941
+ * else if ( min < version && "" == max ) {
13942
+ * return true;
13943
+ * }
13944
+ * else if ( min < version && version < max ) {
13945
+ * return true;
13946
+ * }
13947
+ * return false;
13948
+ * }
13949
+ * );
13950
+ */
13951
+ search: [],
13952
+
13953
+
13954
+ /**
13955
+ * Selector extensions
13956
+ *
13957
+ * The `selector` option can be used to extend the options available for the
13958
+ * selector modifier options (`selector-modifier` object data type) that
13959
+ * each of the three built in selector types offer (row, column and cell +
13960
+ * their plural counterparts). For example the Select extension uses this
13961
+ * mechanism to provide an option to select only rows, columns and cells
13962
+ * that have been marked as selected by the end user (`{selected: true}`),
13963
+ * which can be used in conjunction with the existing built in selector
13964
+ * options.
13965
+ *
13966
+ * Each property is an array to which functions can be pushed. The functions
13967
+ * take three attributes:
13968
+ *
13969
+ * * Settings object for the host table
13970
+ * * Options object (`selector-modifier` object type)
13971
+ * * Array of selected item indexes
13972
+ *
13973
+ * The return is an array of the resulting item indexes after the custom
13974
+ * selector has been applied.
13975
+ *
13976
+ * @type object
13977
+ */
13978
+ selector: {
13979
+ cell: [],
13980
+ column: [],
13981
+ row: []
13982
+ },
13983
+
13984
+
13985
+ /**
13986
+ * Internal functions, exposed for used in plug-ins.
13987
+ *
13988
+ * Please note that you should not need to use the internal methods for
13989
+ * anything other than a plug-in (and even then, try to avoid if possible).
13990
+ * The internal function may change between releases.
13991
+ *
13992
+ * @type object
13993
+ * @default {}
13994
+ */
13995
+ internal: {},
13996
+
13997
+
13998
+ /**
13999
+ * Legacy configuration options. Enable and disable legacy options that
14000
+ * are available in DataTables.
14001
+ *
14002
+ * @type object
14003
+ */
14004
+ legacy: {
14005
+ /**
14006
+ * Enable / disable DataTables 1.9 compatible server-side processing
14007
+ * requests
14008
+ *
14009
+ * @type boolean
14010
+ * @default null
14011
+ */
14012
+ ajax: null
14013
+ },
14014
+
14015
+
14016
+ /**
14017
+ * Pagination plug-in methods.
14018
+ *
14019
+ * Each entry in this object is a function and defines which buttons should
14020
+ * be shown by the pagination rendering method that is used for the table:
14021
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
14022
+ * buttons are displayed in the document, while the functions here tell it
14023
+ * what buttons to display. This is done by returning an array of button
14024
+ * descriptions (what each button will do).
14025
+ *
14026
+ * Pagination types (the four built in options and any additional plug-in
14027
+ * options defined here) can be used through the `paginationType`
14028
+ * initialisation parameter.
14029
+ *
14030
+ * The functions defined take two parameters:
14031
+ *
14032
+ * 1. `{int} page` The current page index
14033
+ * 2. `{int} pages` The number of pages in the table
14034
+ *
14035
+ * Each function is expected to return an array where each element of the
14036
+ * array can be one of:
14037
+ *
14038
+ * * `first` - Jump to first page when activated
14039
+ * * `last` - Jump to last page when activated
14040
+ * * `previous` - Show previous page when activated
14041
+ * * `next` - Show next page when activated
14042
+ * * `{int}` - Show page of the index given
14043
+ * * `{array}` - A nested array containing the above elements to add a
14044
+ * containing 'DIV' element (might be useful for styling).
14045
+ *
14046
+ * Note that DataTables v1.9- used this object slightly differently whereby
14047
+ * an object with two functions would be defined for each plug-in. That
14048
+ * ability is still supported by DataTables 1.10+ to provide backwards
14049
+ * compatibility, but this option of use is now decremented and no longer
14050
+ * documented in DataTables 1.10+.
14051
+ *
14052
+ * @type object
14053
+ * @default {}
14054
+ *
14055
+ * @example
14056
+ * // Show previous, next and current page buttons only
14057
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
14058
+ * return [ 'previous', page, 'next' ];
14059
+ * };
14060
+ */
14061
+ pager: {},
14062
+
14063
+
14064
+ renderer: {
14065
+ pageButton: {},
14066
+ header: {}
14067
+ },
14068
+
14069
+
14070
+ /**
14071
+ * Ordering plug-ins - custom data source
14072
+ *
14073
+ * The extension options for ordering of data available here is complimentary
14074
+ * to the default type based ordering that DataTables typically uses. It
14075
+ * allows much greater control over the the data that is being used to
14076
+ * order a column, but is necessarily therefore more complex.
14077
+ *
14078
+ * This type of ordering is useful if you want to do ordering based on data
14079
+ * live from the DOM (for example the contents of an 'input' element) rather
14080
+ * than just the static string that DataTables knows of.
14081
+ *
14082
+ * The way these plug-ins work is that you create an array of the values you
14083
+ * wish to be ordering for the column in question and then return that
14084
+ * array. The data in the array much be in the index order of the rows in
14085
+ * the table (not the currently ordering order!). Which order data gathering
14086
+ * function is run here depends on the `dt-init columns.orderDataType`
14087
+ * parameter that is used for the column (if any).
14088
+ *
14089
+ * The functions defined take two parameters:
14090
+ *
14091
+ * 1. `{object}` DataTables settings object: see
14092
+ * {@link DataTable.models.oSettings}
14093
+ * 2. `{int}` Target column index
14094
+ *
14095
+ * Each function is expected to return an array:
14096
+ *
14097
+ * * `{array}` Data for the column to be ordering upon
14098
+ *
14099
+ * @type array
14100
+ *
14101
+ * @example
14102
+ * // Ordering using `input` node values
14103
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
14104
+ * {
14105
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
14106
+ * return $('input', td).val();
14107
+ * } );
14108
+ * }
14109
+ */
14110
+ order: {},
14111
+
14112
+
14113
+ /**
14114
+ * Type based plug-ins.
14115
+ *
14116
+ * Each column in DataTables has a type assigned to it, either by automatic
14117
+ * detection or by direct assignment using the `type` option for the column.
14118
+ * The type of a column will effect how it is ordering and search (plug-ins
14119
+ * can also make use of the column type if required).
14120
+ *
14121
+ * @namespace
14122
+ */
14123
+ type: {
14124
+ /**
14125
+ * Type detection functions.
14126
+ *
14127
+ * The functions defined in this object are used to automatically detect
14128
+ * a column's type, making initialisation of DataTables super easy, even
14129
+ * when complex data is in the table.
14130
+ *
14131
+ * The functions defined take two parameters:
14132
+ *
14133
+ * 1. `{*}` Data from the column cell to be analysed
14134
+ * 2. `{settings}` DataTables settings object. This can be used to
14135
+ * perform context specific type detection - for example detection
14136
+ * based on language settings such as using a comma for a decimal
14137
+ * place. Generally speaking the options from the settings will not
14138
+ * be required
14139
+ *
14140
+ * Each function is expected to return:
14141
+ *
14142
+ * * `{string|null}` Data type detected, or null if unknown (and thus
14143
+ * pass it on to the other type detection functions.
14144
+ *
14145
+ * @type array
14146
+ *
14147
+ * @example
14148
+ * // Currency type detection plug-in:
14149
+ * $.fn.dataTable.ext.type.detect.push(
14150
+ * function ( data, settings ) {
14151
+ * // Check the numeric part
14152
+ * if ( ! $.isNumeric( data.substring(1) ) ) {
14153
+ * return null;
14154
+ * }
14155
+ *
14156
+ * // Check prefixed by currency
14157
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
14158
+ * return 'currency';
14159
+ * }
14160
+ * return null;
14161
+ * }
14162
+ * );
14163
+ */
14164
+ detect: [],
14165
+
14166
+
14167
+ /**
14168
+ * Type based search formatting.
14169
+ *
14170
+ * The type based searching functions can be used to pre-format the
14171
+ * data to be search on. For example, it can be used to strip HTML
14172
+ * tags or to de-format telephone numbers for numeric only searching.
14173
+ *
14174
+ * Note that is a search is not defined for a column of a given type,
14175
+ * no search formatting will be performed.
14176
+ *
14177
+ * Pre-processing of searching data plug-ins - When you assign the sType
14178
+ * for a column (or have it automatically detected for you by DataTables
14179
+ * or a type detection plug-in), you will typically be using this for
14180
+ * custom sorting, but it can also be used to provide custom searching
14181
+ * by allowing you to pre-processing the data and returning the data in
14182
+ * the format that should be searched upon. This is done by adding
14183
+ * functions this object with a parameter name which matches the sType
14184
+ * for that target column. This is the corollary of <i>afnSortData</i>
14185
+ * for searching data.
14186
+ *
14187
+ * The functions defined take a single parameter:
14188
+ *
14189
+ * 1. `{*}` Data from the column cell to be prepared for searching
14190
+ *
14191
+ * Each function is expected to return:
14192
+ *
14193
+ * * `{string|null}` Formatted string that will be used for the searching.
14194
+ *
14195
+ * @type object
14196
+ * @default {}
14197
+ *
14198
+ * @example
14199
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
14200
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
14201
+ * }
14202
+ */
14203
+ search: {},
14204
+
14205
+
14206
+ /**
14207
+ * Type based ordering.
14208
+ *
14209
+ * The column type tells DataTables what ordering to apply to the table
14210
+ * when a column is sorted upon. The order for each type that is defined,
14211
+ * is defined by the functions available in this object.
14212
+ *
14213
+ * Each ordering option can be described by three properties added to
14214
+ * this object:
14215
+ *
14216
+ * * `{type}-pre` - Pre-formatting function
14217
+ * * `{type}-asc` - Ascending order function
14218
+ * * `{type}-desc` - Descending order function
14219
+ *
14220
+ * All three can be used together, only `{type}-pre` or only
14221
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
14222
+ * that only `{type}-pre` is used, as this provides the optimal
14223
+ * implementation in terms of speed, although the others are provided
14224
+ * for compatibility with existing Javascript sort functions.
14225
+ *
14226
+ * `{type}-pre`: Functions defined take a single parameter:
14227
+ *
14228
+ * 1. `{*}` Data from the column cell to be prepared for ordering
14229
+ *
14230
+ * And return:
14231
+ *
14232
+ * * `{*}` Data to be sorted upon
14233
+ *
14234
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
14235
+ * functions, taking two parameters:
14236
+ *
14237
+ * 1. `{*}` Data to compare to the second parameter
14238
+ * 2. `{*}` Data to compare to the first parameter
14239
+ *
14240
+ * And returning:
14241
+ *
14242
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
14243
+ * than the second parameter, ===0 if the two parameters are equal and
14244
+ * >0 if the first parameter should be sorted height than the second
14245
+ * parameter.
14246
+ *
14247
+ * @type object
14248
+ * @default {}
14249
+ *
14250
+ * @example
14251
+ * // Numeric ordering of formatted numbers with a pre-formatter
14252
+ * $.extend( $.fn.dataTable.ext.type.order, {
14253
+ * "string-pre": function(x) {
14254
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
14255
+ * return parseFloat( a );
14256
+ * }
14257
+ * } );
14258
+ *
14259
+ * @example
14260
+ * // Case-sensitive string ordering, with no pre-formatting method
14261
+ * $.extend( $.fn.dataTable.ext.order, {
14262
+ * "string-case-asc": function(x,y) {
14263
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14264
+ * },
14265
+ * "string-case-desc": function(x,y) {
14266
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14267
+ * }
14268
+ * } );
14269
+ */
14270
+ order: {}
14271
+ },
14272
+
14273
+ /**
14274
+ * Unique DataTables instance counter
14275
+ *
14276
+ * @type int
14277
+ * @private
14278
+ */
14279
+ _unique: 0,
14280
+
14281
+
14282
+ //
14283
+ // Depreciated
14284
+ // The following properties are retained for backwards compatiblity only.
14285
+ // The should not be used in new projects and will be removed in a future
14286
+ // version
14287
+ //
14288
+
14289
+ /**
14290
+ * Version check function.
14291
+ * @type function
14292
+ * @depreciated Since 1.10
14293
+ */
14294
+ fnVersionCheck: DataTable.fnVersionCheck,
14295
+
14296
+
14297
+ /**
14298
+ * Index for what 'this' index API functions should use
14299
+ * @type int
14300
+ * @deprecated Since v1.10
14301
+ */
14302
+ iApiIndex: 0,
14303
+
14304
+
14305
+ /**
14306
+ * jQuery UI class container
14307
+ * @type object
14308
+ * @deprecated Since v1.10
14309
+ */
14310
+ oJUIClasses: {},
14311
+
14312
+
14313
+ /**
14314
+ * Software version
14315
+ * @type string
14316
+ * @deprecated Since v1.10
14317
+ */
14318
+ sVersion: DataTable.version
14319
+ };
14320
+
14321
+
14322
+ //
14323
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
14324
+ //
14325
+ $.extend( _ext, {
14326
+ afnFiltering: _ext.search,
14327
+ aTypes: _ext.type.detect,
14328
+ ofnSearch: _ext.type.search,
14329
+ oSort: _ext.type.order,
14330
+ afnSortData: _ext.order,
14331
+ aoFeatures: _ext.feature,
14332
+ oApi: _ext.internal,
14333
+ oStdClasses: _ext.classes,
14334
+ oPagination: _ext.pager
14335
+ } );
14336
+
14337
+
14338
+ $.extend( DataTable.ext.classes, {
14339
+ "sTable": "dataTable",
14340
+ "sNoFooter": "no-footer",
14341
+
14342
+ /* Paging buttons */
14343
+ "sPageButton": "paginate_button",
14344
+ "sPageButtonActive": "current",
14345
+ "sPageButtonDisabled": "disabled",
14346
+
14347
+ /* Striping classes */
14348
+ "sStripeOdd": "odd",
14349
+ "sStripeEven": "even",
14350
+
14351
+ /* Empty row */
14352
+ "sRowEmpty": "dataTables_empty",
14353
+
14354
+ /* Features */
14355
+ "sWrapper": "dataTables_wrapper",
14356
+ "sFilter": "dataTables_filter",
14357
+ "sInfo": "dataTables_info",
14358
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
14359
+ "sLength": "dataTables_length",
14360
+ "sProcessing": "dataTables_processing",
14361
+
14362
+ /* Sorting */
14363
+ "sSortAsc": "sorting_asc",
14364
+ "sSortDesc": "sorting_desc",
14365
+ "sSortable": "sorting", /* Sortable in both directions */
14366
+ "sSortableAsc": "sorting_asc_disabled",
14367
+ "sSortableDesc": "sorting_desc_disabled",
14368
+ "sSortableNone": "sorting_disabled",
14369
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
14370
+
14371
+ /* Filtering */
14372
+ "sFilterInput": "",
14373
+
14374
+ /* Page length */
14375
+ "sLengthSelect": "",
14376
+
14377
+ /* Scrolling */
14378
+ "sScrollWrapper": "dataTables_scroll",
14379
+ "sScrollHead": "dataTables_scrollHead",
14380
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
14381
+ "sScrollBody": "dataTables_scrollBody",
14382
+ "sScrollFoot": "dataTables_scrollFoot",
14383
+ "sScrollFootInner": "dataTables_scrollFootInner",
14384
+
14385
+ /* Misc */
14386
+ "sHeaderTH": "",
14387
+ "sFooterTH": "",
14388
+
14389
+ // Deprecated
14390
+ "sSortJUIAsc": "",
14391
+ "sSortJUIDesc": "",
14392
+ "sSortJUI": "",
14393
+ "sSortJUIAscAllowed": "",
14394
+ "sSortJUIDescAllowed": "",
14395
+ "sSortJUIWrapper": "",
14396
+ "sSortIcon": "",
14397
+ "sJUIHeader": "",
14398
+ "sJUIFooter": ""
14399
+ } );
14400
+
14401
+
14402
+ var extPagination = DataTable.ext.pager;
14403
+
14404
+ function _numbers ( page, pages ) {
14405
+ var
14406
+ numbers = [],
14407
+ buttons = extPagination.numbers_length,
14408
+ half = Math.floor( buttons / 2 ),
14409
+ i = 1;
14410
+
14411
+ if ( pages <= buttons ) {
14412
+ numbers = _range( 0, pages );
14413
+ }
14414
+ else if ( page <= half ) {
14415
+ numbers = _range( 0, buttons-2 );
14416
+ numbers.push( 'ellipsis' );
14417
+ numbers.push( pages-1 );
14418
+ }
14419
+ else if ( page >= pages - 1 - half ) {
14420
+ numbers = _range( pages-(buttons-2), pages );
14421
+ numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14422
+ numbers.splice( 0, 0, 0 );
14423
+ }
14424
+ else {
14425
+ numbers = _range( page-half+2, page+half-1 );
14426
+ numbers.push( 'ellipsis' );
14427
+ numbers.push( pages-1 );
14428
+ numbers.splice( 0, 0, 'ellipsis' );
14429
+ numbers.splice( 0, 0, 0 );
14430
+ }
14431
+
14432
+ numbers.DT_el = 'span';
14433
+ return numbers;
14434
+ }
14435
+
14436
+
14437
+ $.extend( extPagination, {
14438
+ simple: function ( page, pages ) {
14439
+ return [ 'previous', 'next' ];
14440
+ },
14441
+
14442
+ full: function ( page, pages ) {
14443
+ return [ 'first', 'previous', 'next', 'last' ];
14444
+ },
14445
+
14446
+ numbers: function ( page, pages ) {
14447
+ return [ _numbers(page, pages) ];
14448
+ },
14449
+
14450
+ simple_numbers: function ( page, pages ) {
14451
+ return [ 'previous', _numbers(page, pages), 'next' ];
14452
+ },
14453
+
14454
+ full_numbers: function ( page, pages ) {
14455
+ return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14456
+ },
14457
+
14458
+ first_last_numbers: function (page, pages) {
14459
+ return ['first', _numbers(page, pages), 'last'];
14460
+ },
14461
+
14462
+ // For testing and plug-ins to use
14463
+ _numbers: _numbers,
14464
+
14465
+ // Number of number buttons (including ellipsis) to show. _Must be odd!_
14466
+ numbers_length: 7
14467
+ } );
14468
+
14469
+
14470
+ $.extend( true, DataTable.ext.renderer, {
14471
+ pageButton: {
14472
+ _: function ( settings, host, idx, buttons, page, pages ) {
14473
+ var classes = settings.oClasses;
14474
+ var lang = settings.oLanguage.oPaginate;
14475
+ var aria = settings.oLanguage.oAria.paginate || {};
14476
+ var btnDisplay, btnClass, counter=0;
14477
+
14478
+ var attach = function( container, buttons ) {
14479
+ var i, ien, node, button;
14480
+ var clickHandler = function ( e ) {
14481
+ _fnPageChange( settings, e.data.action, true );
14482
+ };
14483
+
14484
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14485
+ button = buttons[i];
14486
+
14487
+ if ( $.isArray( button ) ) {
14488
+ var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14489
+ .appendTo( container );
14490
+ attach( inner, button );
14491
+ }
14492
+ else {
14493
+ btnDisplay = null;
14494
+ btnClass = '';
14495
+
14496
+ switch ( button ) {
14497
+ case 'ellipsis':
14498
+ container.append('<span class="ellipsis">&#x2026;</span>');
14499
+ break;
14500
+
14501
+ case 'first':
14502
+ btnDisplay = lang.sFirst;
14503
+ btnClass = button + (page > 0 ?
14504
+ '' : ' '+classes.sPageButtonDisabled);
14505
+ break;
14506
+
14507
+ case 'previous':
14508
+ btnDisplay = lang.sPrevious;
14509
+ btnClass = button + (page > 0 ?
14510
+ '' : ' '+classes.sPageButtonDisabled);
14511
+ break;
14512
+
14513
+ case 'next':
14514
+ btnDisplay = lang.sNext;
14515
+ btnClass = button + (page < pages-1 ?
14516
+ '' : ' '+classes.sPageButtonDisabled);
14517
+ break;
14518
+
14519
+ case 'last':
14520
+ btnDisplay = lang.sLast;
14521
+ btnClass = button + (page < pages-1 ?
14522
+ '' : ' '+classes.sPageButtonDisabled);
14523
+ break;
14524
+
14525
+ default:
14526
+ btnDisplay = button + 1;
14527
+ btnClass = page === button ?
14528
+ classes.sPageButtonActive : '';
14529
+ break;
14530
+ }
14531
+
14532
+ if ( btnDisplay !== null ) {
14533
+ node = $('<a>', {
14534
+ 'class': classes.sPageButton+' '+btnClass,
14535
+ 'aria-controls': settings.sTableId,
14536
+ 'aria-label': aria[ button ],
14537
+ 'data-dt-idx': counter,
14538
+ 'tabindex': settings.iTabIndex,
14539
+ 'id': idx === 0 && typeof button === 'string' ?
14540
+ settings.sTableId +'_'+ button :
14541
+ null
14542
+ } )
14543
+ .html( btnDisplay )
14544
+ .appendTo( container );
14545
+
14546
+ _fnBindAction(
14547
+ node, {action: button}, clickHandler
14548
+ );
14549
+
14550
+ counter++;
14551
+ }
14552
+ }
14553
+ }
14554
+ };
14555
+
14556
+ // IE9 throws an 'unknown error' if document.activeElement is used
14557
+ // inside an iframe or frame. Try / catch the error. Not good for
14558
+ // accessibility, but neither are frames.
14559
+ var activeEl;
14560
+
14561
+ try {
14562
+ // Because this approach is destroying and recreating the paging
14563
+ // elements, focus is lost on the select button which is bad for
14564
+ // accessibility. So we want to restore focus once the draw has
14565
+ // completed
14566
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
14567
+ }
14568
+ catch (e) {}
14569
+
14570
+ attach( $(host).empty(), buttons );
14571
+
14572
+ if ( activeEl !== undefined ) {
14573
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14574
+ }
14575
+ }
14576
+ }
14577
+ } );
14578
+
14579
+
14580
+
14581
+ // Built in type detection. See model.ext.aTypes for information about
14582
+ // what is required from this methods.
14583
+ $.extend( DataTable.ext.type.detect, [
14584
+ // Plain numbers - first since V8 detects some plain numbers as dates
14585
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14586
+ function ( d, settings )
14587
+ {
14588
+ var decimal = settings.oLanguage.sDecimal;
14589
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14590
+ },
14591
+
14592
+ // Dates (only those recognised by the browser's Date.parse)
14593
+ function ( d, settings )
14594
+ {
14595
+ // V8 tries _very_ hard to make a string passed into `Date.parse()`
14596
+ // valid, so we need to use a regex to restrict date formats. Use a
14597
+ // plug-in for anything other than ISO8601 style strings
14598
+ if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
14599
+ return null;
14600
+ }
14601
+ var parsed = Date.parse(d);
14602
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14603
+ },
14604
+
14605
+ // Formatted numbers
14606
+ function ( d, settings )
14607
+ {
14608
+ var decimal = settings.oLanguage.sDecimal;
14609
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14610
+ },
14611
+
14612
+ // HTML numeric
14613
+ function ( d, settings )
14614
+ {
14615
+ var decimal = settings.oLanguage.sDecimal;
14616
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14617
+ },
14618
+
14619
+ // HTML numeric, formatted
14620
+ function ( d, settings )
14621
+ {
14622
+ var decimal = settings.oLanguage.sDecimal;
14623
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14624
+ },
14625
+
14626
+ // HTML (this is strict checking - there must be html)
14627
+ function ( d, settings )
14628
+ {
14629
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14630
+ 'html' : null;
14631
+ }
14632
+ ] );
14633
+
14634
+
14635
+
14636
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14637
+ // what is required from these methods.
14638
+ //
14639
+ // Note that additional search methods are added for the html numbers and
14640
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
14641
+ // place is
14642
+
14643
+
14644
+ $.extend( DataTable.ext.type.search, {
14645
+ html: function ( data ) {
14646
+ return _empty(data) ?
14647
+ data :
14648
+ typeof data === 'string' ?
14649
+ data
14650
+ .replace( _re_new_lines, " " )
14651
+ .replace( _re_html, "" ) :
14652
+ '';
14653
+ },
14654
+
14655
+ string: function ( data ) {
14656
+ return _empty(data) ?
14657
+ data :
14658
+ typeof data === 'string' ?
14659
+ data.replace( _re_new_lines, " " ) :
14660
+ data;
14661
+ }
14662
+ } );
14663
+
14664
+
14665
+
14666
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14667
+ if ( d !== 0 && (!d || d === '-') ) {
14668
+ return -Infinity;
14669
+ }
14670
+
14671
+ // If a decimal place other than `.` is used, it needs to be given to the
14672
+ // function so we can detect it and replace with a `.` which is the only
14673
+ // decimal place Javascript recognises - it is not locale aware.
14674
+ if ( decimalPlace ) {
14675
+ d = _numToDecimal( d, decimalPlace );
14676
+ }
14677
+
14678
+ if ( d.replace ) {
14679
+ if ( re1 ) {
14680
+ d = d.replace( re1, '' );
14681
+ }
14682
+
14683
+ if ( re2 ) {
14684
+ d = d.replace( re2, '' );
14685
+ }
14686
+ }
14687
+
14688
+ return d * 1;
14689
+ };
14690
+
14691
+
14692
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
14693
+ // in a function to provide an easy ability for the language options to add
14694
+ // additional methods if a non-period decimal place is used.
14695
+ function _addNumericSort ( decimalPlace ) {
14696
+ $.each(
14697
+ {
14698
+ // Plain numbers
14699
+ "num": function ( d ) {
14700
+ return __numericReplace( d, decimalPlace );
14701
+ },
14702
+
14703
+ // Formatted numbers
14704
+ "num-fmt": function ( d ) {
14705
+ return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14706
+ },
14707
+
14708
+ // HTML numeric
14709
+ "html-num": function ( d ) {
14710
+ return __numericReplace( d, decimalPlace, _re_html );
14711
+ },
14712
+
14713
+ // HTML numeric, formatted
14714
+ "html-num-fmt": function ( d ) {
14715
+ return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14716
+ }
14717
+ },
14718
+ function ( key, fn ) {
14719
+ // Add the ordering method
14720
+ _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14721
+
14722
+ // For HTML types add a search formatter that will strip the HTML
14723
+ if ( key.match(/^html\-/) ) {
14724
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14725
+ }
14726
+ }
14727
+ );
14728
+ }
14729
+
14730
+
14731
+ // Default sort methods
14732
+ $.extend( _ext.type.order, {
14733
+ // Dates
14734
+ "date-pre": function ( d ) {
14735
+ return Date.parse( d ) || -Infinity;
14736
+ },
14737
+
14738
+ // html
14739
+ "html-pre": function ( a ) {
14740
+ return _empty(a) ?
14741
+ '' :
14742
+ a.replace ?
14743
+ a.replace( /<.*?>/g, "" ).toLowerCase() :
14744
+ a+'';
14745
+ },
14746
+
14747
+ // string
14748
+ "string-pre": function ( a ) {
14749
+ // This is a little complex, but faster than always calling toString,
14750
+ // http://jsperf.com/tostring-v-check
14751
+ return _empty(a) ?
14752
+ '' :
14753
+ typeof a === 'string' ?
14754
+ a.toLowerCase() :
14755
+ ! a.toString ?
14756
+ '' :
14757
+ a.toString();
14758
+ },
14759
+
14760
+ // string-asc and -desc are retained only for compatibility with the old
14761
+ // sort methods
14762
+ "string-asc": function ( x, y ) {
14763
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14764
+ },
14765
+
14766
+ "string-desc": function ( x, y ) {
14767
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14768
+ }
14769
+ } );
14770
+
14771
+
14772
+ // Numeric sorting types - order doesn't matter here
14773
+ _addNumericSort( '' );
14774
+
14775
+
14776
+ $.extend( true, DataTable.ext.renderer, {
14777
+ header: {
14778
+ _: function ( settings, cell, column, classes ) {
14779
+ // No additional mark-up required
14780
+ // Attach a sort listener to update on sort - note that using the
14781
+ // `DT` namespace will allow the event to be removed automatically
14782
+ // on destroy, while the `dt` namespaced event is the one we are
14783
+ // listening for
14784
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14785
+ if ( settings !== ctx ) { // need to check this this is the host
14786
+ return; // table, not a nested one
14787
+ }
14788
+
14789
+ var colIdx = column.idx;
14790
+
14791
+ cell
14792
+ .removeClass(
14793
+ column.sSortingClass +' '+
14794
+ classes.sSortAsc +' '+
14795
+ classes.sSortDesc
14796
+ )
14797
+ .addClass( columns[ colIdx ] == 'asc' ?
14798
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14799
+ classes.sSortDesc :
14800
+ column.sSortingClass
14801
+ );
14802
+ } );
14803
+ },
14804
+
14805
+ jqueryui: function ( settings, cell, column, classes ) {
14806
+ $('<div/>')
14807
+ .addClass( classes.sSortJUIWrapper )
14808
+ .append( cell.contents() )
14809
+ .append( $('<span/>')
14810
+ .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14811
+ )
14812
+ .appendTo( cell );
14813
+
14814
+ // Attach a sort listener to update on sort
14815
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14816
+ if ( settings !== ctx ) {
14817
+ return;
14818
+ }
14819
+
14820
+ var colIdx = column.idx;
14821
+
14822
+ cell
14823
+ .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14824
+ .addClass( columns[ colIdx ] == 'asc' ?
14825
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14826
+ classes.sSortDesc :
14827
+ column.sSortingClass
14828
+ );
14829
+
14830
+ cell
14831
+ .find( 'span.'+classes.sSortIcon )
14832
+ .removeClass(
14833
+ classes.sSortJUIAsc +" "+
14834
+ classes.sSortJUIDesc +" "+
14835
+ classes.sSortJUI +" "+
14836
+ classes.sSortJUIAscAllowed +" "+
14837
+ classes.sSortJUIDescAllowed
14838
+ )
14839
+ .addClass( columns[ colIdx ] == 'asc' ?
14840
+ classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14841
+ classes.sSortJUIDesc :
14842
+ column.sSortingClassJUI
14843
+ );
14844
+ } );
14845
+ }
14846
+ }
14847
+ } );
14848
+
14849
+ /*
14850
+ * Public helper functions. These aren't used internally by DataTables, or
14851
+ * called by any of the options passed into DataTables, but they can be used
14852
+ * externally by developers working with DataTables. They are helper functions
14853
+ * to make working with DataTables a little bit easier.
14854
+ */
14855
+
14856
+ var __htmlEscapeEntities = function ( d ) {
14857
+ return typeof d === 'string' ?
14858
+ d.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') :
14859
+ d;
14860
+ };
14861
+
14862
+ /**
14863
+ * Helpers for `columns.render`.
14864
+ *
14865
+ * The options defined here can be used with the `columns.render` initialisation
14866
+ * option to provide a display renderer. The following functions are defined:
14867
+ *
14868
+ * * `number` - Will format numeric data (defined by `columns.data`) for
14869
+ * display, retaining the original unformatted data for sorting and filtering.
14870
+ * It takes 5 parameters:
14871
+ * * `string` - Thousands grouping separator
14872
+ * * `string` - Decimal point indicator
14873
+ * * `integer` - Number of decimal points to show
14874
+ * * `string` (optional) - Prefix.
14875
+ * * `string` (optional) - Postfix (/suffix).
14876
+ * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
14877
+ * parameters.
14878
+ *
14879
+ * @example
14880
+ * // Column definition using the number renderer
14881
+ * {
14882
+ * data: "salary",
14883
+ * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14884
+ * }
14885
+ *
14886
+ * @namespace
14887
+ */
14888
+ DataTable.render = {
14889
+ number: function ( thousands, decimal, precision, prefix, postfix ) {
14890
+ return {
14891
+ display: function ( d ) {
14892
+ if ( typeof d !== 'number' && typeof d !== 'string' ) {
14893
+ return d;
14894
+ }
14895
+
14896
+ var negative = d < 0 ? '-' : '';
14897
+ var flo = parseFloat( d );
14898
+
14899
+ // If NaN then there isn't much formatting that we can do - just
14900
+ // return immediately, escaping any HTML (this was supposed to
14901
+ // be a number after all)
14902
+ if ( isNaN( flo ) ) {
14903
+ return __htmlEscapeEntities( d );
14904
+ }
14905
+
14906
+ flo = flo.toFixed( precision );
14907
+ d = Math.abs( flo );
14908
+
14909
+ var intPart = parseInt( d, 10 );
14910
+ var floatPart = precision ?
14911
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14912
+ '';
14913
+
14914
+ return negative + (prefix||'') +
14915
+ intPart.toString().replace(
14916
+ /\B(?=(\d{3})+(?!\d))/g, thousands
14917
+ ) +
14918
+ floatPart +
14919
+ (postfix||'');
14920
+ }
14921
+ };
14922
+ },
14923
+
14924
+ text: function () {
14925
+ return {
14926
+ display: __htmlEscapeEntities
14927
+ };
14928
+ }
14929
+ };
14930
+
14931
+
14932
+ /*
14933
+ * This is really a good bit rubbish this method of exposing the internal methods
14934
+ * publicly... - To be fixed in 2.0 using methods on the prototype
14935
+ */
14936
+
14937
+
14938
+ /**
14939
+ * Create a wrapper function for exporting an internal functions to an external API.
14940
+ * @param {string} fn API function name
14941
+ * @returns {function} wrapped function
14942
+ * @memberof DataTable#internal
14943
+ */
14944
+ function _fnExternApiFunc (fn)
14945
+ {
14946
+ return function() {
14947
+ var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14948
+ Array.prototype.slice.call(arguments)
14949
+ );
14950
+ return DataTable.ext.internal[fn].apply( this, args );
14951
+ };
14952
+ }
14953
+
14954
+
14955
+ /**
14956
+ * Reference to internal functions for use by plug-in developers. Note that
14957
+ * these methods are references to internal functions and are considered to be
14958
+ * private. If you use these methods, be aware that they are liable to change
14959
+ * between versions.
14960
+ * @namespace
14961
+ */
14962
+ $.extend( DataTable.ext.internal, {
14963
+ _fnExternApiFunc: _fnExternApiFunc,
14964
+ _fnBuildAjax: _fnBuildAjax,
14965
+ _fnAjaxUpdate: _fnAjaxUpdate,
14966
+ _fnAjaxParameters: _fnAjaxParameters,
14967
+ _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14968
+ _fnAjaxDataSrc: _fnAjaxDataSrc,
14969
+ _fnAddColumn: _fnAddColumn,
14970
+ _fnColumnOptions: _fnColumnOptions,
14971
+ _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14972
+ _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14973
+ _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14974
+ _fnVisbleColumns: _fnVisbleColumns,
14975
+ _fnGetColumns: _fnGetColumns,
14976
+ _fnColumnTypes: _fnColumnTypes,
14977
+ _fnApplyColumnDefs: _fnApplyColumnDefs,
14978
+ _fnHungarianMap: _fnHungarianMap,
14979
+ _fnCamelToHungarian: _fnCamelToHungarian,
14980
+ _fnLanguageCompat: _fnLanguageCompat,
14981
+ _fnBrowserDetect: _fnBrowserDetect,
14982
+ _fnAddData: _fnAddData,
14983
+ _fnAddTr: _fnAddTr,
14984
+ _fnNodeToDataIndex: _fnNodeToDataIndex,
14985
+ _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14986
+ _fnGetCellData: _fnGetCellData,
14987
+ _fnSetCellData: _fnSetCellData,
14988
+ _fnSplitObjNotation: _fnSplitObjNotation,
14989
+ _fnGetObjectDataFn: _fnGetObjectDataFn,
14990
+ _fnSetObjectDataFn: _fnSetObjectDataFn,
14991
+ _fnGetDataMaster: _fnGetDataMaster,
14992
+ _fnClearTable: _fnClearTable,
14993
+ _fnDeleteIndex: _fnDeleteIndex,
14994
+ _fnInvalidate: _fnInvalidate,
14995
+ _fnGetRowElements: _fnGetRowElements,
14996
+ _fnCreateTr: _fnCreateTr,
14997
+ _fnBuildHead: _fnBuildHead,
14998
+ _fnDrawHead: _fnDrawHead,
14999
+ _fnDraw: _fnDraw,
15000
+ _fnReDraw: _fnReDraw,
15001
+ _fnAddOptionsHtml: _fnAddOptionsHtml,
15002
+ _fnDetectHeader: _fnDetectHeader,
15003
+ _fnGetUniqueThs: _fnGetUniqueThs,
15004
+ _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
15005
+ _fnFilterComplete: _fnFilterComplete,
15006
+ _fnFilterCustom: _fnFilterCustom,
15007
+ _fnFilterColumn: _fnFilterColumn,
15008
+ _fnFilter: _fnFilter,
15009
+ _fnFilterCreateSearch: _fnFilterCreateSearch,
15010
+ _fnEscapeRegex: _fnEscapeRegex,
15011
+ _fnFilterData: _fnFilterData,
15012
+ _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
15013
+ _fnUpdateInfo: _fnUpdateInfo,
15014
+ _fnInfoMacros: _fnInfoMacros,
15015
+ _fnInitialise: _fnInitialise,
15016
+ _fnInitComplete: _fnInitComplete,
15017
+ _fnLengthChange: _fnLengthChange,
15018
+ _fnFeatureHtmlLength: _fnFeatureHtmlLength,
15019
+ _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
15020
+ _fnPageChange: _fnPageChange,
15021
+ _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
15022
+ _fnProcessingDisplay: _fnProcessingDisplay,
15023
+ _fnFeatureHtmlTable: _fnFeatureHtmlTable,
15024
+ _fnScrollDraw: _fnScrollDraw,
15025
+ _fnApplyToChildren: _fnApplyToChildren,
15026
+ _fnCalculateColumnWidths: _fnCalculateColumnWidths,
15027
+ _fnThrottle: _fnThrottle,
15028
+ _fnConvertToWidth: _fnConvertToWidth,
15029
+ _fnGetWidestNode: _fnGetWidestNode,
15030
+ _fnGetMaxLenString: _fnGetMaxLenString,
15031
+ _fnStringToCss: _fnStringToCss,
15032
+ _fnSortFlatten: _fnSortFlatten,
15033
+ _fnSort: _fnSort,
15034
+ _fnSortAria: _fnSortAria,
15035
+ _fnSortListener: _fnSortListener,
15036
+ _fnSortAttachListener: _fnSortAttachListener,
15037
+ _fnSortingClasses: _fnSortingClasses,
15038
+ _fnSortData: _fnSortData,
15039
+ _fnSaveState: _fnSaveState,
15040
+ _fnLoadState: _fnLoadState,
15041
+ _fnSettingsFromNode: _fnSettingsFromNode,
15042
+ _fnLog: _fnLog,
15043
+ _fnMap: _fnMap,
15044
+ _fnBindAction: _fnBindAction,
15045
+ _fnCallbackReg: _fnCallbackReg,
15046
+ _fnCallbackFire: _fnCallbackFire,
15047
+ _fnLengthOverflow: _fnLengthOverflow,
15048
+ _fnRenderer: _fnRenderer,
15049
+ _fnDataSource: _fnDataSource,
15050
+ _fnRowAttributes: _fnRowAttributes,
15051
+ _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
15052
+ // in 1.10, so this dead-end function is
15053
+ // added to prevent errors
15054
+ } );
15055
+
15056
+
15057
+ // jQuery access
15058
+ $.fn.dataTable = DataTable;
15059
+
15060
+ // Provide access to the host jQuery object (circular reference)
15061
+ DataTable.$ = $;
15062
+
15063
+ // Legacy aliases
15064
+ $.fn.dataTableSettings = DataTable.settings;
15065
+ $.fn.dataTableExt = DataTable.ext;
15066
+
15067
+ // With a capital `D` we return a DataTables API instance rather than a
15068
+ // jQuery object
15069
+ $.fn.DataTable = function ( opts ) {
15070
+ return $(this).dataTable( opts ).api();
15071
+ };
15072
+
15073
+ // All properties that are available to $.fn.dataTable should also be
15074
+ // available on $.fn.DataTable
15075
+ $.each( DataTable, function ( prop, val ) {
15076
+ $.fn.DataTable[ prop ] = val;
15077
+ } );
15078
+
15079
+
15080
+ // Information about events fired by DataTables - for documentation.
15081
+ /**
15082
+ * Draw event, fired whenever the table is redrawn on the page, at the same
15083
+ * point as fnDrawCallback. This may be useful for binding events or
15084
+ * performing calculations when the table is altered at all.
15085
+ * @name DataTable#draw.dt
15086
+ * @event
15087
+ * @param {event} e jQuery event object
15088
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15089
+ */
15090
+
15091
+ /**
15092
+ * Search event, fired when the searching applied to the table (using the
15093
+ * built-in global search, or column filters) is altered.
15094
+ * @name DataTable#search.dt
15095
+ * @event
15096
+ * @param {event} e jQuery event object
15097
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15098
+ */
15099
+
15100
+ /**
15101
+ * Page change event, fired when the paging of the table is altered.
15102
+ * @name DataTable#page.dt
15103
+ * @event
15104
+ * @param {event} e jQuery event object
15105
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15106
+ */
15107
+
15108
+ /**
15109
+ * Order event, fired when the ordering applied to the table is altered.
15110
+ * @name DataTable#order.dt
15111
+ * @event
15112
+ * @param {event} e jQuery event object
15113
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15114
+ */
15115
+
15116
+ /**
15117
+ * DataTables initialisation complete event, fired when the table is fully
15118
+ * drawn, including Ajax data loaded, if Ajax data is required.
15119
+ * @name DataTable#init.dt
15120
+ * @event
15121
+ * @param {event} e jQuery event object
15122
+ * @param {object} oSettings DataTables settings object
15123
+ * @param {object} json The JSON object request from the server - only
15124
+ * present if client-side Ajax sourced data is used</li></ol>
15125
+ */
15126
+
15127
+ /**
15128
+ * State save event, fired when the table has changed state a new state save
15129
+ * is required. This event allows modification of the state saving object
15130
+ * prior to actually doing the save, including addition or other state
15131
+ * properties (for plug-ins) or modification of a DataTables core property.
15132
+ * @name DataTable#stateSaveParams.dt
15133
+ * @event
15134
+ * @param {event} e jQuery event object
15135
+ * @param {object} oSettings DataTables settings object
15136
+ * @param {object} json The state information to be saved
15137
+ */
15138
+
15139
+ /**
15140
+ * State load event, fired when the table is loading state from the stored
15141
+ * data, but prior to the settings object being modified by the saved state
15142
+ * - allowing modification of the saved state is required or loading of
15143
+ * state for a plug-in.
15144
+ * @name DataTable#stateLoadParams.dt
15145
+ * @event
15146
+ * @param {event} e jQuery event object
15147
+ * @param {object} oSettings DataTables settings object
15148
+ * @param {object} json The saved state information
15149
+ */
15150
+
15151
+ /**
15152
+ * State loaded event, fired when state has been loaded from stored data and
15153
+ * the settings object has been modified by the loaded data.
15154
+ * @name DataTable#stateLoaded.dt
15155
+ * @event
15156
+ * @param {event} e jQuery event object
15157
+ * @param {object} oSettings DataTables settings object
15158
+ * @param {object} json The saved state information
15159
+ */
15160
+
15161
+ /**
15162
+ * Processing event, fired when DataTables is doing some kind of processing
15163
+ * (be it, order, searcg or anything else). It can be used to indicate to
15164
+ * the end user that there is something happening, or that something has
15165
+ * finished.
15166
+ * @name DataTable#processing.dt
15167
+ * @event
15168
+ * @param {event} e jQuery event object
15169
+ * @param {object} oSettings DataTables settings object
15170
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
15171
+ */
15172
+
15173
+ /**
15174
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a
15175
+ * request to made to the server for new data. This event is called before
15176
+ * DataTables processed the returned data, so it can also be used to pre-
15177
+ * process the data returned from the server, if needed.
15178
+ *
15179
+ * Note that this trigger is called in `fnServerData`, if you override
15180
+ * `fnServerData` and which to use this event, you need to trigger it in you
15181
+ * success function.
15182
+ * @name DataTable#xhr.dt
15183
+ * @event
15184
+ * @param {event} e jQuery event object
15185
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15186
+ * @param {object} json JSON returned from the server
15187
+ *
15188
+ * @example
15189
+ * // Use a custom property returned from the server in another DOM element
15190
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15191
+ * $('#status').html( json.status );
15192
+ * } );
15193
+ *
15194
+ * @example
15195
+ * // Pre-process the data returned from the server
15196
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
15197
+ * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
15198
+ * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
15199
+ * }
15200
+ * // Note no return - manipulate the data directly in the JSON object.
15201
+ * } );
15202
+ */
15203
+
15204
+ /**
15205
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
15206
+ * or passing the bDestroy:true parameter in the initialisation object. This
15207
+ * can be used to remove bound events, added DOM nodes, etc.
15208
+ * @name DataTable#destroy.dt
15209
+ * @event
15210
+ * @param {event} e jQuery event object
15211
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15212
+ */
15213
+
15214
+ /**
15215
+ * Page length change event, fired when number of records to show on each
15216
+ * page (the length) is changed.
15217
+ * @name DataTable#length.dt
15218
+ * @event
15219
+ * @param {event} e jQuery event object
15220
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15221
+ * @param {integer} len New length
15222
+ */
15223
+
15224
+ /**
15225
+ * Column sizing has changed.
15226
+ * @name DataTable#column-sizing.dt
15227
+ * @event
15228
+ * @param {event} e jQuery event object
15229
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15230
+ */
15231
+
15232
+ /**
15233
+ * Column visibility has changed.
15234
+ * @name DataTable#column-visibility.dt
15235
+ * @event
15236
+ * @param {event} e jQuery event object
15237
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
15238
+ * @param {int} column Column index
15239
+ * @param {bool} vis `false` if column now hidden, or `true` if visible
15240
+ */
15241
+
15242
+ return $.fn.dataTable;
15243
+ }));
15244
+
15245
+ /*! Responsive 2.1.1
15246
+ * 2014-2016 SpryMedia Ltd - datatables.net/license
15247
+ */
15248
+
15249
+ /**
15250
+ * @summary Responsive
15251
+ * @description Responsive tables plug-in for DataTables
15252
+ * @version 2.1.1
15253
+ * @file dataTables.responsive.js
15254
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
15255
+ * @contact www.sprymedia.co.uk/contact
15256
+ * @copyright Copyright 2014-2016 SpryMedia Ltd.
15257
+ *
15258
+ * This source file is free software, available under the following license:
15259
+ * MIT license - http://datatables.net/license/mit
15260
+ *
15261
+ * This source file is distributed in the hope that it will be useful, but
15262
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15263
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
15264
+ *
15265
+ * For details please refer to: http://www.datatables.net
15266
+ */
15267
+ (function( factory ){
15268
+ if ( typeof define === 'function' && define.amd ) {
15269
+ // AMD
15270
+ define( ['jquery', 'datatables.net'], function ( $ ) {
15271
+ return factory( $, window, document );
15272
+ } );
15273
+ }
15274
+ else if ( typeof exports === 'object' ) {
15275
+ // CommonJS
15276
+ module.exports = function (root, $) {
15277
+ if ( ! root ) {
15278
+ root = window;
15279
+ }
15280
+
15281
+ if ( ! $ || ! $.fn.dataTable ) {
15282
+ $ = require('datatables.net')(root, $).$;
15283
+ }
15284
+
15285
+ return factory( $, root, root.document );
15286
+ };
15287
+ }
15288
+ else {
15289
+ // Browser
15290
+ factory( jQuery, window, document );
15291
+ }
15292
+ }(function( $, window, document, undefined ) {
15293
+ 'use strict';
15294
+ var DataTable = $.fn.dataTable;
15295
+
15296
+
15297
+ /**
15298
+ * Responsive is a plug-in for the DataTables library that makes use of
15299
+ * DataTables' ability to change the visibility of columns, changing the
15300
+ * visibility of columns so the displayed columns fit into the table container.
15301
+ * The end result is that complex tables will be dynamically adjusted to fit
15302
+ * into the viewport, be it on a desktop, tablet or mobile browser.
15303
+ *
15304
+ * Responsive for DataTables has two modes of operation, which can used
15305
+ * individually or combined:
15306
+ *
15307
+ * * Class name based control - columns assigned class names that match the
15308
+ * breakpoint logic can be shown / hidden as required for each breakpoint.
15309
+ * * Automatic control - columns are automatically hidden when there is no
15310
+ * room left to display them. Columns removed from the right.
15311
+ *
15312
+ * In additional to column visibility control, Responsive also has built into
15313
+ * options to use DataTables' child row display to show / hide the information
15314
+ * from the table that has been hidden. There are also two modes of operation
15315
+ * for this child row display:
15316
+ *
15317
+ * * Inline - when the control element that the user can use to show / hide
15318
+ * child rows is displayed inside the first column of the table.
15319
+ * * Column - where a whole column is dedicated to be the show / hide control.
15320
+ *
15321
+ * Initialisation of Responsive is performed by:
15322
+ *
15323
+ * * Adding the class `responsive` or `dt-responsive` to the table. In this case
15324
+ * Responsive will automatically be initialised with the default configuration
15325
+ * options when the DataTable is created.
15326
+ * * Using the `responsive` option in the DataTables configuration options. This
15327
+ * can also be used to specify the configuration options, or simply set to
15328
+ * `true` to use the defaults.
15329
+ *
15330
+ * @class
15331
+ * @param {object} settings DataTables settings object for the host table
15332
+ * @param {object} [opts] Configuration options
15333
+ * @requires jQuery 1.7+
15334
+ * @requires DataTables 1.10.3+
15335
+ *
15336
+ * @example
15337
+ * $('#example').DataTable( {
15338
+ * responsive: true
15339
+ * } );
15340
+ * } );
15341
+ */
15342
+ var Responsive = function ( settings, opts ) {
15343
+ // Sanity check that we are using DataTables 1.10 or newer
15344
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.3' ) ) {
15345
+ throw 'DataTables Responsive requires DataTables 1.10.3 or newer';
15346
+ }
15347
+
15348
+ this.s = {
15349
+ dt: new DataTable.Api( settings ),
15350
+ columns: [],
15351
+ current: []
15352
+ };
15353
+
15354
+ // Check if responsive has already been initialised on this table
15355
+ if ( this.s.dt.settings()[0].responsive ) {
15356
+ return;
15357
+ }
15358
+
15359
+ // details is an object, but for simplicity the user can give it as a string
15360
+ // or a boolean
15361
+ if ( opts && typeof opts.details === 'string' ) {
15362
+ opts.details = { type: opts.details };
15363
+ }
15364
+ else if ( opts && opts.details === false ) {
15365
+ opts.details = { type: false };
15366
+ }
15367
+ else if ( opts && opts.details === true ) {
15368
+ opts.details = { type: 'inline' };
15369
+ }
15370
+
15371
+ this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
15372
+ settings.responsive = this;
15373
+ this._constructor();
15374
+ };
15375
+
15376
+ $.extend( Responsive.prototype, {
15377
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15378
+ * Constructor
15379
+ */
15380
+
15381
+ /**
15382
+ * Initialise the Responsive instance
15383
+ *
15384
+ * @private
15385
+ */
15386
+ _constructor: function ()
15387
+ {
15388
+ var that = this;
15389
+ var dt = this.s.dt;
15390
+ var dtPrivateSettings = dt.settings()[0];
15391
+ var oldWindowWidth = $(window).width();
15392
+
15393
+ dt.settings()[0]._responsive = this;
15394
+
15395
+ // Use DataTables' throttle function to avoid processor thrashing on
15396
+ // resize
15397
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
15398
+ // iOS has a bug whereby resize can fire when only scrolling
15399
+ // See: http://stackoverflow.com/questions/8898412
15400
+ var width = $(window).width();
15401
+
15402
+ if ( width !== oldWindowWidth ) {
15403
+ that._resize();
15404
+ oldWindowWidth = width;
15405
+ }
15406
+ } ) );
15407
+
15408
+ // DataTables doesn't currently trigger an event when a row is added, so
15409
+ // we need to hook into its private API to enforce the hidden rows when
15410
+ // new data is added
15411
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
15412
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
15413
+ $('>td, >th', tr).each( function ( i ) {
15414
+ var idx = dt.column.index( 'toData', i );
15415
+
15416
+ if ( that.s.current[idx] === false ) {
15417
+ $(this).css('display', 'none');
15418
+ }
15419
+ } );
15420
+ }
15421
+ } );
15422
+
15423
+ // Destroy event handler
15424
+ dt.on( 'destroy.dtr', function () {
15425
+ dt.off( '.dtr' );
15426
+ $( dt.table().body() ).off( '.dtr' );
15427
+ $(window).off( 'resize.dtr orientationchange.dtr' );
15428
+
15429
+ // Restore the columns that we've hidden
15430
+ $.each( that.s.current, function ( i, val ) {
15431
+ if ( val === false ) {
15432
+ that._setColumnVis( i, true );
15433
+ }
15434
+ } );
15435
+ } );
15436
+
15437
+ // Reorder the breakpoints array here in case they have been added out
15438
+ // of order
15439
+ this.c.breakpoints.sort( function (a, b) {
15440
+ return a.width < b.width ? 1 :
15441
+ a.width > b.width ? -1 : 0;
15442
+ } );
15443
+
15444
+ this._classLogic();
15445
+ this._resizeAuto();
15446
+
15447
+ // Details handler
15448
+ var details = this.c.details;
15449
+
15450
+ if ( details.type !== false ) {
15451
+ that._detailsInit();
15452
+
15453
+ // DataTables will trigger this event on every column it shows and
15454
+ // hides individually
15455
+ dt.on( 'column-visibility.dtr', function (e, ctx, col, vis) {
15456
+ that._classLogic();
15457
+ that._resizeAuto();
15458
+ that._resize();
15459
+ } );
15460
+
15461
+ // Redraw the details box on each draw which will happen if the data
15462
+ // has changed. This is used until DataTables implements a native
15463
+ // `updated` event for rows
15464
+ dt.on( 'draw.dtr', function () {
15465
+ that._redrawChildren();
15466
+ } );
15467
+
15468
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
15469
+ }
15470
+
15471
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
15472
+ that._classLogic();
15473
+ that._resizeAuto();
15474
+ that._resize();
15475
+ } );
15476
+
15477
+ // Change in column sizes means we need to calc
15478
+ dt.on( 'column-sizing.dtr', function () {
15479
+ that._resizeAuto();
15480
+ that._resize();
15481
+ });
15482
+
15483
+ // On Ajax reload we want to reopen any child rows which are displayed
15484
+ // by responsive
15485
+ dt.on( 'preXhr.dtr', function () {
15486
+ var rowIds = [];
15487
+ dt.rows().every( function () {
15488
+ if ( this.child.isShown() ) {
15489
+ rowIds.push( this.id(true) );
15490
+ }
15491
+ } );
15492
+
15493
+ dt.one( 'draw.dtr', function () {
15494
+ dt.rows( rowIds ).every( function () {
15495
+ that._detailsDisplay( this, false );
15496
+ } );
15497
+ } );
15498
+ });
15499
+
15500
+ dt.on( 'init.dtr', function (e, settings, details) {
15501
+ that._resizeAuto();
15502
+ that._resize();
15503
+
15504
+ // If columns were hidden, then DataTables needs to adjust the
15505
+ // column sizing
15506
+ if ( $.inArray( false, that.s.current ) ) {
15507
+ dt.columns.adjust();
15508
+ }
15509
+ } );
15510
+
15511
+ // First pass - draw the table for the current viewport size
15512
+ this._resize();
15513
+ },
15514
+
15515
+
15516
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15517
+ * Private methods
15518
+ */
15519
+
15520
+ /**
15521
+ * Calculate the visibility for the columns in a table for a given
15522
+ * breakpoint. The result is pre-determined based on the class logic if
15523
+ * class names are used to control all columns, but the width of the table
15524
+ * is also used if there are columns which are to be automatically shown
15525
+ * and hidden.
15526
+ *
15527
+ * @param {string} breakpoint Breakpoint name to use for the calculation
15528
+ * @return {array} Array of boolean values initiating the visibility of each
15529
+ * column.
15530
+ * @private
15531
+ */
15532
+ _columnsVisiblity: function ( breakpoint )
15533
+ {
15534
+ var dt = this.s.dt;
15535
+ var columns = this.s.columns;
15536
+ var i, ien;
15537
+
15538
+ // Create an array that defines the column ordering based first on the
15539
+ // column's priority, and secondly the column index. This allows the
15540
+ // columns to be removed from the right if the priority matches
15541
+ var order = columns
15542
+ .map( function ( col, idx ) {
15543
+ return {
15544
+ columnIdx: idx,
15545
+ priority: col.priority
15546
+ };
15547
+ } )
15548
+ .sort( function ( a, b ) {
15549
+ if ( a.priority !== b.priority ) {
15550
+ return a.priority - b.priority;
15551
+ }
15552
+ return a.columnIdx - b.columnIdx;
15553
+ } );
15554
+
15555
+ // Class logic - determine which columns are in this breakpoint based
15556
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
15557
+ // to indicate this to the rest of the function
15558
+ var display = $.map( columns, function ( col ) {
15559
+ return col.auto && col.minWidth === null ?
15560
+ false :
15561
+ col.auto === true ?
15562
+ '-' :
15563
+ $.inArray( breakpoint, col.includeIn ) !== -1;
15564
+ } );
15565
+
15566
+ // Auto column control - first pass: how much width is taken by the
15567
+ // ones that must be included from the non-auto columns
15568
+ var requiredWidth = 0;
15569
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
15570
+ if ( display[i] === true ) {
15571
+ requiredWidth += columns[i].minWidth;
15572
+ }
15573
+ }
15574
+
15575
+ // Second pass, use up any remaining width for other columns. For
15576
+ // scrolling tables we need to subtract the width of the scrollbar. It
15577
+ // may not be requires which makes this sub-optimal, but it would
15578
+ // require another full redraw to make complete use of those extra few
15579
+ // pixels
15580
+ var scrolling = dt.settings()[0].oScroll;
15581
+ var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
15582
+ var widthAvailable = dt.table().container().offsetWidth - bar;
15583
+ var usedWidth = widthAvailable - requiredWidth;
15584
+
15585
+ // Control column needs to always be included. This makes it sub-
15586
+ // optimal in terms of using the available with, but to stop layout
15587
+ // thrashing or overflow. Also we need to account for the control column
15588
+ // width first so we know how much width is available for the other
15589
+ // columns, since the control column might not be the first one shown
15590
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
15591
+ if ( columns[i].control ) {
15592
+ usedWidth -= columns[i].minWidth;
15593
+ }
15594
+ }
15595
+
15596
+ // Allow columns to be shown (counting by priority and then right to
15597
+ // left) until we run out of room
15598
+ var empty = false;
15599
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
15600
+ var colIdx = order[i].columnIdx;
15601
+
15602
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
15603
+ // Once we've found a column that won't fit we don't let any
15604
+ // others display either, or columns might disappear in the
15605
+ // middle of the table
15606
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
15607
+ empty = true;
15608
+ display[colIdx] = false;
15609
+ }
15610
+ else {
15611
+ display[colIdx] = true;
15612
+ }
15613
+
15614
+ usedWidth -= columns[colIdx].minWidth;
15615
+ }
15616
+ }
15617
+
15618
+ // Determine if the 'control' column should be shown (if there is one).
15619
+ // This is the case when there is a hidden column (that is not the
15620
+ // control column). The two loops look inefficient here, but they are
15621
+ // trivial and will fly through. We need to know the outcome from the
15622
+ // first , before the action in the second can be taken
15623
+ var showControl = false;
15624
+
15625
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
15626
+ if ( ! columns[i].control && ! columns[i].never && ! display[i] ) {
15627
+ showControl = true;
15628
+ break;
15629
+ }
15630
+ }
15631
+
15632
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
15633
+ if ( columns[i].control ) {
15634
+ display[i] = showControl;
15635
+ }
15636
+ }
15637
+
15638
+ // Finally we need to make sure that there is at least one column that
15639
+ // is visible
15640
+ if ( $.inArray( true, display ) === -1 ) {
15641
+ display[0] = true;
15642
+ }
15643
+
15644
+ return display;
15645
+ },
15646
+
15647
+
15648
+ /**
15649
+ * Create the internal `columns` array with information about the columns
15650
+ * for the table. This includes determining which breakpoints the column
15651
+ * will appear in, based upon class names in the column, which makes up the
15652
+ * vast majority of this method.
15653
+ *
15654
+ * @private
15655
+ */
15656
+ _classLogic: function ()
15657
+ {
15658
+ var that = this;
15659
+ var calc = {};
15660
+ var breakpoints = this.c.breakpoints;
15661
+ var dt = this.s.dt;
15662
+ var columns = dt.columns().eq(0).map( function (i) {
15663
+ var column = this.column(i);
15664
+ var className = column.header().className;
15665
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
15666
+
15667
+ if ( priority === undefined ) {
15668
+ var dataPriority = $(column.header()).data('priority');
15669
+
15670
+ priority = dataPriority !== undefined ?
15671
+ dataPriority * 1 :
15672
+ 10000;
15673
+ }
15674
+
15675
+ return {
15676
+ className: className,
15677
+ includeIn: [],
15678
+ auto: false,
15679
+ control: false,
15680
+ never: className.match(/\bnever\b/) ? true : false,
15681
+ priority: priority
15682
+ };
15683
+ } );
15684
+
15685
+ // Simply add a breakpoint to `includeIn` array, ensuring that there are
15686
+ // no duplicates
15687
+ var add = function ( colIdx, name ) {
15688
+ var includeIn = columns[ colIdx ].includeIn;
15689
+
15690
+ if ( $.inArray( name, includeIn ) === -1 ) {
15691
+ includeIn.push( name );
15692
+ }
15693
+ };
15694
+
15695
+ var column = function ( colIdx, name, operator, matched ) {
15696
+ var size, i, ien;
15697
+
15698
+ if ( ! operator ) {
15699
+ columns[ colIdx ].includeIn.push( name );
15700
+ }
15701
+ else if ( operator === 'max-' ) {
15702
+ // Add this breakpoint and all smaller
15703
+ size = that._find( name ).width;
15704
+
15705
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15706
+ if ( breakpoints[i].width <= size ) {
15707
+ add( colIdx, breakpoints[i].name );
15708
+ }
15709
+ }
15710
+ }
15711
+ else if ( operator === 'min-' ) {
15712
+ // Add this breakpoint and all larger
15713
+ size = that._find( name ).width;
15714
+
15715
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15716
+ if ( breakpoints[i].width >= size ) {
15717
+ add( colIdx, breakpoints[i].name );
15718
+ }
15719
+ }
15720
+ }
15721
+ else if ( operator === 'not-' ) {
15722
+ // Add all but this breakpoint
15723
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15724
+ if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
15725
+ add( colIdx, breakpoints[i].name );
15726
+ }
15727
+ }
15728
+ }
15729
+ };
15730
+
15731
+ // Loop over each column and determine if it has a responsive control
15732
+ // class
15733
+ columns.each( function ( col, i ) {
15734
+ var classNames = col.className.split(' ');
15735
+ var hasClass = false;
15736
+
15737
+ // Split the class name up so multiple rules can be applied if needed
15738
+ for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
15739
+ var className = $.trim( classNames[k] );
15740
+
15741
+ if ( className === 'all' ) {
15742
+ // Include in all
15743
+ hasClass = true;
15744
+ col.includeIn = $.map( breakpoints, function (a) {
15745
+ return a.name;
15746
+ } );
15747
+ return;
15748
+ }
15749
+ else if ( className === 'none' || col.never ) {
15750
+ // Include in none (default) and no auto
15751
+ hasClass = true;
15752
+ return;
15753
+ }
15754
+ else if ( className === 'control' ) {
15755
+ // Special column that is only visible, when one of the other
15756
+ // columns is hidden. This is used for the details control
15757
+ hasClass = true;
15758
+ col.control = true;
15759
+ return;
15760
+ }
15761
+
15762
+ $.each( breakpoints, function ( j, breakpoint ) {
15763
+ // Does this column have a class that matches this breakpoint?
15764
+ var brokenPoint = breakpoint.name.split('-');
15765
+ var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
15766
+ var match = className.match( re );
15767
+
15768
+ if ( match ) {
15769
+ hasClass = true;
15770
+
15771
+ if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
15772
+ // Class name matches breakpoint name fully
15773
+ column( i, breakpoint.name, match[1], match[2]+match[3] );
15774
+ }
15775
+ else if ( match[2] === brokenPoint[0] && ! match[3] ) {
15776
+ // Class name matched primary breakpoint name with no qualifier
15777
+ column( i, breakpoint.name, match[1], match[2] );
15778
+ }
15779
+ }
15780
+ } );
15781
+ }
15782
+
15783
+ // If there was no control class, then automatic sizing is used
15784
+ if ( ! hasClass ) {
15785
+ col.auto = true;
15786
+ }
15787
+ } );
15788
+
15789
+ this.s.columns = columns;
15790
+ },
15791
+
15792
+
15793
+ /**
15794
+ * Show the details for the child row
15795
+ *
15796
+ * @param {DataTables.Api} row API instance for the row
15797
+ * @param {boolean} update Update flag
15798
+ * @private
15799
+ */
15800
+ _detailsDisplay: function ( row, update )
15801
+ {
15802
+ var that = this;
15803
+ var dt = this.s.dt;
15804
+ var details = this.c.details;
15805
+
15806
+ if ( details && details.type !== false ) {
15807
+ var res = details.display( row, update, function () {
15808
+ return details.renderer(
15809
+ dt, row[0], that._detailsObj(row[0])
15810
+ );
15811
+ } );
15812
+
15813
+ if ( res === true || res === false ) {
15814
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
15815
+ }
15816
+ }
15817
+ },
15818
+
15819
+
15820
+ /**
15821
+ * Initialisation for the details handler
15822
+ *
15823
+ * @private
15824
+ */
15825
+ _detailsInit: function ()
15826
+ {
15827
+ var that = this;
15828
+ var dt = this.s.dt;
15829
+ var details = this.c.details;
15830
+
15831
+ // The inline type always uses the first child as the target
15832
+ if ( details.type === 'inline' ) {
15833
+ details.target = 'td:first-child, th:first-child';
15834
+ }
15835
+
15836
+ // Keyboard accessibility
15837
+ dt.on( 'draw.dtr', function () {
15838
+ that._tabIndexes();
15839
+ } );
15840
+ that._tabIndexes(); // Initial draw has already happened
15841
+
15842
+ $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
15843
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
15844
+ $(this).click();
15845
+ }
15846
+ } );
15847
+
15848
+ // type.target can be a string jQuery selector or a column index
15849
+ var target = details.target;
15850
+ var selector = typeof target === 'string' ? target : 'td, th';
15851
+
15852
+ // Click handler to show / hide the details rows when they are available
15853
+ $( dt.table().body() )
15854
+ .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
15855
+ // If the table is not collapsed (i.e. there is no hidden columns)
15856
+ // then take no action
15857
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
15858
+ return;
15859
+ }
15860
+
15861
+ // Check that the row is actually a DataTable's controlled node
15862
+ if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
15863
+ return;
15864
+ }
15865
+
15866
+ // For column index, we determine if we should act or not in the
15867
+ // handler - otherwise it is already okay
15868
+ if ( typeof target === 'number' ) {
15869
+ var targetIdx = target < 0 ?
15870
+ dt.columns().eq(0).length + target :
15871
+ target;
15872
+
15873
+ if ( dt.cell( this ).index().column !== targetIdx ) {
15874
+ return;
15875
+ }
15876
+ }
15877
+
15878
+ // $().closest() includes itself in its check
15879
+ var row = dt.row( $(this).closest('tr') );
15880
+
15881
+ // Check event type to do an action
15882
+ if ( e.type === 'click' ) {
15883
+ // The renderer is given as a function so the caller can execute it
15884
+ // only when they need (i.e. if hiding there is no point is running
15885
+ // the renderer)
15886
+ that._detailsDisplay( row, false );
15887
+ }
15888
+ else if ( e.type === 'mousedown' ) {
15889
+ // For mouse users, prevent the focus ring from showing
15890
+ $(this).css('outline', 'none');
15891
+ }
15892
+ else if ( e.type === 'mouseup' ) {
15893
+ // And then re-allow at the end of the click
15894
+ $(this).blur().css('outline', '');
15895
+ }
15896
+ } );
15897
+ },
15898
+
15899
+
15900
+ /**
15901
+ * Get the details to pass to a renderer for a row
15902
+ * @param {int} rowIdx Row index
15903
+ * @private
15904
+ */
15905
+ _detailsObj: function ( rowIdx )
15906
+ {
15907
+ var that = this;
15908
+ var dt = this.s.dt;
15909
+
15910
+ return $.map( this.s.columns, function( col, i ) {
15911
+ // Never and control columns should not be passed to the renderer
15912
+ if ( col.never || col.control ) {
15913
+ return;
15914
+ }
15915
+
15916
+ return {
15917
+ title: dt.settings()[0].aoColumns[ i ].sTitle,
15918
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
15919
+ hidden: dt.column( i ).visible() && !that.s.current[ i ],
15920
+ columnIndex: i,
15921
+ rowIndex: rowIdx
15922
+ };
15923
+ } );
15924
+ },
15925
+
15926
+
15927
+ /**
15928
+ * Find a breakpoint object from a name
15929
+ *
15930
+ * @param {string} name Breakpoint name to find
15931
+ * @return {object} Breakpoint description object
15932
+ * @private
15933
+ */
15934
+ _find: function ( name )
15935
+ {
15936
+ var breakpoints = this.c.breakpoints;
15937
+
15938
+ for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
15939
+ if ( breakpoints[i].name === name ) {
15940
+ return breakpoints[i];
15941
+ }
15942
+ }
15943
+ },
15944
+
15945
+
15946
+ /**
15947
+ * Re-create the contents of the child rows as the display has changed in
15948
+ * some way.
15949
+ *
15950
+ * @private
15951
+ */
15952
+ _redrawChildren: function ()
15953
+ {
15954
+ var that = this;
15955
+ var dt = this.s.dt;
15956
+
15957
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
15958
+ var row = dt.row( idx );
15959
+
15960
+ that._detailsDisplay( dt.row( idx ), true );
15961
+ } );
15962
+ },
15963
+
15964
+
15965
+ /**
15966
+ * Alter the table display for a resized viewport. This involves first
15967
+ * determining what breakpoint the window currently is in, getting the
15968
+ * column visibilities to apply and then setting them.
15969
+ *
15970
+ * @private
15971
+ */
15972
+ _resize: function ()
15973
+ {
15974
+ var that = this;
15975
+ var dt = this.s.dt;
15976
+ var width = $(window).width();
15977
+ var breakpoints = this.c.breakpoints;
15978
+ var breakpoint = breakpoints[0].name;
15979
+ var columns = this.s.columns;
15980
+ var i, ien;
15981
+ var oldVis = this.s.current.slice();
15982
+
15983
+ // Determine what breakpoint we are currently at
15984
+ for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
15985
+ if ( width <= breakpoints[i].width ) {
15986
+ breakpoint = breakpoints[i].name;
15987
+ break;
15988
+ }
15989
+ }
15990
+
15991
+ // Show the columns for that break point
15992
+ var columnsVis = this._columnsVisiblity( breakpoint );
15993
+ this.s.current = columnsVis;
15994
+
15995
+ // Set the class before the column visibility is changed so event
15996
+ // listeners know what the state is. Need to determine if there are
15997
+ // any columns that are not visible but can be shown
15998
+ var collapsedClass = false;
15999
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
16000
+ if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control ) {
16001
+ collapsedClass = true;
16002
+ break;
16003
+ }
16004
+ }
16005
+
16006
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
16007
+
16008
+ var changed = false;
16009
+
16010
+ dt.columns().eq(0).each( function ( colIdx, i ) {
16011
+ if ( columnsVis[i] !== oldVis[i] ) {
16012
+ changed = true;
16013
+ that._setColumnVis( colIdx, columnsVis[i] );
16014
+ }
16015
+ } );
16016
+
16017
+ if ( changed ) {
16018
+ this._redrawChildren();
16019
+
16020
+ // Inform listeners of the change
16021
+ $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
16022
+ }
16023
+ },
16024
+
16025
+
16026
+ /**
16027
+ * Determine the width of each column in the table so the auto column hiding
16028
+ * has that information to work with. This method is never going to be 100%
16029
+ * perfect since column widths can change slightly per page, but without
16030
+ * seriously compromising performance this is quite effective.
16031
+ *
16032
+ * @private
16033
+ */
16034
+ _resizeAuto: function ()
16035
+ {
16036
+ var dt = this.s.dt;
16037
+ var columns = this.s.columns;
16038
+
16039
+ // Are we allowed to do auto sizing?
16040
+ if ( ! this.c.auto ) {
16041
+ return;
16042
+ }
16043
+
16044
+ // Are there any columns that actually need auto-sizing, or do they all
16045
+ // have classes defined
16046
+ if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
16047
+ return;
16048
+ }
16049
+
16050
+ // Clone the table with the current data in it
16051
+ var tableWidth = dt.table().node().offsetWidth;
16052
+ var columnWidths = dt.columns;
16053
+ var clonedTable = dt.table().node().cloneNode( false );
16054
+ var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
16055
+ var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
16056
+
16057
+ // Header
16058
+ var headerCells = dt.columns()
16059
+ .header()
16060
+ .filter( function (idx) {
16061
+ return dt.column(idx).visible();
16062
+ } )
16063
+ .to$()
16064
+ .clone( false )
16065
+ .css( 'display', 'table-cell' );
16066
+
16067
+ // Body rows - we don't need to take account of DataTables' column
16068
+ // visibility since we implement our own here (hence the `display` set)
16069
+ $(clonedBody)
16070
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
16071
+ .find( 'th, td' ).css( 'display', '' );
16072
+
16073
+ // Footer
16074
+ var footer = dt.table().footer();
16075
+ if ( footer ) {
16076
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
16077
+ var footerCells = dt.columns()
16078
+ .footer()
16079
+ .filter( function (idx) {
16080
+ return dt.column(idx).visible();
16081
+ } )
16082
+ .to$()
16083
+ .clone( false )
16084
+ .css( 'display', 'table-cell' );
16085
+
16086
+ $('<tr/>')
16087
+ .append( footerCells )
16088
+ .appendTo( clonedFooter );
16089
+ }
16090
+
16091
+ $('<tr/>')
16092
+ .append( headerCells )
16093
+ .appendTo( clonedHeader );
16094
+
16095
+ // In the inline case extra padding is applied to the first column to
16096
+ // give space for the show / hide icon. We need to use this in the
16097
+ // calculation
16098
+ if ( this.c.details.type === 'inline' ) {
16099
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
16100
+ }
16101
+
16102
+ // It is unsafe to insert elements with the same name into the DOM
16103
+ // multiple times. For example, cloning and inserting a checked radio
16104
+ // clears the chcecked state of the original radio.
16105
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
16106
+
16107
+ var inserted = $('<div/>')
16108
+ .css( {
16109
+ width: 1,
16110
+ height: 1,
16111
+ overflow: 'hidden'
16112
+ } )
16113
+ .append( clonedTable );
16114
+
16115
+ inserted.insertBefore( dt.table().node() );
16116
+
16117
+ // The cloned header now contains the smallest that each column can be
16118
+ headerCells.each( function (i) {
16119
+ var idx = dt.column.index( 'fromVisible', i );
16120
+ columns[ idx ].minWidth = this.offsetWidth || 0;
16121
+ } );
16122
+
16123
+ inserted.remove();
16124
+ },
16125
+
16126
+ /**
16127
+ * Set a column's visibility.
16128
+ *
16129
+ * We don't use DataTables' column visibility controls in order to ensure
16130
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
16131
+ * supported (and all evergreen browsers of course) the control of the
16132
+ * display attribute works well.
16133
+ *
16134
+ * @param {integer} col Column index
16135
+ * @param {boolean} showHide Show or hide (true or false)
16136
+ * @private
16137
+ */
16138
+ _setColumnVis: function ( col, showHide )
16139
+ {
16140
+ var dt = this.s.dt;
16141
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
16142
+
16143
+ $( dt.column( col ).header() ).css( 'display', display );
16144
+ $( dt.column( col ).footer() ).css( 'display', display );
16145
+ dt.column( col ).nodes().to$().css( 'display', display );
16146
+ },
16147
+
16148
+
16149
+ /**
16150
+ * Update the cell tab indexes for keyboard accessibility. This is called on
16151
+ * every table draw - that is potentially inefficient, but also the least
16152
+ * complex option given that column visibility can change on the fly. Its a
16153
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
16154
+ * issue with a single CSS statement.
16155
+ *
16156
+ * @private
16157
+ */
16158
+ _tabIndexes: function ()
16159
+ {
16160
+ var dt = this.s.dt;
16161
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
16162
+ var ctx = dt.settings()[0];
16163
+ var target = this.c.details.target;
16164
+
16165
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
16166
+
16167
+ var selector = typeof target === 'number' ?
16168
+ ':eq('+target+')' :
16169
+ target;
16170
+
16171
+ // This is a bit of a hack - we need to limit the selected nodes to just
16172
+ // those of this table
16173
+ if ( selector === 'td:first-child, th:first-child' ) {
16174
+ selector = '>td:first-child, >th:first-child';
16175
+ }
16176
+
16177
+ $( selector, dt.rows( { page: 'current' } ).nodes() )
16178
+ .attr( 'tabIndex', ctx.iTabIndex )
16179
+ .data( 'dtr-keyboard', 1 );
16180
+ }
16181
+ } );
16182
+
16183
+
16184
+ /**
16185
+ * List of default breakpoints. Each item in the array is an object with two
16186
+ * properties:
16187
+ *
16188
+ * * `name` - the breakpoint name.
16189
+ * * `width` - the breakpoint width
16190
+ *
16191
+ * @name Responsive.breakpoints
16192
+ * @static
16193
+ */
16194
+ Responsive.breakpoints = [
16195
+ { name: 'desktop', width: Infinity },
16196
+ { name: 'tablet-l', width: 1024 },
16197
+ { name: 'tablet-p', width: 768 },
16198
+ { name: 'mobile-l', width: 480 },
16199
+ { name: 'mobile-p', width: 320 }
16200
+ ];
16201
+
16202
+
16203
+ /**
16204
+ * Display methods - functions which define how the hidden data should be shown
16205
+ * in the table.
16206
+ *
16207
+ * @namespace
16208
+ * @name Responsive.defaults
16209
+ * @static
16210
+ */
16211
+ Responsive.display = {
16212
+ childRow: function ( row, update, render ) {
16213
+ if ( update ) {
16214
+ if ( $(row.node()).hasClass('parent') ) {
16215
+ row.child( render(), 'child' ).show();
16216
+
16217
+ return true;
16218
+ }
16219
+ }
16220
+ else {
16221
+ if ( ! row.child.isShown() ) {
16222
+ row.child( render(), 'child' ).show();
16223
+ $( row.node() ).addClass( 'parent' );
16224
+
16225
+ return true;
16226
+ }
16227
+ else {
16228
+ row.child( false );
16229
+ $( row.node() ).removeClass( 'parent' );
16230
+
16231
+ return false;
16232
+ }
16233
+ }
16234
+ },
16235
+
16236
+ childRowImmediate: function ( row, update, render ) {
16237
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
16238
+ // User interaction and the row is show, or nothing to show
16239
+ row.child( false );
16240
+ $( row.node() ).removeClass( 'parent' );
16241
+
16242
+ return false;
16243
+ }
16244
+ else {
16245
+ // Display
16246
+ row.child( render(), 'child' ).show();
16247
+ $( row.node() ).addClass( 'parent' );
16248
+
16249
+ return true;
16250
+ }
16251
+ },
16252
+
16253
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
16254
+ // have options passed into them. This specific one doesn't need to be a
16255
+ // function but it is for consistency in the `modal` name
16256
+ modal: function ( options ) {
16257
+ return function ( row, update, render ) {
16258
+ if ( ! update ) {
16259
+ // Show a modal
16260
+ var close = function () {
16261
+ modal.remove(); // will tidy events for us
16262
+ $(document).off( 'keypress.dtr' );
16263
+ };
16264
+
16265
+ var modal = $('<div class="dtr-modal"/>')
16266
+ .append( $('<div class="dtr-modal-display"/>')
16267
+ .append( $('<div class="dtr-modal-content"/>')
16268
+ .append( render() )
16269
+ )
16270
+ .append( $('<div class="dtr-modal-close">&times;</div>' )
16271
+ .click( function () {
16272
+ close();
16273
+ } )
16274
+ )
16275
+ )
16276
+ .append( $('<div class="dtr-modal-background"/>')
16277
+ .click( function () {
16278
+ close();
16279
+ } )
16280
+ )
16281
+ .appendTo( 'body' );
16282
+
16283
+ $(document).on( 'keyup.dtr', function (e) {
16284
+ if ( e.keyCode === 27 ) {
16285
+ e.stopPropagation();
16286
+
16287
+ close();
16288
+ }
16289
+ } );
16290
+ }
16291
+ else {
16292
+ $('div.dtr-modal-content')
16293
+ .empty()
16294
+ .append( render() );
16295
+ }
16296
+
16297
+ if ( options && options.header ) {
16298
+ $('div.dtr-modal-content').prepend(
16299
+ '<h2>'+options.header( row )+'</h2>'
16300
+ );
16301
+ }
16302
+ };
16303
+ }
16304
+ };
16305
+
16306
+
16307
+ /**
16308
+ * Display methods - functions which define how the hidden data should be shown
16309
+ * in the table.
16310
+ *
16311
+ * @namespace
16312
+ * @name Responsive.defaults
16313
+ * @static
16314
+ */
16315
+ Responsive.renderer = {
16316
+ listHidden: function () {
16317
+ return function ( api, rowIdx, columns ) {
16318
+ var data = $.map( columns, function ( col ) {
16319
+ return col.hidden ?
16320
+ '<li data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
16321
+ '<span class="dtr-title">'+
16322
+ col.title+
16323
+ '</span> '+
16324
+ '<span class="dtr-data">'+
16325
+ col.data+
16326
+ '</span>'+
16327
+ '</li>' :
16328
+ '';
16329
+ } ).join('');
16330
+
16331
+ return data ?
16332
+ $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
16333
+ false;
16334
+ }
16335
+ },
16336
+
16337
+ tableAll: function ( options ) {
16338
+ options = $.extend( {
16339
+ tableClass: ''
16340
+ }, options );
16341
+
16342
+ return function ( api, rowIdx, columns ) {
16343
+ var data = $.map( columns, function ( col ) {
16344
+ return '<tr data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
16345
+ '<td>'+col.title+':'+'</td> '+
16346
+ '<td>'+col.data+'</td>'+
16347
+ '</tr>';
16348
+ } ).join('');
16349
+
16350
+ return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
16351
+ }
16352
+ }
16353
+ };
16354
+
16355
+ /**
16356
+ * Responsive default settings for initialisation
16357
+ *
16358
+ * @namespace
16359
+ * @name Responsive.defaults
16360
+ * @static
16361
+ */
16362
+ Responsive.defaults = {
16363
+ /**
16364
+ * List of breakpoints for the instance. Note that this means that each
16365
+ * instance can have its own breakpoints. Additionally, the breakpoints
16366
+ * cannot be changed once an instance has been creased.
16367
+ *
16368
+ * @type {Array}
16369
+ * @default Takes the value of `Responsive.breakpoints`
16370
+ */
16371
+ breakpoints: Responsive.breakpoints,
16372
+
16373
+ /**
16374
+ * Enable / disable auto hiding calculations. It can help to increase
16375
+ * performance slightly if you disable this option, but all columns would
16376
+ * need to have breakpoint classes assigned to them
16377
+ *
16378
+ * @type {Boolean}
16379
+ * @default `true`
16380
+ */
16381
+ auto: true,
16382
+
16383
+ /**
16384
+ * Details control. If given as a string value, the `type` property of the
16385
+ * default object is set to that value, and the defaults used for the rest
16386
+ * of the object - this is for ease of implementation.
16387
+ *
16388
+ * The object consists of the following properties:
16389
+ *
16390
+ * * `display` - A function that is used to show and hide the hidden details
16391
+ * * `renderer` - function that is called for display of the child row data.
16392
+ * The default function will show the data from the hidden columns
16393
+ * * `target` - Used as the selector for what objects to attach the child
16394
+ * open / close to
16395
+ * * `type` - `false` to disable the details display, `inline` or `column`
16396
+ * for the two control types
16397
+ *
16398
+ * @type {Object|string}
16399
+ */
16400
+ details: {
16401
+ display: Responsive.display.childRow,
16402
+
16403
+ renderer: Responsive.renderer.listHidden(),
16404
+
16405
+ target: 0,
16406
+
16407
+ type: 'inline'
16408
+ },
16409
+
16410
+ /**
16411
+ * Orthogonal data request option. This is used to define the data type
16412
+ * requested when Responsive gets the data to show in the child row.
16413
+ *
16414
+ * @type {String}
16415
+ */
16416
+ orthogonal: 'display'
16417
+ };
16418
+
16419
+
16420
+ /*
16421
+ * API
16422
+ */
16423
+ var Api = $.fn.dataTable.Api;
16424
+
16425
+ // Doesn't do anything - work around for a bug in DT... Not documented
16426
+ Api.register( 'responsive()', function () {
16427
+ return this;
16428
+ } );
16429
+
16430
+ Api.register( 'responsive.index()', function ( li ) {
16431
+ li = $(li);
16432
+
16433
+ return {
16434
+ column: li.data('dtr-index'),
16435
+ row: li.parent().data('dtr-index')
16436
+ };
16437
+ } );
16438
+
16439
+ Api.register( 'responsive.rebuild()', function () {
16440
+ return this.iterator( 'table', function ( ctx ) {
16441
+ if ( ctx._responsive ) {
16442
+ ctx._responsive._classLogic();
16443
+ }
16444
+ } );
16445
+ } );
16446
+
16447
+ Api.register( 'responsive.recalc()', function () {
16448
+ return this.iterator( 'table', function ( ctx ) {
16449
+ if ( ctx._responsive ) {
16450
+ ctx._responsive._resizeAuto();
16451
+ ctx._responsive._resize();
16452
+ }
16453
+ } );
16454
+ } );
16455
+
16456
+ Api.register( 'responsive.hasHidden()', function () {
16457
+ var ctx = this.context[0];
16458
+
16459
+ return ctx._responsive ?
16460
+ $.inArray( false, ctx._responsive.s.current ) !== -1 :
16461
+ false;
16462
+ } );
16463
+
16464
+
16465
+ /**
16466
+ * Version information
16467
+ *
16468
+ * @name Responsive.version
16469
+ * @static
16470
+ */
16471
+ Responsive.version = '2.1.1';
16472
+
16473
+
16474
+ $.fn.dataTable.Responsive = Responsive;
16475
+ $.fn.DataTable.Responsive = Responsive;
16476
+
16477
+ // Attach a listener to the document which listens for DataTables initialisation
16478
+ // events so we can automatically initialise
16479
+ $(document).on( 'preInit.dt.dtr', function (e, settings, json) {
16480
+ if ( e.namespace !== 'dt' ) {
16481
+ return;
16482
+ }
16483
+
16484
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
16485
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
16486
+ settings.oInit.responsive ||
16487
+ DataTable.defaults.responsive
16488
+ ) {
16489
+ var init = settings.oInit.responsive;
16490
+
16491
+ if ( init !== false ) {
16492
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
16493
+ }
16494
+ }
16495
+ } );
16496
+
16497
+
16498
+ return Responsive;
16499
+ }));
16500
+
16501
+ /*!***************************************************
16502
+ * mark.js v8.11.0
16503
+ * https://github.com/julmot/mark.js
16504
+ * Copyright (c) 2014–2017, Julian Motz
16505
+ * Released under the MIT license https://git.io/vwTVl
16506
+ *****************************************************/
16507
+
16508
+ "use strict";
16509
+
16510
+ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
16511
+
16512
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
16513
+
16514
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
16515
+
16516
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16517
+
16518
+ (function (factory, window, document) {
16519
+ if (typeof define === "function" && define.amd) {
16520
+ define(["jquery"], function (jQuery) {
16521
+ return factory(window, document, jQuery);
16522
+ });
16523
+ } else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module.exports) {
16524
+ module.exports = factory(window, document, require("jquery"));
16525
+ } else {
16526
+ factory(window, document, jQuery);
16527
+ }
16528
+ })(function (window, document, $) {
16529
+ var Mark = function () {
16530
+ function Mark(ctx) {
16531
+ _classCallCheck(this, Mark);
16532
+
16533
+ this.ctx = ctx;
16534
+
16535
+ this.ie = false;
16536
+ var ua = window.navigator.userAgent;
16537
+ if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) {
16538
+ this.ie = true;
16539
+ }
16540
+ }
16541
+
16542
+ _createClass(Mark, [{
16543
+ key: "log",
16544
+ value: function log(msg) {
16545
+ var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "debug";
16546
+
16547
+ var log = this.opt.log;
16548
+ if (!this.opt.debug) {
16549
+ return;
16550
+ }
16551
+ if ((typeof log === "undefined" ? "undefined" : _typeof(log)) === "object" && typeof log[level] === "function") {
16552
+ log[level]("mark.js: " + msg);
16553
+ }
16554
+ }
16555
+ }, {
16556
+ key: "escapeStr",
16557
+ value: function escapeStr(str) {
16558
+ return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
16559
+ }
16560
+ }, {
16561
+ key: "createRegExp",
16562
+ value: function createRegExp(str) {
16563
+ if (this.opt.wildcards !== "disabled") {
16564
+ str = this.setupWildcardsRegExp(str);
16565
+ }
16566
+ str = this.escapeStr(str);
16567
+ if (Object.keys(this.opt.synonyms).length) {
16568
+ str = this.createSynonymsRegExp(str);
16569
+ }
16570
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
16571
+ str = this.setupIgnoreJoinersRegExp(str);
16572
+ }
16573
+ if (this.opt.diacritics) {
16574
+ str = this.createDiacriticsRegExp(str);
16575
+ }
16576
+ str = this.createMergedBlanksRegExp(str);
16577
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
16578
+ str = this.createJoinersRegExp(str);
16579
+ }
16580
+ if (this.opt.wildcards !== "disabled") {
16581
+ str = this.createWildcardsRegExp(str);
16582
+ }
16583
+ str = this.createAccuracyRegExp(str);
16584
+ return str;
16585
+ }
16586
+ }, {
16587
+ key: "createSynonymsRegExp",
16588
+ value: function createSynonymsRegExp(str) {
16589
+ var syn = this.opt.synonyms,
16590
+ sens = this.opt.caseSensitive ? "" : "i",
16591
+ joinerPlaceholder = this.opt.ignoreJoiners || this.opt.ignorePunctuation.length ? "\0" : "";
16592
+ for (var index in syn) {
16593
+ if (syn.hasOwnProperty(index)) {
16594
+ var value = syn[index],
16595
+ k1 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(index) : this.escapeStr(index),
16596
+ k2 = this.opt.wildcards !== "disabled" ? this.setupWildcardsRegExp(value) : this.escapeStr(value);
16597
+ if (k1 !== "" && k2 !== "") {
16598
+ str = str.replace(new RegExp("(" + k1 + "|" + k2 + ")", "gm" + sens), joinerPlaceholder + ("(" + this.processSynomyms(k1) + "|") + (this.processSynomyms(k2) + ")") + joinerPlaceholder);
16599
+ }
16600
+ }
16601
+ }
16602
+ return str;
16603
+ }
16604
+ }, {
16605
+ key: "processSynomyms",
16606
+ value: function processSynomyms(str) {
16607
+ if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
16608
+ str = this.setupIgnoreJoinersRegExp(str);
16609
+ }
16610
+ return str;
16611
+ }
16612
+ }, {
16613
+ key: "setupWildcardsRegExp",
16614
+ value: function setupWildcardsRegExp(str) {
16615
+ str = str.replace(/(?:\\)*\?/g, function (val) {
16616
+ return val.charAt(0) === "\\" ? "?" : "\x01";
16617
+ });
16618
+
16619
+ return str.replace(/(?:\\)*\*/g, function (val) {
16620
+ return val.charAt(0) === "\\" ? "*" : "\x02";
16621
+ });
16622
+ }
16623
+ }, {
16624
+ key: "createWildcardsRegExp",
16625
+ value: function createWildcardsRegExp(str) {
16626
+ var spaces = this.opt.wildcards === "withSpaces";
16627
+ return str.replace(/\u0001/g, spaces ? "[\\S\\s]?" : "\\S?").replace(/\u0002/g, spaces ? "[\\S\\s]*?" : "\\S*");
16628
+ }
16629
+ }, {
16630
+ key: "setupIgnoreJoinersRegExp",
16631
+ value: function setupIgnoreJoinersRegExp(str) {
16632
+ return str.replace(/[^(|)\\]/g, function (val, indx, original) {
16633
+ var nextChar = original.charAt(indx + 1);
16634
+ if (/[(|)\\]/.test(nextChar) || nextChar === "") {
16635
+ return val;
16636
+ } else {
16637
+ return val + "\0";
16638
+ }
16639
+ });
16640
+ }
16641
+ }, {
16642
+ key: "createJoinersRegExp",
16643
+ value: function createJoinersRegExp(str) {
16644
+ var joiner = [];
16645
+ var ignorePunctuation = this.opt.ignorePunctuation;
16646
+ if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) {
16647
+ joiner.push(this.escapeStr(ignorePunctuation.join("")));
16648
+ }
16649
+ if (this.opt.ignoreJoiners) {
16650
+ joiner.push("\\u00ad\\u200b\\u200c\\u200d");
16651
+ }
16652
+ return joiner.length ? str.split(/\u0000+/).join("[" + joiner.join("") + "]*") : str;
16653
+ }
16654
+ }, {
16655
+ key: "createDiacriticsRegExp",
16656
+ value: function createDiacriticsRegExp(str) {
16657
+ var sens = this.opt.caseSensitive ? "" : "i",
16658
+ dct = this.opt.caseSensitive ? ["aàáảãạăằắẳẵặâầấẩẫậäåāą", "AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ", "cçćč", "CÇĆČ", "dđď", "DĐĎ", "eèéẻẽẹêềếểễệëěēę", "EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ", "iìíỉĩịîïī", "IÌÍỈĨỊÎÏĪ", "lł", "LŁ", "nñňń", "NÑŇŃ", "oòóỏõọôồốổỗộơởỡớờợöøō", "OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ", "rř", "RŘ", "sšśșş", "SŠŚȘŞ", "tťțţ", "TŤȚŢ", "uùúủũụưừứửữựûüůū", "UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ", "yýỳỷỹỵÿ", "YÝỲỶỸỴŸ", "zžżź", "ZŽŻŹ"] : ["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ", "cçćčCÇĆČ", "dđďDĐĎ", "eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ", "iìíỉĩịîïīIÌÍỈĨỊÎÏĪ", "lłLŁ", "nñňńNÑŇŃ", "oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ", "rřRŘ", "sšśșşSŠŚȘŞ", "tťțţTŤȚŢ", "uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ", "yýỳỷỹỵÿYÝỲỶỸỴŸ", "zžżźZŽŻŹ"];
16659
+ var handled = [];
16660
+ str.split("").forEach(function (ch) {
16661
+ dct.every(function (dct) {
16662
+ if (dct.indexOf(ch) !== -1) {
16663
+ if (handled.indexOf(dct) > -1) {
16664
+ return false;
16665
+ }
16666
+
16667
+ str = str.replace(new RegExp("[" + dct + "]", "gm" + sens), "[" + dct + "]");
16668
+ handled.push(dct);
16669
+ }
16670
+ return true;
16671
+ });
16672
+ });
16673
+ return str;
16674
+ }
16675
+ }, {
16676
+ key: "createMergedBlanksRegExp",
16677
+ value: function createMergedBlanksRegExp(str) {
16678
+ return str.replace(/[\s]+/gmi, "[\\s]+");
16679
+ }
16680
+ }, {
16681
+ key: "createAccuracyRegExp",
16682
+ value: function createAccuracyRegExp(str) {
16683
+ var _this = this;
16684
+
16685
+ var chars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~\xA1\xBF";
16686
+ var acc = this.opt.accuracy,
16687
+ val = typeof acc === "string" ? acc : acc.value,
16688
+ ls = typeof acc === "string" ? [] : acc.limiters,
16689
+ lsJoin = "";
16690
+ ls.forEach(function (limiter) {
16691
+ lsJoin += "|" + _this.escapeStr(limiter);
16692
+ });
16693
+ switch (val) {
16694
+ case "partially":
16695
+ default:
16696
+ return "()(" + str + ")";
16697
+ case "complementary":
16698
+ lsJoin = "\\s" + (lsJoin ? lsJoin : this.escapeStr(chars));
16699
+ return "()([^" + lsJoin + "]*" + str + "[^" + lsJoin + "]*)";
16700
+ case "exactly":
16701
+ return "(^|\\s" + lsJoin + ")(" + str + ")(?=$|\\s" + lsJoin + ")";
16702
+ }
16703
+ }
16704
+ }, {
16705
+ key: "getSeparatedKeywords",
16706
+ value: function getSeparatedKeywords(sv) {
16707
+ var _this2 = this;
16708
+
16709
+ var stack = [];
16710
+ sv.forEach(function (kw) {
16711
+ if (!_this2.opt.separateWordSearch) {
16712
+ if (kw.trim() && stack.indexOf(kw) === -1) {
16713
+ stack.push(kw);
16714
+ }
16715
+ } else {
16716
+ kw.split(" ").forEach(function (kwSplitted) {
16717
+ if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) {
16718
+ stack.push(kwSplitted);
16719
+ }
16720
+ });
16721
+ }
16722
+ });
16723
+ return {
16724
+ "keywords": stack.sort(function (a, b) {
16725
+ return b.length - a.length;
16726
+ }),
16727
+ "length": stack.length
16728
+ };
16729
+ }
16730
+ }, {
16731
+ key: "isNumeric",
16732
+ value: function isNumeric(value) {
16733
+ return Number(parseFloat(value)) == value;
16734
+ }
16735
+ }, {
16736
+ key: "checkRanges",
16737
+ value: function checkRanges(array) {
16738
+ var _this3 = this;
16739
+
16740
+ if (!Array.isArray(array) || Object.prototype.toString.call(array[0]) !== "[object Object]") {
16741
+ this.log("markRanges() will only accept an array of objects");
16742
+ this.opt.noMatch(array);
16743
+ return [];
16744
+ }
16745
+ var stack = [];
16746
+ var last = 0;
16747
+ array.sort(function (a, b) {
16748
+ return a.start - b.start;
16749
+ }).forEach(function (item) {
16750
+ var _callNoMatchOnInvalid = _this3.callNoMatchOnInvalidRanges(item, last),
16751
+ start = _callNoMatchOnInvalid.start,
16752
+ end = _callNoMatchOnInvalid.end,
16753
+ valid = _callNoMatchOnInvalid.valid;
16754
+
16755
+ if (valid) {
16756
+ item.start = start;
16757
+ item.length = end - start;
16758
+ stack.push(item);
16759
+ last = end;
16760
+ }
16761
+ });
16762
+ return stack;
16763
+ }
16764
+ }, {
16765
+ key: "callNoMatchOnInvalidRanges",
16766
+ value: function callNoMatchOnInvalidRanges(range, last) {
16767
+ var start = void 0,
16768
+ end = void 0,
16769
+ valid = false;
16770
+ if (range && typeof range.start !== "undefined") {
16771
+ start = parseInt(range.start, 10);
16772
+ end = start + parseInt(range.length, 10);
16773
+
16774
+ if (this.isNumeric(range.start) && this.isNumeric(range.length) && end - last > 0 && end - start > 0) {
16775
+ valid = true;
16776
+ } else {
16777
+ this.log("Ignoring invalid or overlapping range: " + ("" + JSON.stringify(range)));
16778
+ this.opt.noMatch(range);
16779
+ }
16780
+ } else {
16781
+ this.log("Ignoring invalid range: " + JSON.stringify(range));
16782
+ this.opt.noMatch(range);
16783
+ }
16784
+ return {
16785
+ start: start,
16786
+ end: end,
16787
+ valid: valid
16788
+ };
16789
+ }
16790
+ }, {
16791
+ key: "checkWhitespaceRanges",
16792
+ value: function checkWhitespaceRanges(range, originalLength, string) {
16793
+ var end = void 0,
16794
+ valid = true,
16795
+ max = string.length,
16796
+ offset = originalLength - max,
16797
+ start = parseInt(range.start, 10) - offset;
16798
+
16799
+ start = start > max ? max : start;
16800
+ end = start + parseInt(range.length, 10);
16801
+ if (end > max) {
16802
+ end = max;
16803
+ this.log("End range automatically set to the max value of " + max);
16804
+ }
16805
+ if (start < 0 || end - start < 0 || start > max || end > max) {
16806
+ valid = false;
16807
+ this.log("Invalid range: " + JSON.stringify(range));
16808
+ this.opt.noMatch(range);
16809
+ } else if (string.substring(start, end).replace(/\s+/g, "") === "") {
16810
+ valid = false;
16811
+
16812
+ this.log("Skipping whitespace only range: " + JSON.stringify(range));
16813
+ this.opt.noMatch(range);
16814
+ }
16815
+ return {
16816
+ start: start,
16817
+ end: end,
16818
+ valid: valid
16819
+ };
16820
+ }
16821
+ }, {
16822
+ key: "getTextNodes",
16823
+ value: function getTextNodes(cb) {
16824
+ var _this4 = this;
16825
+
16826
+ var val = "",
16827
+ nodes = [];
16828
+ this.iterator.forEachNode(NodeFilter.SHOW_TEXT, function (node) {
16829
+ nodes.push({
16830
+ start: val.length,
16831
+ end: (val += node.textContent).length,
16832
+ node: node
16833
+ });
16834
+ }, function (node) {
16835
+ if (_this4.matchesExclude(node.parentNode)) {
16836
+ return NodeFilter.FILTER_REJECT;
16837
+ } else {
16838
+ return NodeFilter.FILTER_ACCEPT;
16839
+ }
16840
+ }, function () {
16841
+ cb({
16842
+ value: val,
16843
+ nodes: nodes
16844
+ });
16845
+ });
16846
+ }
16847
+ }, {
16848
+ key: "matchesExclude",
16849
+ value: function matchesExclude(el) {
16850
+ return DOMIterator.matches(el, this.opt.exclude.concat(["script", "style", "title", "head", "html"]));
16851
+ }
16852
+ }, {
16853
+ key: "wrapRangeInTextNode",
16854
+ value: function wrapRangeInTextNode(node, start, end) {
16855
+ var hEl = !this.opt.element ? "mark" : this.opt.element,
16856
+ startNode = node.splitText(start),
16857
+ ret = startNode.splitText(end - start);
16858
+ var repl = document.createElement(hEl);
16859
+ repl.setAttribute("data-markjs", "true");
16860
+ if (this.opt.className) {
16861
+ repl.setAttribute("class", this.opt.className);
16862
+ }
16863
+ repl.textContent = startNode.textContent;
16864
+ startNode.parentNode.replaceChild(repl, startNode);
16865
+ return ret;
16866
+ }
16867
+ }, {
16868
+ key: "wrapRangeInMappedTextNode",
16869
+ value: function wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) {
16870
+ var _this5 = this;
16871
+
16872
+ dict.nodes.every(function (n, i) {
16873
+ var sibl = dict.nodes[i + 1];
16874
+ if (typeof sibl === "undefined" || sibl.start > start) {
16875
+ if (!filterCb(n.node)) {
16876
+ return false;
16877
+ }
16878
+
16879
+ var s = start - n.start,
16880
+ e = (end > n.end ? n.end : end) - n.start,
16881
+ startStr = dict.value.substr(0, n.start),
16882
+ endStr = dict.value.substr(e + n.start);
16883
+ n.node = _this5.wrapRangeInTextNode(n.node, s, e);
16884
+
16885
+ dict.value = startStr + endStr;
16886
+ dict.nodes.forEach(function (k, j) {
16887
+ if (j >= i) {
16888
+ if (dict.nodes[j].start > 0 && j !== i) {
16889
+ dict.nodes[j].start -= e;
16890
+ }
16891
+ dict.nodes[j].end -= e;
16892
+ }
16893
+ });
16894
+ end -= e;
16895
+ eachCb(n.node.previousSibling, n.start);
16896
+ if (end > n.end) {
16897
+ start = n.end;
16898
+ } else {
16899
+ return false;
16900
+ }
16901
+ }
16902
+ return true;
16903
+ });
16904
+ }
16905
+ }, {
16906
+ key: "wrapMatches",
16907
+ value: function wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) {
16908
+ var _this6 = this;
16909
+
16910
+ var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
16911
+ this.getTextNodes(function (dict) {
16912
+ dict.nodes.forEach(function (node) {
16913
+ node = node.node;
16914
+ var match = void 0;
16915
+ while ((match = regex.exec(node.textContent)) !== null && match[matchIdx] !== "") {
16916
+ if (!filterCb(match[matchIdx], node)) {
16917
+ continue;
16918
+ }
16919
+ var pos = match.index;
16920
+ if (matchIdx !== 0) {
16921
+ for (var i = 1; i < matchIdx; i++) {
16922
+ pos += match[i].length;
16923
+ }
16924
+ }
16925
+ node = _this6.wrapRangeInTextNode(node, pos, pos + match[matchIdx].length);
16926
+ eachCb(node.previousSibling);
16927
+
16928
+ regex.lastIndex = 0;
16929
+ }
16930
+ });
16931
+ endCb();
16932
+ });
16933
+ }
16934
+ }, {
16935
+ key: "wrapMatchesAcrossElements",
16936
+ value: function wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) {
16937
+ var _this7 = this;
16938
+
16939
+ var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
16940
+ this.getTextNodes(function (dict) {
16941
+ var match = void 0;
16942
+ while ((match = regex.exec(dict.value)) !== null && match[matchIdx] !== "") {
16943
+ var start = match.index;
16944
+ if (matchIdx !== 0) {
16945
+ for (var i = 1; i < matchIdx; i++) {
16946
+ start += match[i].length;
16947
+ }
16948
+ }
16949
+ var end = start + match[matchIdx].length;
16950
+
16951
+ _this7.wrapRangeInMappedTextNode(dict, start, end, function (node) {
16952
+ return filterCb(match[matchIdx], node);
16953
+ }, function (node, lastIndex) {
16954
+ regex.lastIndex = lastIndex;
16955
+ eachCb(node);
16956
+ });
16957
+ }
16958
+ endCb();
16959
+ });
16960
+ }
16961
+ }, {
16962
+ key: "wrapRangeFromIndex",
16963
+ value: function wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) {
16964
+ var _this8 = this;
16965
+
16966
+ this.getTextNodes(function (dict) {
16967
+ var originalLength = dict.value.length;
16968
+ ranges.forEach(function (range, counter) {
16969
+ var _checkWhitespaceRange = _this8.checkWhitespaceRanges(range, originalLength, dict.value),
16970
+ start = _checkWhitespaceRange.start,
16971
+ end = _checkWhitespaceRange.end,
16972
+ valid = _checkWhitespaceRange.valid;
16973
+
16974
+ if (valid) {
16975
+ _this8.wrapRangeInMappedTextNode(dict, start, end, function (node) {
16976
+ return filterCb(node, range, dict.value.substring(start, end), counter);
16977
+ }, function (node) {
16978
+ eachCb(node, range);
16979
+ });
16980
+ }
16981
+ });
16982
+ endCb();
16983
+ });
16984
+ }
16985
+ }, {
16986
+ key: "unwrapMatches",
16987
+ value: function unwrapMatches(node) {
16988
+ var parent = node.parentNode;
16989
+ var docFrag = document.createDocumentFragment();
16990
+ while (node.firstChild) {
16991
+ docFrag.appendChild(node.removeChild(node.firstChild));
16992
+ }
16993
+ parent.replaceChild(docFrag, node);
16994
+ if (!this.ie) {
16995
+ parent.normalize();
16996
+ } else {
16997
+ this.normalizeTextNode(parent);
16998
+ }
16999
+ }
17000
+ }, {
17001
+ key: "normalizeTextNode",
17002
+ value: function normalizeTextNode(node) {
17003
+ if (!node) {
17004
+ return;
17005
+ }
17006
+ if (node.nodeType === 3) {
17007
+ while (node.nextSibling && node.nextSibling.nodeType === 3) {
17008
+ node.nodeValue += node.nextSibling.nodeValue;
17009
+ node.parentNode.removeChild(node.nextSibling);
17010
+ }
17011
+ } else {
17012
+ this.normalizeTextNode(node.firstChild);
17013
+ }
17014
+ this.normalizeTextNode(node.nextSibling);
17015
+ }
17016
+ }, {
17017
+ key: "markRegExp",
17018
+ value: function markRegExp(regexp, opt) {
17019
+ var _this9 = this;
17020
+
17021
+ this.opt = opt;
17022
+ this.log("Searching with expression \"" + regexp + "\"");
17023
+ var totalMatches = 0,
17024
+ fn = "wrapMatches";
17025
+ var eachCb = function eachCb(element) {
17026
+ totalMatches++;
17027
+ _this9.opt.each(element);
17028
+ };
17029
+ if (this.opt.acrossElements) {
17030
+ fn = "wrapMatchesAcrossElements";
17031
+ }
17032
+ this[fn](regexp, this.opt.ignoreGroups, function (match, node) {
17033
+ return _this9.opt.filter(node, match, totalMatches);
17034
+ }, eachCb, function () {
17035
+ if (totalMatches === 0) {
17036
+ _this9.opt.noMatch(regexp);
17037
+ }
17038
+ _this9.opt.done(totalMatches);
17039
+ });
17040
+ }
17041
+ }, {
17042
+ key: "mark",
17043
+ value: function mark(sv, opt) {
17044
+ var _this10 = this;
17045
+
17046
+ this.opt = opt;
17047
+ var totalMatches = 0,
17048
+ fn = "wrapMatches";
17049
+
17050
+ var _getSeparatedKeywords = this.getSeparatedKeywords(typeof sv === "string" ? [sv] : sv),
17051
+ kwArr = _getSeparatedKeywords.keywords,
17052
+ kwArrLen = _getSeparatedKeywords.length,
17053
+ sens = this.opt.caseSensitive ? "" : "i",
17054
+ handler = function handler(kw) {
17055
+ var regex = new RegExp(_this10.createRegExp(kw), "gm" + sens),
17056
+ matches = 0;
17057
+ _this10.log("Searching with expression \"" + regex + "\"");
17058
+ _this10[fn](regex, 1, function (term, node) {
17059
+ return _this10.opt.filter(node, kw, totalMatches, matches);
17060
+ }, function (element) {
17061
+ matches++;
17062
+ totalMatches++;
17063
+ _this10.opt.each(element);
17064
+ }, function () {
17065
+ if (matches === 0) {
17066
+ _this10.opt.noMatch(kw);
17067
+ }
17068
+ if (kwArr[kwArrLen - 1] === kw) {
17069
+ _this10.opt.done(totalMatches);
17070
+ } else {
17071
+ handler(kwArr[kwArr.indexOf(kw) + 1]);
17072
+ }
17073
+ });
17074
+ };
17075
+
17076
+ if (this.opt.acrossElements) {
17077
+ fn = "wrapMatchesAcrossElements";
17078
+ }
17079
+ if (kwArrLen === 0) {
17080
+ this.opt.done(totalMatches);
17081
+ } else {
17082
+ handler(kwArr[0]);
17083
+ }
17084
+ }
17085
+ }, {
17086
+ key: "markRanges",
17087
+ value: function markRanges(rawRanges, opt) {
17088
+ var _this11 = this;
17089
+
17090
+ this.opt = opt;
17091
+ var totalMatches = 0,
17092
+ ranges = this.checkRanges(rawRanges);
17093
+ if (ranges && ranges.length) {
17094
+ this.log("Starting to mark with the following ranges: " + JSON.stringify(ranges));
17095
+ this.wrapRangeFromIndex(ranges, function (node, range, match, counter) {
17096
+ return _this11.opt.filter(node, range, match, counter);
17097
+ }, function (element, range) {
17098
+ totalMatches++;
17099
+ _this11.opt.each(element, range);
17100
+ }, function () {
17101
+ _this11.opt.done(totalMatches);
17102
+ });
17103
+ } else {
17104
+ this.opt.done(totalMatches);
17105
+ }
17106
+ }
17107
+ }, {
17108
+ key: "unmark",
17109
+ value: function unmark(opt) {
17110
+ var _this12 = this;
17111
+
17112
+ this.opt = opt;
17113
+ var sel = this.opt.element ? this.opt.element : "*";
17114
+ sel += "[data-markjs]";
17115
+ if (this.opt.className) {
17116
+ sel += "." + this.opt.className;
17117
+ }
17118
+ this.log("Removal selector \"" + sel + "\"");
17119
+ this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, function (node) {
17120
+ _this12.unwrapMatches(node);
17121
+ }, function (node) {
17122
+ var matchesSel = DOMIterator.matches(node, sel),
17123
+ matchesExclude = _this12.matchesExclude(node);
17124
+ if (!matchesSel || matchesExclude) {
17125
+ return NodeFilter.FILTER_REJECT;
17126
+ } else {
17127
+ return NodeFilter.FILTER_ACCEPT;
17128
+ }
17129
+ }, this.opt.done);
17130
+ }
17131
+ }, {
17132
+ key: "opt",
17133
+ set: function set(val) {
17134
+ this._opt = _extends({}, {
17135
+ "element": "",
17136
+ "className": "",
17137
+ "exclude": [],
17138
+ "iframes": false,
17139
+ "iframesTimeout": 5000,
17140
+ "separateWordSearch": true,
17141
+ "diacritics": true,
17142
+ "synonyms": {},
17143
+ "accuracy": "partially",
17144
+ "acrossElements": false,
17145
+ "caseSensitive": false,
17146
+ "ignoreJoiners": false,
17147
+ "ignoreGroups": 0,
17148
+ "ignorePunctuation": [],
17149
+ "wildcards": "disabled",
17150
+ "each": function each() {},
17151
+ "noMatch": function noMatch() {},
17152
+ "filter": function filter() {
17153
+ return true;
17154
+ },
17155
+ "done": function done() {},
17156
+ "debug": false,
17157
+ "log": window.console
17158
+ }, val);
17159
+ },
17160
+ get: function get() {
17161
+ return this._opt;
17162
+ }
17163
+ }, {
17164
+ key: "iterator",
17165
+ get: function get() {
17166
+ return new DOMIterator(this.ctx, this.opt.iframes, this.opt.exclude, this.opt.iframesTimeout);
17167
+ }
17168
+ }]);
17169
+
17170
+ return Mark;
17171
+ }();
17172
+
17173
+ var DOMIterator = function () {
17174
+ function DOMIterator(ctx) {
17175
+ var iframes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
17176
+ var exclude = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
17177
+ var iframesTimeout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5000;
17178
+
17179
+ _classCallCheck(this, DOMIterator);
17180
+
17181
+ this.ctx = ctx;
17182
+
17183
+ this.iframes = iframes;
17184
+
17185
+ this.exclude = exclude;
17186
+
17187
+ this.iframesTimeout = iframesTimeout;
17188
+ }
17189
+
17190
+ _createClass(DOMIterator, [{
17191
+ key: "getContexts",
17192
+ value: function getContexts() {
17193
+ var ctx = void 0,
17194
+ filteredCtx = [];
17195
+ if (typeof this.ctx === "undefined" || !this.ctx) {
17196
+ ctx = [];
17197
+ } else if (NodeList.prototype.isPrototypeOf(this.ctx)) {
17198
+ ctx = Array.prototype.slice.call(this.ctx);
17199
+ } else if (Array.isArray(this.ctx)) {
17200
+ ctx = this.ctx;
17201
+ } else if (typeof this.ctx === "string") {
17202
+ ctx = Array.prototype.slice.call(document.querySelectorAll(this.ctx));
17203
+ } else {
17204
+ ctx = [this.ctx];
17205
+ }
17206
+
17207
+ ctx.forEach(function (ctx) {
17208
+ var isDescendant = filteredCtx.filter(function (contexts) {
17209
+ return contexts.contains(ctx);
17210
+ }).length > 0;
17211
+ if (filteredCtx.indexOf(ctx) === -1 && !isDescendant) {
17212
+ filteredCtx.push(ctx);
17213
+ }
17214
+ });
17215
+ return filteredCtx;
17216
+ }
17217
+ }, {
17218
+ key: "getIframeContents",
17219
+ value: function getIframeContents(ifr, successFn) {
17220
+ var errorFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
17221
+
17222
+ var doc = void 0;
17223
+ try {
17224
+ var ifrWin = ifr.contentWindow;
17225
+ doc = ifrWin.document;
17226
+ if (!ifrWin || !doc) {
17227
+ throw new Error("iframe inaccessible");
17228
+ }
17229
+ } catch (e) {
17230
+ errorFn();
17231
+ }
17232
+ if (doc) {
17233
+ successFn(doc);
17234
+ }
17235
+ }
17236
+ }, {
17237
+ key: "isIframeBlank",
17238
+ value: function isIframeBlank(ifr) {
17239
+ var bl = "about:blank",
17240
+ src = ifr.getAttribute("src").trim(),
17241
+ href = ifr.contentWindow.location.href;
17242
+ return href === bl && src !== bl && src;
17243
+ }
17244
+ }, {
17245
+ key: "observeIframeLoad",
17246
+ value: function observeIframeLoad(ifr, successFn, errorFn) {
17247
+ var _this13 = this;
17248
+
17249
+ var called = false,
17250
+ tout = null;
17251
+ var listener = function listener() {
17252
+ if (called) {
17253
+ return;
17254
+ }
17255
+ called = true;
17256
+ clearTimeout(tout);
17257
+ try {
17258
+ if (!_this13.isIframeBlank(ifr)) {
17259
+ ifr.removeEventListener("load", listener);
17260
+ _this13.getIframeContents(ifr, successFn, errorFn);
17261
+ }
17262
+ } catch (e) {
17263
+ errorFn();
17264
+ }
17265
+ };
17266
+ ifr.addEventListener("load", listener);
17267
+ tout = setTimeout(listener, this.iframesTimeout);
17268
+ }
17269
+ }, {
17270
+ key: "onIframeReady",
17271
+ value: function onIframeReady(ifr, successFn, errorFn) {
17272
+ try {
17273
+ if (ifr.contentWindow.document.readyState === "complete") {
17274
+ if (this.isIframeBlank(ifr)) {
17275
+ this.observeIframeLoad(ifr, successFn, errorFn);
17276
+ } else {
17277
+ this.getIframeContents(ifr, successFn, errorFn);
17278
+ }
17279
+ } else {
17280
+ this.observeIframeLoad(ifr, successFn, errorFn);
17281
+ }
17282
+ } catch (e) {
17283
+ errorFn();
17284
+ }
17285
+ }
17286
+ }, {
17287
+ key: "waitForIframes",
17288
+ value: function waitForIframes(ctx, done) {
17289
+ var _this14 = this;
17290
+
17291
+ var eachCalled = 0;
17292
+ this.forEachIframe(ctx, function () {
17293
+ return true;
17294
+ }, function (ifr) {
17295
+ eachCalled++;
17296
+ _this14.waitForIframes(ifr.querySelector("html"), function () {
17297
+ if (! --eachCalled) {
17298
+ done();
17299
+ }
17300
+ });
17301
+ }, function (handled) {
17302
+ if (!handled) {
17303
+ done();
17304
+ }
17305
+ });
17306
+ }
17307
+ }, {
17308
+ key: "forEachIframe",
17309
+ value: function forEachIframe(ctx, filter, each) {
17310
+ var _this15 = this;
17311
+
17312
+ var end = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
17313
+
17314
+ var ifr = ctx.querySelectorAll("iframe"),
17315
+ open = ifr.length,
17316
+ handled = 0;
17317
+ ifr = Array.prototype.slice.call(ifr);
17318
+ var checkEnd = function checkEnd() {
17319
+ if (--open <= 0) {
17320
+ end(handled);
17321
+ }
17322
+ };
17323
+ if (!open) {
17324
+ checkEnd();
17325
+ }
17326
+ ifr.forEach(function (ifr) {
17327
+ if (DOMIterator.matches(ifr, _this15.exclude)) {
17328
+ checkEnd();
17329
+ } else {
17330
+ _this15.onIframeReady(ifr, function (con) {
17331
+ if (filter(ifr)) {
17332
+ handled++;
17333
+ each(con);
17334
+ }
17335
+ checkEnd();
17336
+ }, checkEnd);
17337
+ }
17338
+ });
17339
+ }
17340
+ }, {
17341
+ key: "createIterator",
17342
+ value: function createIterator(ctx, whatToShow, filter) {
17343
+ return document.createNodeIterator(ctx, whatToShow, filter, false);
17344
+ }
17345
+ }, {
17346
+ key: "createInstanceOnIframe",
17347
+ value: function createInstanceOnIframe(contents) {
17348
+ return new DOMIterator(contents.querySelector("html"), this.iframes);
17349
+ }
17350
+ }, {
17351
+ key: "compareNodeIframe",
17352
+ value: function compareNodeIframe(node, prevNode, ifr) {
17353
+ var compCurr = node.compareDocumentPosition(ifr),
17354
+ prev = Node.DOCUMENT_POSITION_PRECEDING;
17355
+ if (compCurr & prev) {
17356
+ if (prevNode !== null) {
17357
+ var compPrev = prevNode.compareDocumentPosition(ifr),
17358
+ after = Node.DOCUMENT_POSITION_FOLLOWING;
17359
+ if (compPrev & after) {
17360
+ return true;
17361
+ }
17362
+ } else {
17363
+ return true;
17364
+ }
17365
+ }
17366
+ return false;
17367
+ }
17368
+ }, {
17369
+ key: "getIteratorNode",
17370
+ value: function getIteratorNode(itr) {
17371
+ var prevNode = itr.previousNode();
17372
+ var node = void 0;
17373
+ if (prevNode === null) {
17374
+ node = itr.nextNode();
17375
+ } else {
17376
+ node = itr.nextNode() && itr.nextNode();
17377
+ }
17378
+ return {
17379
+ prevNode: prevNode,
17380
+ node: node
17381
+ };
17382
+ }
17383
+ }, {
17384
+ key: "checkIframeFilter",
17385
+ value: function checkIframeFilter(node, prevNode, currIfr, ifr) {
17386
+ var key = false,
17387
+ handled = false;
17388
+ ifr.forEach(function (ifrDict, i) {
17389
+ if (ifrDict.val === currIfr) {
17390
+ key = i;
17391
+ handled = ifrDict.handled;
17392
+ }
17393
+ });
17394
+ if (this.compareNodeIframe(node, prevNode, currIfr)) {
17395
+ if (key === false && !handled) {
17396
+ ifr.push({
17397
+ val: currIfr,
17398
+ handled: true
17399
+ });
17400
+ } else if (key !== false && !handled) {
17401
+ ifr[key].handled = true;
17402
+ }
17403
+ return true;
17404
+ }
17405
+ if (key === false) {
17406
+ ifr.push({
17407
+ val: currIfr,
17408
+ handled: false
17409
+ });
17410
+ }
17411
+ return false;
17412
+ }
17413
+ }, {
17414
+ key: "handleOpenIframes",
17415
+ value: function handleOpenIframes(ifr, whatToShow, eCb, fCb) {
17416
+ var _this16 = this;
17417
+
17418
+ ifr.forEach(function (ifrDict) {
17419
+ if (!ifrDict.handled) {
17420
+ _this16.getIframeContents(ifrDict.val, function (con) {
17421
+ _this16.createInstanceOnIframe(con).forEachNode(whatToShow, eCb, fCb);
17422
+ });
17423
+ }
17424
+ });
17425
+ }
17426
+ }, {
17427
+ key: "iterateThroughNodes",
17428
+ value: function iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) {
17429
+ var _this17 = this;
17430
+
17431
+ var itr = this.createIterator(ctx, whatToShow, filterCb);
17432
+ var ifr = [],
17433
+ elements = [],
17434
+ node = void 0,
17435
+ prevNode = void 0,
17436
+ retrieveNodes = function retrieveNodes() {
17437
+ var _getIteratorNode = _this17.getIteratorNode(itr);
17438
+
17439
+ prevNode = _getIteratorNode.prevNode;
17440
+ node = _getIteratorNode.node;
17441
+
17442
+ return node;
17443
+ };
17444
+ while (retrieveNodes()) {
17445
+ if (this.iframes) {
17446
+ this.forEachIframe(ctx, function (currIfr) {
17447
+ return _this17.checkIframeFilter(node, prevNode, currIfr, ifr);
17448
+ }, function (con) {
17449
+ _this17.createInstanceOnIframe(con).forEachNode(whatToShow, function (ifrNode) {
17450
+ return elements.push(ifrNode);
17451
+ }, filterCb);
17452
+ });
17453
+ }
17454
+
17455
+ elements.push(node);
17456
+ }
17457
+ elements.forEach(function (node) {
17458
+ eachCb(node);
17459
+ });
17460
+ if (this.iframes) {
17461
+ this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb);
17462
+ }
17463
+ doneCb();
17464
+ }
17465
+ }, {
17466
+ key: "forEachNode",
17467
+ value: function forEachNode(whatToShow, each, filter) {
17468
+ var _this18 = this;
17469
+
17470
+ var done = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
17471
+
17472
+ var contexts = this.getContexts();
17473
+ var open = contexts.length;
17474
+ if (!open) {
17475
+ done();
17476
+ }
17477
+ contexts.forEach(function (ctx) {
17478
+ var ready = function ready() {
17479
+ _this18.iterateThroughNodes(whatToShow, ctx, each, filter, function () {
17480
+ if (--open <= 0) {
17481
+ done();
17482
+ }
17483
+ });
17484
+ };
17485
+
17486
+ if (_this18.iframes) {
17487
+ _this18.waitForIframes(ctx, ready);
17488
+ } else {
17489
+ ready();
17490
+ }
17491
+ });
17492
+ }
17493
+ }], [{
17494
+ key: "matches",
17495
+ value: function matches(element, selector) {
17496
+ var selectors = typeof selector === "string" ? [selector] : selector,
17497
+ fn = element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.webkitMatchesSelector;
17498
+ if (fn) {
17499
+ var match = false;
17500
+ selectors.every(function (sel) {
17501
+ if (fn.call(element, sel)) {
17502
+ match = true;
17503
+ return false;
17504
+ }
17505
+ return true;
17506
+ });
17507
+ return match;
17508
+ } else {
17509
+ return false;
17510
+ }
17511
+ }
17512
+ }]);
17513
+
17514
+ return DOMIterator;
17515
+ }();
17516
+
17517
+ $.fn.mark = function (sv, opt) {
17518
+ new Mark(this.get()).mark(sv, opt);
17519
+ return this;
17520
+ };
17521
+ $.fn.markRegExp = function (regexp, opt) {
17522
+ new Mark(this.get()).markRegExp(regexp, opt);
17523
+ return this;
17524
+ };
17525
+ $.fn.markRanges = function (ranges, opt) {
17526
+ new Mark(this.get()).markRanges(ranges, opt);
17527
+ return this;
17528
+ };
17529
+ $.fn.unmark = function (opt) {
17530
+ new Mark(this.get()).unmark(opt);
17531
+ return this;
17532
+ };
17533
+ return $;
17534
+ }, window, document);
17535
+
17536
+ /*!***************************************************
17537
+ * datatables.mark.js v2.0.1
17538
+ * https://github.com/julmot/datatables.mark.js
17539
+ * Copyright (c) 2016–2017, Julian Motz
17540
+ * Released under the MIT license https://git.io/voRZ7
17541
+ *****************************************************/
17542
+
17543
+ 'use strict';
17544
+
17545
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
17546
+
17547
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
17548
+
17549
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17550
+
17551
+ (function (factory, window, document) {
17552
+ if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
17553
+ var jquery = require('jquery');
17554
+ require('datatables.net');
17555
+ require('mark.js/dist/jquery.mark.js');
17556
+ module.exports = factory(window, document, jquery);
17557
+ } else if (typeof define === 'function' && define.amd) {
17558
+ define(['jquery', 'datatables.net', 'markjs'], function (jQuery) {
17559
+ return factory(window, document, jQuery);
17560
+ });
17561
+ } else {
17562
+ factory(window, document, jQuery);
17563
+ }
17564
+ })(function (window, document, $) {
17565
+ var MarkDataTables = function () {
17566
+ function MarkDataTables(dtInstance, options) {
17567
+ _classCallCheck(this, MarkDataTables);
17568
+
17569
+ if (!$.fn.mark || !$.fn.unmark) {
17570
+ throw new Error('jquery.mark.js is necessary for datatables.mark.js');
17571
+ }
17572
+ this.instance = dtInstance;
17573
+ this.options = (typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' ? options : {};
17574
+ this.intervalThreshold = 49;
17575
+ this.intervalMs = 300;
17576
+ this.initMarkListener();
17577
+ }
17578
+
17579
+ _createClass(MarkDataTables, [{
17580
+ key: 'initMarkListener',
17581
+ value: function initMarkListener() {
17582
+ var _this = this;
17583
+
17584
+ var ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth';
17585
+ var intvl = null;
17586
+ this.instance.on(ev, function () {
17587
+ var rows = _this.instance.rows({
17588
+ filter: 'applied',
17589
+ page: 'current'
17590
+ }).nodes().length;
17591
+ if (rows > _this.intervalThreshold) {
17592
+ clearTimeout(intvl);
17593
+ intvl = setTimeout(function () {
17594
+ _this.mark();
17595
+ }, _this.intervalMs);
17596
+ } else {
17597
+ _this.mark();
17598
+ }
17599
+ });
17600
+ this.instance.on('destroy', function () {
17601
+ _this.instance.off(ev);
17602
+ });
17603
+ this.mark();
17604
+ }
17605
+ }, {
17606
+ key: 'mark',
17607
+ value: function mark() {
17608
+ var _this2 = this;
17609
+
17610
+ var globalSearch = this.instance.search();
17611
+ $(this.instance.table().body()).unmark(this.options);
17612
+ this.instance.columns({
17613
+ search: 'applied',
17614
+ page: 'current'
17615
+ }).nodes().each(function (nodes, colIndex) {
17616
+ var columnSearch = _this2.instance.column(colIndex).search(),
17617
+ searchVal = columnSearch || globalSearch;
17618
+ if (searchVal) {
17619
+ nodes.forEach(function (node) {
17620
+ $(node).mark(searchVal, _this2.options);
17621
+ });
17622
+ }
17623
+ });
17624
+ }
17625
+ }]);
17626
+
17627
+ return MarkDataTables;
17628
+ }();
17629
+
17630
+ $(document).on('init.dt.dth', function (event, settings) {
17631
+ if (event.namespace !== 'dt') {
17632
+ return;
17633
+ }
17634
+
17635
+ var dtInstance = $.fn.dataTable.Api(settings);
17636
+
17637
+ var options = null;
17638
+ if (dtInstance.init().mark) {
17639
+ options = dtInstance.init().mark;
17640
+ } else if ($.fn.dataTable.defaults.mark) {
17641
+ options = $.fn.dataTable.defaults.mark;
17642
+ }
17643
+ if (options === null) {
17644
+ return;
17645
+ }
17646
+
17647
+ new MarkDataTables(dtInstance, options);
17648
+ });
17649
+ }, window, document);
admin/datatables/js/datatables-all.min.js ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ DataTables 1.10.16
3
+ 2008-2017 SpryMedia Ltd - datatables.net/license
4
+ */
5
+ (function(h){"function"===typeof define&&define.amd?define(["jquery"],function(E){return h(E,window,document)}):"object"===typeof exports?module.exports=function(E,G){E||(E=window);G||(G="undefined"!==typeof window?require("jquery"):require("jquery")(E));return h(G,E,E.document)}:h(jQuery,window,document)})(function(h,E,G,k){function X(a){var b,c,d={};h.each(a,function(e){if((b=e.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=e.replace(b[0],b[2].toLowerCase()),
6
+ d[c]=e,"o"===b[1]&&X(a[e])});a._hungarianMap=d}function I(a,b,c){a._hungarianMap||X(a);var d;h.each(b,function(e){d=a._hungarianMap[e];if(d!==k&&(c||b[d]===k))"o"===d.charAt(0)?(b[d]||(b[d]={}),h.extend(!0,b[d],b[e]),I(a[d],b[d],c)):b[d]=b[e]})}function Ca(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&F(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&F(a,a,"sZeroRecords","sLoadingRecords");
7
+ a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&cb(a)}function db(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");"boolean"===typeof a.sScrollX&&(a.sScrollX=a.sScrollX?"100%":"");"boolean"===typeof a.scrollX&&(a.scrollX=
8
+ a.scrollX?"100%":"");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&I(m.models.oSearch,a[b])}function eb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;"number"===typeof b&&!h.isArray(b)&&(a.aDataSort=[b])}function fb(a){if(!m.__browser){var b={};m.__browser=b;var c=h("<div/>").css({position:"fixed",top:0,left:-1*h(E).scrollLeft(),height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
9
+ top:1,left:1,width:100,overflow:"scroll"}).append(h("<div/>").css({width:"100%",height:10}))).appendTo("body"),d=c.children(),e=d.children();b.barWidth=d[0].offsetWidth-d[0].clientWidth;b.bScrollOversize=100===e[0].offsetWidth&&100!==d[0].clientWidth;b.bScrollbarLeft=1!==Math.round(e.offset().left);b.bBounding=c[0].getBoundingClientRect().width?!0:!1;c.remove()}h.extend(a.oBrowser,m.__browser);a.oScroll.iBarWidth=m.__browser.barWidth}function gb(a,b,c,d,e,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;d!==
10
+ e;)a.hasOwnProperty(d)&&(g=j?b(g,a[d],d,a):a[d],j=!0,d+=f);return g}function Da(a,b){var c=m.defaults.column,d=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:G.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[d],mData:c.mData?c.mData:d,idx:d});a.aoColumns.push(c);c=a.aoPreSearchCols;c[d]=h.extend({},m.models.oSearch,c[d]);ja(a,d,h(b).data())}function ja(a,b,c){var b=a.aoColumns[b],d=a.oClasses,e=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=
11
+ e.attr("width")||null;var f=(e.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(eb(c),I(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),c.sClass&&e.addClass(c.sClass),h.extend(b,c),F(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),F(b,c,"aDataSort"));var g=b.mData,j=Q(g),i=b.mRender?Q(b.mRender):null,c=function(a){return"string"===
12
+ typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b._setter=null;b.fnGetData=function(a,b,c){var d=j(a,b,k,c);return i&&b?i(d,b,a,c):d};b.fnSetData=function(a,b,c){return R(g)(a,b,c)};"number"!==typeof g&&(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,e.addClass(d.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=d.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=
13
+ d.sSortableAsc,b.sSortingClassJUI=d.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=d.sSortableDesc,b.sSortingClassJUI=d.sSortJUIDescAllowed):(b.sSortingClass=d.sSortable,b.sSortingClassJUI=d.sSortJUI)}function Y(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Ea(a);for(var c=0,d=b.length;c<d;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&ka(a);r(a,null,"column-sizing",[a])}function Z(a,b){var c=la(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=
14
+ la(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function aa(a){var b=0;h.each(a.aoColumns,function(a,d){d.bVisible&&"none"!==h(d.nTh).css("display")&&b++});return b}function la(a,b){var c=[];h.map(a.aoColumns,function(a,e){a[b]&&c.push(e)});return c}function Fa(a){var b=a.aoColumns,c=a.aoData,d=m.ext.type.detect,e,f,g,j,i,h,l,q,t;e=0;for(f=b.length;e<f;e++)if(l=b[e],t=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=d.length;g<j;g++){i=0;for(h=c.length;i<h;i++){t[i]===
15
+ k&&(t[i]=B(a,i,e,"type"));q=d[g](t[i],a);if(!q&&g!==d.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function hb(a,b,c,d){var e,f,g,j,i,n,l=a.aoColumns;if(b)for(e=b.length-1;0<=e;e--){n=b[e];var q=n.targets!==k?n.targets:n.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Da(a);d(q[f],n)}else if("number"===typeof q[f]&&0>q[f])d(l.length+q[f],n);else if("string"===typeof q[f]){j=0;for(i=l.length;j<
16
+ i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&d(j,n)}}if(c){e=0;for(a=c.length;e<a;e++)d(e,c[e])}}function M(a,b,c,d){var e=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data",idx:e});f._aData=b;a.aoData.push(f);for(var g=a.aoColumns,j=0,i=g.length;j<i;j++)g[j].sType=null;a.aiDisplayMaster.push(e);b=a.rowIdFn(b);b!==k&&(a.aIds[b]=f);(c||!a.oFeatures.bDeferRender)&&Ga(a,e,c,d);return e}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,e){c=Ha(a,e);return M(a,
17
+ c.data,e,c.cells)})}function B(a,b,c,d){var e=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,i=f.fnGetData(g,d,{settings:a,row:b,col:c});if(i===k)return a.iDrawError!=e&&null===j&&(J(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b+", column "+c,4),a.iDrawError=e),j;if((i===g||null===i)&&null!==j&&d!==k)i=j;else if("function"===typeof i)return i.call(g);return null===i&&"display"==d?"":i}function ib(a,b,c,d){a.aoColumns[c].fnSetData(a.aoData[b]._aData,
18
+ d,{settings:a,row:b,col:c})}function Ia(a){return h.map(a.match(/(\\.|[^\.])+/g)||[""],function(a){return a.replace(/\\\./g,".")})}function Q(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=Q(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,
19
+ b,f){var g,j;if(""!==f){j=Ia(f);for(var i=0,n=j.length;i<n;i++){f=j[i].match(ba);g=j[i].match(U);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");if(h.isArray(a)){i=0;for(n=a.length;i<n;i++)g.push(c(a[i],b,j))}a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(U,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===k)return k;a=a[j[i]]}}return a};return function(b,e){return c(b,e,a)}}return function(b){return b[a]}}function R(a){if(h.isPlainObject(a))return R(a._);
20
+ if(null===a)return function(){};if("function"===typeof a)return function(b,d,e){a(b,"set",d,e)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,d,e){var e=Ia(e),f;f=e[e.length-1];for(var g,j,i=0,n=e.length-1;i<n;i++){g=e[i].match(ba);j=e[i].match(U);if(g){e[i]=e[i].replace(ba,"");a[e[i]]=[];f=e.slice();f.splice(0,i+1);g=f.join(".");if(h.isArray(d)){j=0;for(n=d.length;j<n;j++)f={},b(f,d[j],g),a[e[i]].push(f)}else a[e[i]]=d;return}j&&(e[i]=e[i].replace(U,
21
+ ""),a=a[e[i]](d));if(null===a[e[i]]||a[e[i]]===k)a[e[i]]={};a=a[e[i]]}if(f.match(U))a[f.replace(U,"")](d);else a[f.replace(ba,"")]=d};return function(c,d){return b(c,d,a)}}return function(b,d){b[a]=d}}function Ja(a){return D(a.aoData,"_aData")}function na(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0;a.aIds={}}function oa(a,b,c){for(var d=-1,e=0,f=a.length;e<f;e++)a[e]==b?d=e:a[e]>b&&a[e]--; -1!=d&&c===k&&a.splice(d,1)}function ca(a,b,c,d){var e=a.aoData[b],f,g=function(c,d){for(;c.childNodes.length;)c.removeChild(c.firstChild);
22
+ c.innerHTML=B(a,b,d,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===e.src)e._aData=Ha(a,e,d,d===k?k:e._aData).data;else{var j=e.anCells;if(j)if(d!==k)g(j[d],d);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}e._aSortData=null;e._aFilterData=null;g=a.aoColumns;if(d!==k)g[d].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;Ka(a,e)}}function Ha(a,b,c,d){var e=[],f=b.firstChild,g,j,i=0,n,l=a.aoColumns,q=a._rowReadObject,d=d!==k?d:q?{}:[],t=function(a,b){if("string"===typeof a){var c=a.indexOf("@");
23
+ -1!==c&&(c=a.substring(c+1),R(a)(d,b.getAttribute(c)))}},m=function(a){if(c===k||c===i)j=l[i],n=h.trim(a.innerHTML),j&&j._bAttrSrc?(R(j.mData._)(d,n),t(j.mData.sort,a),t(j.mData.type,a),t(j.mData.filter,a)):q?(j._setter||(j._setter=R(j.mData)),j._setter(d,n)):d[i]=n;i++};if(f)for(;f;){g=f.nodeName.toUpperCase();if("TD"==g||"TH"==g)m(f),e.push(f);f=f.nextSibling}else{e=b.anCells;f=0;for(g=e.length;f<g;f++)m(e[f])}if(b=b.firstChild?b:b.nTr)(b=b.getAttribute("id"))&&R(a.rowId)(d,b);return{data:d,cells:e}}
24
+ function Ga(a,b,c,d){var e=a.aoData[b],f=e._aData,g=[],j,i,n,l,q;if(null===e.nTr){j=c||G.createElement("tr");e.nTr=j;e.anCells=g;j._DT_RowIndex=b;Ka(a,e);l=0;for(q=a.aoColumns.length;l<q;l++){n=a.aoColumns[l];i=c?d[l]:G.createElement(n.sCellType);i._DT_CellIndex={row:b,column:l};g.push(i);if((!c||n.mRender||n.mData!==l)&&(!h.isPlainObject(n.mData)||n.mData._!==l+".display"))i.innerHTML=B(a,b,l,"display");n.sClass&&(i.className+=" "+n.sClass);n.bVisible&&!c?j.appendChild(i):!n.bVisible&&c&&i.parentNode.removeChild(i);
25
+ n.fnCreatedCell&&n.fnCreatedCell.call(a.oInstance,i,B(a,b,l),f,b,l)}r(a,"aoRowCreatedCallback",null,[j,f,b])}e.nTr.setAttribute("role","row")}function Ka(a,b){var c=b.nTr,d=b._aData;if(c){var e=a.rowIdFn(d);e&&(c.id=e);d.DT_RowClass&&(e=d.DT_RowClass.split(" "),b.__rowc=b.__rowc?qa(b.__rowc.concat(e)):e,h(c).removeClass(b.__rowc.join(" ")).addClass(d.DT_RowClass));d.DT_RowAttr&&h(c).attr(d.DT_RowAttr);d.DT_RowData&&h(c).data(d.DT_RowData)}}function jb(a){var b,c,d,e,f,g=a.nTHead,j=a.nTFoot,i=0===
26
+ h("th, td",g).length,n=a.oClasses,l=a.aoColumns;i&&(e=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],d=h(f.nTh).addClass(f.sClass),i&&d.appendTo(e),a.oFeatures.bSort&&(d.addClass(f.sSortingClass),!1!==f.bSortable&&(d.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),La(a,f.nTh,b))),f.sTitle!=d[0].innerHTML&&d.html(f.sTitle),Ma(a,"header")(a,d,f,n);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(n.sHeaderTH);h(j).find(">tr>th, >tr>td").addClass(n.sFooterTH);
27
+ if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var d,e,f,g=[],j=[],i=a.aoColumns.length,n;if(b){c===k&&(c=!1);d=0;for(e=b.length;d<e;d++){g[d]=b[d].slice();g[d].nTr=b[d].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[d].splice(f,1);j.push([])}d=0;for(e=g.length;d<e;d++){if(a=g[d].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[d].length;f<b;f++)if(n=i=1,j[d][f]===k){a.appendChild(g[d][f].cell);
28
+ for(j[d][f]=1;g[d+i]!==k&&g[d][f].cell==g[d+i][f].cell;)j[d+i][f]=1,i++;for(;g[d][f+n]!==k&&g[d][f].cell==g[d][f+n].cell;){for(c=0;c<i;c++)j[d+c][f+n]=1;n++}h(g[d][f].cell).attr("rowspan",i).attr("colspan",n)}}}}function N(a){var b=r(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,d=a.asStripeClasses,e=d.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==y(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=
29
+ -1);var g=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:n;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ga(a,l);l=q.nTr;if(0!==e){var t=d[c%e];q._sRowStripe!=t&&(h(l).removeClass(q._sRowStripe).addClass(t),q._sRowStripe=t)}r(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==y(a)?c=f.sLoadingRecords:
30
+ f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":e?d[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];r(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],Ja(a),g,n,i]);r(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],Ja(a),g,n,i]);d=h(a.nTBody);d.children().detach();d.append(h(b));r(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function S(a,b){var c=a.oFeatures,d=c.bFilter;
31
+ c.bSort&&lb(a);d?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;N(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),d=a.oFeatures,e=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=e[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,n,l,q,k=0;k<f.length;k++){g=null;j=f[k];if("<"==j){i=h("<div/>")[0];
32
+ n=f[k+1];if("'"==n||'"'==n){l="";for(q=2;f[k+q]!=n;)l+=f[k+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(n=l.split("."),i.id=n[0].substr(1,n[0].length-1),i.className=n[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;k+=q}e.append(i);e=h(i)}else if(">"==j)e=e.parent();else if("l"==j&&d.bPaginate&&d.bLengthChange)g=nb(a);else if("f"==j&&d.bFilter)g=ob(a);else if("r"==j&&d.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==j&&d.bInfo)g=rb(a);else if("p"==
33
+ j&&d.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(n=i.length;q<n;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),e.append(g))}c.replaceWith(e);a.nHolding=null}function da(a,b){var c=h(b).children("tr"),d,e,f,g,j,i,n,l,q,k;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){d=c[f];for(e=d.firstChild;e;){if("TD"==e.nodeName.toUpperCase()||"TH"==e.nodeName.toUpperCase()){l=1*e.getAttribute("colspan");
34
+ q=1*e.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;n=g;k=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][n+j]={cell:e,unique:k},a[f+g].nTr=d}e=e.nextSibling}}}function ra(a,b,c){var d=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,e=c.length;b<e;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!d[f]||!a.bSortCellsTop))d[f]=c[b][f].cell;return d}function sa(a,b,c){r(a,"aoServerParams","serverParams",[b]);if(b&&h.isArray(b)){var d={},
35
+ e=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(e);c?(c=c[0],d[c]||(d[c]=[]),d[c].push(b.value)):d[b.name]=b.value});b=d}var f,g=a.ajax,j=a.oInstance,i=function(b){r(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var n=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&n?n:h.extend(!0,b,n);delete g.data}n={data:b,success:function(b){var c=b.error||b.sError;c&&J(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var d=r(a,null,"xhr",
36
+ [a,null,a.jqXHR]);-1===h.inArray(!0,d)&&("parsererror"==c?J(a,0,"Invalid JSON response",1):4===b.readyState&&J(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;r(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(n,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(n,g)),g.data=f)}function kb(a){return a.bAjaxDataGet?(a.iDraw++,C(a,
37
+ !0),sa(a,tb(a),function(b){ub(a,b)}),!1):!0}function tb(a){var b=a.aoColumns,c=b.length,d=a.oFeatures,e=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,n,l,k=V(a);g=a._iDisplayStart;i=!1!==d.bPaginate?a._iDisplayLength:-1;var t=function(a,b){j.push({name:a,value:b})};t("sEcho",a.iDraw);t("iColumns",c);t("sColumns",D(b,"sName").join(","));t("iDisplayStart",g);t("iDisplayLength",i);var pa={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:e.sSearch,regex:e.bRegex}};for(g=0;g<c;g++)n=b[g],
38
+ l=f[g],i="function"==typeof n.mData?"function":n.mData,pa.columns.push({data:i,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),t("mDataProp_"+g,i),d.bFilter&&(t("sSearch_"+g,l.sSearch),t("bRegex_"+g,l.bRegex),t("bSearchable_"+g,n.bSearchable)),d.bSort&&t("bSortable_"+g,n.bSortable);d.bFilter&&(t("sSearch",e.sSearch),t("bRegex",e.bRegex));d.bSort&&(h.each(k,function(a,b){pa.order.push({column:b.col,dir:b.dir});t("iSortCol_"+a,b.col);t("sSortDir_"+
39
+ a,b.dir)}),t("iSortingCols",k.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:pa:b?j:pa}function ub(a,b){var c=ta(a,b),d=b.sEcho!==k?b.sEcho:b.draw,e=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(d){if(1*d<a.iDraw)return;a.iDraw=1*d}na(a);a._iRecordsTotal=parseInt(e,10);a._iRecordsDisplay=parseInt(f,10);d=0;for(e=c.length;d<e;d++)M(a,c[d]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;N(a);a._bInitComplete||
40
+ ua(a,b);a.bAjaxDataGet=!0;C(a,!1)}function ta(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?Q(c)(b):b}function ob(a){var b=a.oClasses,c=a.sTableId,d=a.oLanguage,e=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=d.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),f=function(){var b=!this.value?
41
+ "":this.value;b!=e.sSearch&&(fa(a,{sSearch:b,bRegex:e.bRegex,bSmart:e.bSmart,bCaseInsensitive:e.bCaseInsensitive}),a._iDisplayStart=0,N(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===y(a)?400:0,i=h("input",b).val(e.sSearch).attr("placeholder",d.sSearchPlaceholder).on("keyup.DT search.DT input.DT paste.DT cut.DT",g?Na(f,g):f).on("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==G.activeElement&&i.val(e.sSearch)}catch(d){}});
42
+ return b[0]}function fa(a,b,c){var d=a.oPreviousSearch,e=a.aoPreSearchCols,f=function(a){d.sSearch=a.sSearch;d.bRegex=a.bRegex;d.bSmart=a.bSmart;d.bCaseInsensitive=a.bCaseInsensitive};Fa(a);if("ssp"!=y(a)){vb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<e.length;b++)wb(a,e[b].sSearch,b,e[b].bEscapeRegex!==k?!e[b].bEscapeRegex:e[b].bRegex,e[b].bSmart,e[b].bCaseInsensitive);xb(a)}else f(b);a.bFiltered=!0;r(a,null,"search",[a])}function xb(a){for(var b=
43
+ m.ext.search,c=a.aiDisplay,d,e,f=0,g=b.length;f<g;f++){for(var j=[],i=0,n=c.length;i<n;i++)e=c[i],d=a.aoData[e],b[f](a,d._aFilterData,e,d._aData,i)&&j.push(e);c.length=0;h.merge(c,j)}}function wb(a,b,c,d,e,f){if(""!==b){for(var g=[],j=a.aiDisplay,d=Oa(b,d,e,f),e=0;e<j.length;e++)b=a.aoData[j[e]]._aFilterData[c],d.test(b)&&g.push(j[e]);a.aiDisplay=g}}function vb(a,b,c,d,e,f){var d=Oa(b,d,e,f),f=a.oPreviousSearch.sSearch,g=a.aiDisplayMaster,j,e=[];0!==m.ext.search.length&&(c=!0);j=yb(a);if(0>=b.length)a.aiDisplay=
44
+ g.slice();else{if(j||c||f.length>b.length||0!==b.indexOf(f)||a.bSorted)a.aiDisplay=g.slice();b=a.aiDisplay;for(c=0;c<b.length;c++)d.test(a.aoData[b[c]]._sFilterRow)&&e.push(b[c]);a.aiDisplay=e}}function Oa(a,b,c,d){a=b?a:Pa(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,d?"i":"")}function yb(a){var b=a.aoColumns,c,d,e,f,g,j,i,h,l=m.ext.type.search;c=!1;
45
+ d=0;for(f=a.aoData.length;d<f;d++)if(h=a.aoData[d],!h._aFilterData){j=[];e=0;for(g=b.length;e<g;e++)c=b[e],c.bSearchable?(i=B(a,d,e,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(va.innerHTML=i,i=Wb?va.textContent:va.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}function zb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,
46
+ caseInsensitive:a.bCaseInsensitive}}function Ab(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function rb(a){var b=a.sTableId,c=a.aanFeatures.i,d=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Bb,sName:"information"}),d.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return d[0]}function Bb(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,d=a._iDisplayStart+
47
+ 1,e=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Cb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,d,e,f,g,j));h(b).html(j)}}function Cb(a,b){var c=a.fnFormatNumber,d=a._iDisplayStart+1,e=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===e;return b.replace(/_START_/g,c.call(a,d)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,
48
+ f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(d/e))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/e)))}function ga(a){var b,c,d=a.iInitDisplayStart,e=a.aoColumns,f;c=a.oFeatures;var g=a.bDeferLoading;if(a.bInitialised){mb(a);jb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ea(a);b=0;for(c=e.length;b<c;b++)f=e[b],f.sWidth&&(f.nTh.style.width=v(f.sWidth));r(a,null,"preInit",[a]);S(a);e=y(a);if("ssp"!=e||g)"ajax"==e?sa(a,[],function(c){var f=ta(a,c);for(b=0;b<f.length;b++)M(a,f[b]);a.iInitDisplayStart=
49
+ d;S(a);C(a,!1);ua(a,c)},a):(C(a,!1),ua(a))}else setTimeout(function(){ga(a)},200)}function ua(a,b){a._bInitComplete=!0;(b||a.oInit.aaData)&&Y(a);r(a,null,"plugin-init",[a,b]);r(a,"aoInitComplete","init",[a,b])}function Qa(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Ra(a);r(a,null,"length",[a,c])}function nb(a){for(var b=a.oClasses,c=a.sTableId,d=a.aLengthMenu,e=h.isArray(d[0]),f=e?d[0]:d,d=e?d[1]:d,e=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)e[0][g]=
50
+ new Option("number"===typeof d[g]?a.fnFormatNumber(d[g]):d[g],f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",e[0].outerHTML));h("select",i).val(a._iDisplayLength).on("change.DT",function(){Qa(a,h(this).val());N(a)});h(a.nTable).on("length.dt.DT",function(b,c,d){a===c&&h("select",i).val(d)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],d="function"===typeof c,e=function(a){N(a)},
51
+ b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;d||c.fnInit(a,b,e);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(d){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),k,l=0;for(k=f.p.length;l<k;l++)Ma(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,e)},sName:"pagination"}));return b}function Sa(a,b,c){var d=a._iDisplayStart,e=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===
52
+ e?d=0:"number"===typeof b?(d=b*e,d>f&&(d=0)):"first"==b?d=0:"previous"==b?(d=0<=e?d-e:0,0>d&&(d=0)):"next"==b?d+e<f&&(d+=e):"last"==b?d=Math.floor((f-1)/e)*e:J(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==d;a._iDisplayStart=d;b&&(r(a,null,"page",[a]),c&&N(a));return b}function pb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",
53
+ b?"block":"none");r(a,null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var d=c.sX,e=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),n=h(b[0].cloneNode(!1)),l=b.children("tfoot");l.length||(l=null);i=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",
54
+ {"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({position:"relative",overflow:"auto",width:!d?null:v(d)}).append(b));l&&i.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:d?!d?null:v(d):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left",
55
+ 0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=i.children(),k=b[0],f=b[1],t=l?b[2]:null;if(d)h(f).on("scroll.DT",function(){var a=this.scrollLeft;k.scrollLeft=a;l&&(t.scrollLeft=a)});h(f).css(e&&c.bCollapse?"max-height":"height",e);a.nScrollHead=k;a.nScrollBody=f;a.nScrollFoot=t;a.aoDrawCallback.push({fn:ka,sName:"scrolling"});return i[0]}function ka(a){var b=a.oScroll,c=b.sX,d=b.sXInner,e=b.sY,b=b.iBarWidth,f=h(a.nScrollHead),g=f[0].style,j=f.children("div"),i=j[0].style,n=j.children("table"),
56
+ j=a.nScrollBody,l=h(j),q=j.style,t=h(a.nScrollFoot).children("div"),m=t.children("table"),o=h(a.nTHead),p=h(a.nTable),s=p[0],r=s.style,u=a.nTFoot?h(a.nTFoot):null,x=a.oBrowser,T=x.bScrollOversize,Xb=D(a.aoColumns,"nTh"),O,K,P,w,Ta=[],y=[],z=[],A=[],B,C=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};K=j.scrollHeight>j.clientHeight;if(a.scrollBarVis!==K&&a.scrollBarVis!==k)a.scrollBarVis=K,Y(a);else{a.scrollBarVis=K;p.children("thead, tfoot").remove();
57
+ u&&(P=u.clone().prependTo(p),O=u.find("tr"),P=P.find("tr"));w=o.clone().prependTo(p);o=o.find("tr");K=w.find("tr");w.find("th, td").removeAttr("tabindex");c||(q.width="100%",f[0].style.width="100%");h.each(ra(a,w),function(b,c){B=Z(a,b);c.style.width=a.aoColumns[B].sWidth});u&&H(function(a){a.style.width=""},P);f=p.outerWidth();if(""===c){r.width="100%";if(T&&(p.find("tbody").height()>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(p.outerWidth()-b);f=p.outerWidth()}else""!==d&&(r.width=
58
+ v(d),f=p.outerWidth());H(C,K);H(function(a){z.push(a.innerHTML);Ta.push(v(h(a).css("width")))},K);H(function(a,b){if(h.inArray(a,Xb)!==-1)a.style.width=Ta[b]},o);h(K).height(0);u&&(H(C,P),H(function(a){A.push(a.innerHTML);y.push(v(h(a).css("width")))},P),H(function(a,b){a.style.width=y[b]},O),h(P).height(0));H(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+z[b]+"</div>";a.style.width=Ta[b]},K);u&&H(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+
59
+ A[b]+"</div>";a.style.width=y[b]},P);if(p.outerWidth()<f){O=j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")?f+b:f;if(T&&(j.scrollHeight>j.offsetHeight||"scroll"==l.css("overflow-y")))r.width=v(O-b);(""===c||""!==d)&&J(a,1,"Possible column misalignment",6)}else O="100%";q.width=v(O);g.width=v(O);u&&(a.nScrollFoot.style.width=v(O));!e&&T&&(q.height=v(s.offsetHeight+b));c=p.outerWidth();n[0].style.width=v(c);i.width=v(c);d=p.height()>j.clientHeight||"scroll"==l.css("overflow-y");e="padding"+
60
+ (x.bScrollbarLeft?"Left":"Right");i[e]=d?b+"px":"0px";u&&(m[0].style.width=v(c),t[0].style.width=v(c),t[0].style[e]=d?b+"px":"0px");p.children("colgroup").insertBefore(p.children("thead"));l.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}}function H(a,b,c){for(var d=0,e=0,f=b.length,g,j;e<f;){g=b[e].firstChild;for(j=c?c[e].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,d):a(g,d),d++),g=g.nextSibling,j=c?j.nextSibling:null;e++}}function Ea(a){var b=a.nTable,c=a.aoColumns,d=a.oScroll,
61
+ e=d.sY,f=d.sX,g=d.sXInner,j=c.length,i=la(a,"bVisible"),n=h("th",a.nTHead),l=b.getAttribute("width"),k=b.parentNode,t=!1,m,o,p=a.oBrowser,d=p.bScrollOversize;(m=b.style.width)&&-1!==m.indexOf("%")&&(l=m);for(m=0;m<i.length;m++)o=c[i[m]],null!==o.sWidth&&(o.sWidth=Db(o.sWidthOrig,k),t=!0);if(d||!t&&!f&&!e&&j==aa(a)&&j==n.length)for(m=0;m<j;m++)i=Z(a,m),null!==i&&(c[i].sWidth=v(n.eq(m).width()));else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var s=h("<tr/>").appendTo(j.find("tbody"));
62
+ j.find("thead, tfoot").remove();j.append(h(a.nTHead).clone()).append(h(a.nTFoot).clone());j.find("tfoot th, tfoot td").css("width","");n=ra(a,j.find("thead")[0]);for(m=0;m<i.length;m++)o=c[i[m]],n[m].style.width=null!==o.sWidthOrig&&""!==o.sWidthOrig?v(o.sWidthOrig):"",o.sWidthOrig&&f&&h(n[m]).append(h("<div/>").css({width:o.sWidthOrig,margin:0,padding:0,border:0,height:1}));if(a.aoData.length)for(m=0;m<i.length;m++)t=i[m],o=c[t],h(Eb(a,t)).clone(!1).append(o.sContentPadding).appendTo(s);h("[name]",
63
+ j).removeAttr("name");o=h("<div/>").css(f||e?{position:"absolute",top:0,left:0,height:1,right:0,overflow:"hidden"}:{}).append(j).appendTo(k);f&&g?j.width(g):f?(j.css("width","auto"),j.removeAttr("width"),j.width()<k.clientWidth&&l&&j.width(k.clientWidth)):e?j.width(k.clientWidth):l&&j.width(l);for(m=e=0;m<i.length;m++)k=h(n[m]),g=k.outerWidth()-k.width(),k=p.bBounding?Math.ceil(n[m].getBoundingClientRect().width):k.outerWidth(),e+=k,c[i[m]].sWidth=v(k-g);b.style.width=v(e);o.remove()}l&&(b.style.width=
64
+ v(l));if((l||f)&&!a._reszEvt)b=function(){h(E).on("resize.DT-"+a.sInstance,Na(function(){Y(a)}))},d?setTimeout(b,1E3):b(),a._reszEvt=!0}function Db(a,b){if(!a)return 0;var c=h("<div/>").css("width",v(a)).appendTo(b||G.body),d=c[0].offsetWidth;c.remove();return d}function Eb(a,b){var c=Fb(a,b);if(0>c)return null;var d=a.aoData[c];return!d.nTr?h("<td/>").html(B(a,c,b,"display"))[0]:d.anCells[b]}function Fb(a,b){for(var c,d=-1,e=-1,f=0,g=a.aoData.length;f<g;f++)c=B(a,f,b,"display")+"",c=c.replace(Yb,
65
+ ""),c=c.replace(/&nbsp;/g," "),c.length>d&&(d=c.length,e=f);return e}function v(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function V(a){var b,c,d=[],e=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var n=[];f=function(a){a.length&&!h.isArray(a[0])?n.push(a):h.merge(n,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<n.length;a++){i=n[a][0];f=e[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=e[g].sType||
66
+ "string",n[a]._idx===k&&(n[a]._idx=h.inArray(n[a][1],e[g].asSorting)),d.push({src:i,col:g,dir:n[a][1],index:n[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return d}function lb(a){var b,c,d=[],e=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;Fa(a);h=V(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Gb(a,j.col);if("ssp"!=y(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)d[i[b]]=b;g===h.length?i.sort(function(a,b){var c,e,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=
67
+ 0;g<i;g++)if(j=h[g],c=k[j.col],e=m[j.col],c=c<e?-1:c>e?1:0,0!==c)return"asc"===j.dir?c:-c;c=d[a];e=d[b];return c<e?-1:c>e?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,o=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=o[i.col],i=e[i.type+"-"+i.dir]||e["string-"+i.dir],c=i(c,g),0!==c)return c;c=d[a];g=d[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Hb(a){for(var b,c,d=a.aoColumns,e=V(a),a=a.oLanguage.oAria,f=0,g=d.length;f<g;f++){c=d[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,
68
+ "");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<e.length&&e[0].col==f?(i.setAttribute("aria-sort","asc"==e[0].dir?"ascending":"descending"),c=j[e[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",b)}}function Ua(a,b,c,d){var e=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof e[0]&&(e=a.aaSorting=[e]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,
69
+ D(e,"0")),-1!==c?(b=g(e[c],!0),null===b&&1===e.length&&(b=0),null===b?e.splice(c,1):(e[c][1]=f[b],e[c]._idx=b)):(e.push([b,f[0],0]),e[e.length-1]._idx=0)):e.length&&e[0][0]==b?(b=g(e[0]),e.length=1,e[0][1]=f[b],e[0]._idx=b):(e.length=0,e.push([b,f[0]]),e[0]._idx=0);S(a);"function"==typeof d&&d(a)}function La(a,b,c,d){var e=a.aoColumns[c];Va(b,{},function(b){!1!==e.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Ua(a,c,b.shiftKey,d);"ssp"!==y(a)&&C(a,!1)},0)):Ua(a,c,b.shiftKey,d))})}
70
+ function wa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,d=V(a),e=a.oFeatures,f,g;if(e.bSort&&e.bSortClasses){e=0;for(f=b.length;e<f;e++)g=b[e].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>e?e+1:3));e=0;for(f=d.length;e<f;e++)g=d[e].src,h(D(a.aoData,"anCells",g)).addClass(c+(2>e?e+1:3))}a.aLastSort=d}function Gb(a,b){var c=a.aoColumns[b],d=m.ext.order[c.sSortDataType],e;d&&(e=d.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],
71
+ c._aSortData||(c._aSortData=[]),!c._aSortData[b]||d)f=d?e[j]:B(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function xa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),search:zb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,d){return{visible:b.bVisible,search:zb(a.aoPreSearchCols[d])}})};r(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,
72
+ b)}}function Ib(a,b,c){var d,e,f=a.aoColumns,b=function(b){if(b&&b.time){var g=r(a,"aoStateLoadParams","stateLoadParams",[a,b]);if(-1===h.inArray(!1,g)&&(g=a.iStateDuration,!(0<g&&b.time<+new Date-1E3*g)&&!(b.columns&&f.length!==b.columns.length))){a.oLoadedState=h.extend(!0,{},b);b.start!==k&&(a._iDisplayStart=b.start,a.iInitDisplayStart=b.start);b.length!==k&&(a._iDisplayLength=b.length);b.order!==k&&(a.aaSorting=[],h.each(b.order,function(b,c){a.aaSorting.push(c[0]>=f.length?[0,c[1]]:c)}));b.search!==
73
+ k&&h.extend(a.oPreviousSearch,Ab(b.search));if(b.columns){d=0;for(e=b.columns.length;d<e;d++)g=b.columns[d],g.visible!==k&&(f[d].bVisible=g.visible),g.search!==k&&h.extend(a.aoPreSearchCols[d],Ab(g.search))}r(a,"aoStateLoaded","stateLoaded",[a,b])}}c()};if(a.oFeatures.bStateSave){var g=a.fnStateLoadCallback.call(a.oInstance,a,b);g!==k&&b(g)}else c()}function ya(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function J(a,b,c,d){c="DataTables warning: "+(a?"table id="+a.sTableId+
74
+ " - ":"")+c;d&&(c+=". For more information about this error, please see http://datatables.net/tn/"+d);if(b)E.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,a&&r(a,null,"error",[a,d,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,d,c)}}function F(a,b,c,d){h.isArray(c)?h.each(c,function(c,d){h.isArray(d)?F(a,b,d[0],d[1]):F(a,b,d)}):(d===k&&(d=c),b[c]!==k&&(a[d]=b[c]))}function Jb(a,b,c){var d,e;for(e in b)b.hasOwnProperty(e)&&(d=b[e],
75
+ h.isPlainObject(d)?(h.isPlainObject(a[e])||(a[e]={}),h.extend(!0,a[e],d)):a[e]=c&&"data"!==e&&"aaData"!==e&&h.isArray(d)?d.slice():d);return a}function Va(a,b,c){h(a).on("click.DT",b,function(b){a.blur();c(b)}).on("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).on("selectstart.DT",function(){return!1})}function z(a,b,c,d){c&&a[b].push({fn:c,sName:d})}function r(a,b,c,d){var e=[];b&&(e=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,d)}));null!==c&&(b=h.Event(c+
76
+ ".dt"),h(a.nTable).trigger(b,d),e.push(b.result));return e}function Ra(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),d=a._iDisplayLength;b>=c&&(b=c-d);b-=b%d;if(-1===d||0>b)b=0;a._iDisplayStart=b}function Ma(a,b){var c=a.renderer,d=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?d[c[b]]||d._:"string"===typeof c?d[c]||d._:d._}function y(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function ha(a,b){var c=[],c=Kb.numbers_length,d=Math.floor(c/2);b<=c?c=W(0,b):a<=d?(c=W(0,
77
+ c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-d?c=W(b-(c-2),b):(c=W(a-d+2,a+d-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function cb(a){h.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Wa)},"html-num":function(b){return za(b,a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Wa)}},function(b,c){x.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(x.type.search[b+a]=x.type.search.html)})}function Lb(a){return function(){var b=
78
+ [ya(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new s(ya(this[x.iApiIndex])):new s(this)};this.fnAddData=function(a,b){var c=this.api(!0),d=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===k||b)&&c.draw();return d.flatten().toArray()};this.fnAdjustColumnSizing=
79
+ function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],d=c.oScroll;a===k||a?b.draw(!1):(""!==d.sX||""!==d.sY)&&ka(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var d=this.api(!0),a=d.rows(a),e=a.settings()[0],h=e.aoData[a[0][0]];a.remove();b&&b.call(this,e,h);(c===k||c)&&d.draw();return h};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};
80
+ this.fnFilter=function(a,b,c,d,e,h){e=this.api(!0);null===b||b===k?e.search(a,c,d,h):e.column(b).search(a,c,d,h);e.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var d=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==d||"th"==d?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();
81
+ return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ya(this[x.iApiIndex])};
82
+ this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,d,e){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(e===k||e)&&h.columns.adjust();(d===k||d)&&h.draw();return 0};this.fnVersionCheck=x.fnVersionCheck;var b=this,c=a===k,d=this.length;c&&(a={});this.oApi=this.internal=x.internal;for(var e in m.ext.internal)e&&(this[e]=Lb(e));this.each(function(){var e={},g=1<d?Jb(e,a,!0):
83
+ a,j=0,i,e=this.getAttribute("id"),n=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())J(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{db(l);eb(l.column);I(l,l,!0);I(l.column,l.column,!0);I(l,h.extend(g,q.data()));var t=m.settings,j=0;for(i=t.length;j<i;j++){var o=t[j];if(o.nTable==this||o.nTHead.parentNode==this||o.nTFoot&&o.nTFoot.parentNode==this){var s=g.bRetrieve!==k?g.bRetrieve:l.bRetrieve;if(c||s)return o.oInstance;if(g.bDestroy!==k?g.bDestroy:l.bDestroy){o.oInstance.fnDestroy();
84
+ break}else{J(o,0,"Cannot reinitialise DataTable",3);return}}if(o.sTableId==this.id){t.splice(j,1);break}}if(null===e||""===e)this.id=e="DataTables_Table_"+m.ext._unique++;var p=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:e,sTableId:e});p.nTable=this;p.oApi=b.internal;p.oInit=g;t.push(p);p.oInstance=1===b.length?b:q.dataTable();db(g);g.oLanguage&&Ca(g.oLanguage);g.aLengthMenu&&!g.iDisplayLength&&(g.iDisplayLength=h.isArray(g.aLengthMenu[0])?g.aLengthMenu[0][0]:g.aLengthMenu[0]);
85
+ g=Jb(h.extend(!0,{},l),g);F(p.oFeatures,g,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));F(p,g,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback","renderer","searchDelay","rowId",["iCookieDuration","iStateDuration"],
86
+ ["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"]]);F(p.oScroll,g,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);F(p.oLanguage,g,"fnInfoCallback");z(p,"aoDrawCallback",g.fnDrawCallback,"user");z(p,"aoServerParams",g.fnServerParams,"user");z(p,"aoStateSaveParams",g.fnStateSaveParams,"user");z(p,"aoStateLoadParams",g.fnStateLoadParams,"user");z(p,"aoStateLoaded",g.fnStateLoaded,"user");z(p,"aoRowCallback",
87
+ g.fnRowCallback,"user");z(p,"aoRowCreatedCallback",g.fnCreatedRow,"user");z(p,"aoHeaderCallback",g.fnHeaderCallback,"user");z(p,"aoFooterCallback",g.fnFooterCallback,"user");z(p,"aoInitComplete",g.fnInitComplete,"user");z(p,"aoPreDrawCallback",g.fnPreDrawCallback,"user");p.rowIdFn=Q(g.rowId);fb(p);var u=p.oClasses;h.extend(u,m.ext.classes,g.oClasses);q.addClass(u.sTable);p.iInitDisplayStart===k&&(p.iInitDisplayStart=g.iDisplayStart,p._iDisplayStart=g.iDisplayStart);null!==g.iDeferLoading&&(p.bDeferLoading=
88
+ !0,e=h.isArray(g.iDeferLoading),p._iRecordsDisplay=e?g.iDeferLoading[0]:g.iDeferLoading,p._iRecordsTotal=e?g.iDeferLoading[1]:g.iDeferLoading);var v=p.oLanguage;h.extend(!0,v,g.oLanguage);v.sUrl&&(h.ajax({dataType:"json",url:v.sUrl,success:function(a){Ca(a);I(l.oLanguage,a);h.extend(true,v,a);ga(p)},error:function(){ga(p)}}),n=!0);null===g.asStripeClasses&&(p.asStripeClasses=[u.sStripeOdd,u.sStripeEven]);var e=p.asStripeClasses,x=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(e,function(a){return x.hasClass(a)}))&&
89
+ (h("tbody tr",this).removeClass(e.join(" ")),p.asDestroyStripes=e.slice());e=[];t=this.getElementsByTagName("thead");0!==t.length&&(da(p.aoHeader,t[0]),e=ra(p));if(null===g.aoColumns){t=[];j=0;for(i=e.length;j<i;j++)t.push(null)}else t=g.aoColumns;j=0;for(i=t.length;j<i;j++)Da(p,e?e[j]:null);hb(p,g.aoColumnDefs,t,function(a,b){ja(p,a,b)});if(x.length){var w=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h(x[0]).children("th, td").each(function(a,b){var c=p.aoColumns[a];if(c.mData===
90
+ a){var d=w(b,"sort")||w(b,"order"),e=w(b,"filter")||w(b,"search");if(d!==null||e!==null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ja(p,a)}}})}var T=p.oFeatures,e=function(){if(g.aaSorting===k){var a=p.aaSorting;j=0;for(i=a.length;j<i;j++)a[j][1]=p.aoColumns[j].asSorting[0]}wa(p);T.bSort&&z(p,"aoDrawCallback",function(){if(p.bSorted){var a=V(p),b={};h.each(a,function(a,c){b[c.src]=c.dir});r(p,null,"order",[p,a,b]);Hb(p)}});
91
+ z(p,"aoDrawCallback",function(){(p.bSorted||y(p)==="ssp"||T.bDeferRender)&&wa(p)},"sc");var a=q.children("caption").each(function(){this._captionSide=h(this).css("caption-side")}),b=q.children("thead");b.length===0&&(b=h("<thead/>").appendTo(q));p.nTHead=b[0];b=q.children("tbody");b.length===0&&(b=h("<tbody/>").appendTo(q));p.nTBody=b[0];b=q.children("tfoot");if(b.length===0&&a.length>0&&(p.oScroll.sX!==""||p.oScroll.sY!==""))b=h("<tfoot/>").appendTo(q);if(b.length===0||b.children().length===0)q.addClass(u.sNoFooter);
92
+ else if(b.length>0){p.nTFoot=b[0];da(p.aoFooter,p.nTFoot)}if(g.aaData)for(j=0;j<g.aaData.length;j++)M(p,g.aaData[j]);else(p.bDeferLoading||y(p)=="dom")&&ma(p,h(p.nTBody).children("tr"));p.aiDisplay=p.aiDisplayMaster.slice();p.bInitialised=true;n===false&&ga(p)};g.bStateSave?(T.bStateSave=!0,z(p,"aoDrawCallback",xa,"state_save"),Ib(p,g,e)):e()}});b=null;return this},x,s,o,u,Xa={},Mb=/[\r\n]/g,Aa=/<.*?>/g,Zb=/^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/,$b=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)",
93
+ "g"),Wa=/[',$ツ」竄ャツ・%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,L=function(a){return!a||!0===a||"-"===a?!0:!1},Nb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Ob=function(a,b){Xa[b]||(Xa[b]=RegExp(Pa(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Xa[b],"."):a},Ya=function(a,b,c){var d="string"===typeof a;if(L(a))return!0;b&&d&&(a=Ob(a,b));c&&d&&(a=a.replace(Wa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Pb=function(a,b,c){return L(a)?!0:!(L(a)||"string"===
94
+ typeof a)?null:Ya(a.replace(Aa,""),b,c)?!0:null},D=function(a,b,c){var d=[],e=0,f=a.length;if(c!==k)for(;e<f;e++)a[e]&&a[e][b]&&d.push(a[e][b][c]);else for(;e<f;e++)a[e]&&d.push(a[e][b]);return d},ia=function(a,b,c,d){var e=[],f=0,g=b.length;if(d!==k)for(;f<g;f++)a[b[f]][c]&&e.push(a[b[f]][c][d]);else for(;f<g;f++)e.push(a[b[f]][c]);return e},W=function(a,b){var c=[],d;b===k?(b=0,d=a):(d=b,b=a);for(var e=b;e<d;e++)c.push(e);return c},Qb=function(a){for(var b=[],c=0,d=a.length;c<d;c++)a[c]&&b.push(a[c]);
95
+ return b},qa=function(a){var b;a:{if(!(2>a.length)){b=a.slice().sort();for(var c=b[0],d=1,e=b.length;d<e;d++){if(b[d]===c){b=!1;break a}c=b[d]}}b=!0}if(b)return a.slice();b=[];var e=a.length,f,g=0,d=0;a:for(;d<e;d++){c=a[d];for(f=0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b};m.util={throttle:function(a,b){var c=b!==k?b:200,d,e;return function(){var b=this,g=+new Date,j=arguments;d&&g<d+c?(clearTimeout(e),e=setTimeout(function(){d=k;a.apply(b,j)},c)):(d=g,a.apply(b,j))}},escapeRegex:function(a){return a.replace($b,
96
+ "\\$1")}};var A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,U=/\(\)$/,Pa=m.util.escapeRegex,va=h("<div>")[0],Wb=va.textContent!==k,Yb=/<.*?>/g,Na=m.util.throttle,Rb=[],w=Array.prototype,ac=function(a){var b,c,d=m.settings,e=h.map(d,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,e),-1!==b?[d[b]]:null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof
97
+ h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,e);return-1!==b?d[b]:null}).toArray()};s=function(a,b){if(!(this instanceof s))return new s(a,b);var c=[],d=function(a){(a=ac(a))&&(c=c.concat(a))};if(h.isArray(a))for(var e=0,f=a.length;e<f;e++)d(a[e]);else d(a);this.context=qa(c);b&&h.merge(this,b);this.selector={rows:null,cols:null,opts:null};s.extend(this,this,Rb)};m.Api=s;h.extend(s.prototype,{any:function(){return 0!==this.count()},concat:w.concat,context:[],count:function(){return this.flatten().length},
98
+ each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new s(b[a],this[a]):null},filter:function(a){var b=[];if(w.filter)b=w.filter.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new s(this.context,b)},flatten:function(){var a=[];return new s(this.context,a.concat.apply(a,this.toArray()))},join:w.join,indexOf:w.indexOf||function(a,b){for(var c=b||0,
99
+ d=this.length;c<d;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,d){var e=[],f,g,j,h,n,l=this.context,m,o,u=this.selector;"string"===typeof a&&(d=c,c=b,b=a,a=!1);g=0;for(j=l.length;g<j;g++){var r=new s(l[g]);if("table"===b)f=c.call(r,l[g],g),f!==k&&e.push(f);else if("columns"===b||"rows"===b)f=c.call(r,l[g],this[g],g),f!==k&&e.push(f);else if("column"===b||"column-rows"===b||"row"===b||"cell"===b){o=this[g];"column-rows"===b&&(m=Ba(l[g],u.opts));h=0;for(n=o.length;h<n;h++)f=o[h],f=
100
+ "cell"===b?c.call(r,l[g],f.row,f.column,g,h):c.call(r,l[g],f,g,h,m),f!==k&&e.push(f)}}return e.length||d?(a=new s(l,a?e.concat.apply([],e):e),b=a.selector,b.rows=u.rows,b.cols=u.cols,b.opts=u.opts,a):this},lastIndexOf:w.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(w.map)b=w.map.call(this,a,this);else for(var c=0,d=this.length;c<d;c++)b.push(a.call(this,this[c],c));return new s(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},
101
+ pop:w.pop,push:w.push,reduce:w.reduce||function(a,b){return gb(this,a,b,0,this.length,1)},reduceRight:w.reduceRight||function(a,b){return gb(this,a,b,this.length-1,-1,-1)},reverse:w.reverse,selector:null,shift:w.shift,slice:function(){return new s(this.context,this)},sort:w.sort,splice:w.splice,toArray:function(){return w.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},unique:function(){return new s(this.context,qa(this))},unshift:w.unshift});s.extend=function(a,
102
+ b,c){if(c.length&&b&&(b instanceof s||b.__dt_wrapper)){var d,e,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);s.extend(d,d,c.methodExt);return d}};d=0;for(e=c.length;d<e;d++)f=c[d],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,s.extend(a,b[f.name],f.propExt)}};s.register=o=function(a,b){if(h.isArray(a))for(var c=0,d=a.length;c<d;c++)s.register(a[c],b);else for(var e=a.split("."),f=Rb,g,j,c=0,d=e.length;c<d;c++){g=(j=-1!==
103
+ e[c].indexOf("()"))?e[c].replace("()",""):e[c];var i;a:{i=0;for(var n=f.length;i<n;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===d-1?i.val=b:f=j?i.methodExt:i.propExt}};s.registerPlural=u=function(a,b,c){s.register(a,c);s.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof s?a.length?h.isArray(a[0])?new s(a.context,a[0]):a[0]:k:a})};o("tables()",function(a){var b;if(a){b=s;var c=this.context;if("number"===
104
+ typeof a)a=[c[a]];else var d=h.map(c,function(a){return a.nTable}),a=h(d).filter(a).map(function(){var a=h.inArray(this,d);return c[a]}).toArray();b=new b(a)}else b=this;return b});o("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new s(b[0]):a});u("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});u("tables().body()","table().body()",function(){return this.iterator("table",function(a){return a.nTBody},1)});u("tables().header()",
105
+ "table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});u("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});u("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});o("draw()",function(a){return this.iterator("table",function(b){"page"===a?N(b):("string"===typeof a&&(a="full-hold"===a?!1:!0),S(b,!1===a))})});o("page()",function(a){return a===
106
+ k?this.page.info().page:this.iterator("table",function(b){Sa(b,a)})});o("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a.oFeatures.bPaginate?a._iDisplayLength:-1,d=a.fnRecordsDisplay(),e=-1===c;return{page:e?0:Math.floor(b/c),pages:e?1:Math.ceil(d/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:d,serverSide:"ssp"===y(a)}});o("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:
107
+ k:this.iterator("table",function(b){Qa(b,a)})});var Sb=function(a,b,c){if(c){var d=new s(a);d.one("draw",function(){c(d.ajax.json())})}if("ssp"==y(a))S(a,b);else{C(a,!0);var e=a.jqXHR;e&&4!==e.readyState&&e.abort();sa(a,[],function(c){na(a);for(var c=ta(a,c),d=0,e=c.length;d<e;d++)M(a,c[d]);S(a,b);C(a,!1)})}};o("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});o("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});o("ajax.reload()",function(a,
108
+ b){return this.iterator("table",function(c){Sb(c,!1===b,a)})});o("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});o("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Sb(c,!1===b,a)})});var Za=function(a,b,c,d,e){var f=[],g,j,i,n,l,m;i=typeof b;if(!b||"string"===i||"function"===
109
+ i||b.length===k)b=[b];i=0;for(n=b.length;i<n;i++){j=b[i]&&b[i].split&&!b[i].match(/[\[\(:]/)?b[i].split(","):[b[i]];l=0;for(m=j.length;l<m;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&(f=f.concat(g))}a=x.selector[a];if(a.length){i=0;for(n=a.length;i<n;i++)f=a[i](d,e,f)}return qa(f)},$a=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},ab=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=
110
+ a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Ba=function(a,b){var c,d,e,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;d=b.order;e=b.page;if("ssp"==y(a))return"removed"===j?[]:W(0,c.length);if("current"==e){c=a._iDisplayStart;for(d=a.fnDisplayEnd();c<d;c++)f.push(g[c])}else if("current"==d||"applied"==d)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==d||"original"==d){c=0;for(d=a.aoData.length;c<
111
+ d;c++)"none"==j?f.push(c):(e=h.inArray(c,g),(-1===e&&"removed"==j||0<=e&&"applied"==j)&&f.push(c))}return f};o("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var e=b,f;return Za("row",a,function(a){var b=Nb(a);if(b!==null&&!e)return[b];f||(f=Ba(c,e));if(b!==null&&h.inArray(b,f)!==-1)return[b];if(a===null||a===k||a==="")return f;if(typeof a==="function")return h.map(f,function(b){var e=c.aoData[b];return a(b,e._aData,e.nTr)?b:null});
112
+ b=Qb(ia(c.aoData,f,"nTr"));if(a.nodeName){if(a._DT_RowIndex!==k)return[a._DT_RowIndex];if(a._DT_CellIndex)return[a._DT_CellIndex.row];b=h(a).closest("*[data-dt-row]");return b.length?[b.data("dt-row")]:[]}if(typeof a==="string"&&a.charAt(0)==="#"){var i=c.aIds[a.replace(/^#/,"")];if(i!==k)return[i.idx]}return h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},c,e)},1);c.selector.rows=a;c.selector.opts=b;return c});o("rows().nodes()",function(){return this.iterator("row",function(a,
113
+ b){return a.aoData[b].nTr||k},1)});o("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ia(a.aoData,b,"_aData")},1)});u("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var d=b.aoData[c];return"search"===a?d._aFilterData:d._aSortData},1)});u("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",function(b,c){ca(b,c,a)})});u("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,
114
+ b){return b},1)});u("rows().ids()","row().id()",function(a){for(var b=[],c=this.context,d=0,e=c.length;d<e;d++)for(var f=0,g=this[d].length;f<g;f++){var h=c[d].rowIdFn(c[d].aoData[this[d][f]]._aData);b.push((!0===a?"#":"")+h)}return new s(c,b)});u("rows().remove()","row().remove()",function(){var a=this;this.iterator("row",function(b,c,d){var e=b.aoData,f=e[c],g,h,i,n,l;e.splice(c,1);g=0;for(h=e.length;g<h;g++)if(i=e[g],l=i.anCells,null!==i.nTr&&(i.nTr._DT_RowIndex=g),null!==l){i=0;for(n=l.length;i<
115
+ n;i++)l[i]._DT_CellIndex.row=g}oa(b.aiDisplayMaster,c);oa(b.aiDisplay,c);oa(a[d],c,!1);0<b._iRecordsDisplay&&b._iRecordsDisplay--;Ra(b);c=b.rowIdFn(f._aData);c!==k&&delete b.aIds[c]});this.iterator("table",function(a){for(var c=0,d=a.aoData.length;c<d;c++)a.aoData[c].idx=c});return this});o("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(M(b,c));return h},1),c=this.rows(-1);
116
+ c.pop();h.merge(c,b);return c});o("row()",function(a,b){return ab(this.rows(a,b))});o("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});o("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||null:null});o("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&
117
+ "TR"===a.nodeName.toUpperCase()?ma(b,a)[0]:M(b,a)});return this.row(b[0])});var bb=function(a,b){var c=a.context;if(c.length&&(c=c[0].aoData[b!==k?b:a[0]])&&c._details)c._details.remove(),c._detailsShow=k,c._details=k},Tb=function(a,b){var c=a.context;if(c.length&&a.length){var d=c[0].aoData[a[0]];if(d._details){(d._detailsShow=b)?d._details.insertAfter(d.nTr):d._details.detach();var e=c[0],f=new s(e),g=e.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<D(g,
118
+ "_details").length&&(f.on("draw.dt.DT_details",function(a,b){e===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(e===b)for(var c,d=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",d)}),f.on("destroy.dt.DT_details",function(a,b){if(e===b)for(var c=0,d=g.length;c<d;c++)g[c]._details&&bb(f,c)}))}}};o("row().child()",function(a,b){var c=this.context;
119
+ if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)bb(this);else if(c.length&&this.length){var d=c[0],c=c[0].aoData[this[0]],e=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?e.push(a):(c=h("<tr><td/></tr>").addClass(b),h("td",c).addClass(b).html(a)[0].colSpan=aa(d),e.push(c[0]))};f(a,b);c._details&&c._details.detach();c._details=h(e);c._detailsShow&&
120
+ c._details.insertAfter(c.nTr)}return this});o(["row().child.show()","row().child().show()"],function(){Tb(this,!0);return this});o(["row().child.hide()","row().child().hide()"],function(){Tb(this,!1);return this});o(["row().child.remove()","row().child().remove()"],function(){bb(this);return this});o("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var bc=/^([^:]+):(name|visIdx|visible)$/,Ub=function(a,b,c,d,e){for(var c=
121
+ [],d=0,f=e.length;d<f;d++)c.push(B(a,e[d],b));return c};o("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var e=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return Za("column",e,function(a){var b=Nb(a);if(a==="")return W(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var e=Ba(c,f);return h.map(g,function(b,f){return a(f,Ub(c,f,0,0,e),i[f])?f:null})}var k=typeof a==="string"?a.match(bc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=
122
+ parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[Z(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null});default:return[]}if(a.nodeName&&a._DT_CellIndex)return[a._DT_CellIndex.column];b=h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray();if(b.length||!a.nodeName)return b;b=h(a).closest("*[data-dt-column]");return b.length?[b.data("dt-column")]:[]},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});u("columns().header()",
123
+ "column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});u("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});u("columns().data()","column().data()",function(){return this.iterator("column-rows",Ub,1)});u("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});u("columns().cache()","column().cache()",
124
+ function(a){return this.iterator("column-rows",function(b,c,d,e,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});u("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,d,e){return ia(a.aoData,e,"anCells",b)},1)});u("columns().visible()","column().visible()",function(a,b){var c=this.iterator("column",function(b,c){if(a===k)return b.aoColumns[c].bVisible;var f=b.aoColumns,g=f[c],j=b.aoData,i,n,l;if(a!==k&&g.bVisible!==a){if(a){var m=
125
+ h.inArray(!0,D(f,"bVisible"),c+1);i=0;for(n=j.length;i<n;i++)l=j[i].nTr,f=j[i].anCells,l&&l.insertBefore(f[c],f[m]||null)}else h(D(b.aoData,"anCells",c)).detach();g.bVisible=a;ea(b,b.aoHeader);ea(b,b.aoFooter);xa(b)}});a!==k&&(this.iterator("column",function(c,e){r(c,null,"column-visibility",[c,e,a,b])}),(b===k||b)&&this.columns.adjust());return c});u("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});o("columns.adjust()",
126
+ function(){return this.iterator("table",function(a){Y(a)},1)});o("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return Z(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});o("column()",function(a,b){return ab(this.columns(a,b))});o("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=$a(c),f=
127
+ b.aoData,g=Ba(b,e),j=Qb(ia(f,g,"anCells")),i=h([].concat.apply([],j)),l,n=b.aoColumns.length,m,o,u,s,r,v;return Za("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){m=[];o=0;for(u=g.length;o<u;o++){l=g[o];for(s=0;s<n;s++){r={row:l,column:s};if(c){v=f[l];a(r,B(b,l,s),v.anCells?v.anCells[s]:null)&&m.push(r)}else m.push(r)}}return m}if(h.isPlainObject(a))return[a];c=i.filter(a).map(function(a,b){return{row:b._DT_CellIndex.row,column:b._DT_CellIndex.column}}).toArray();if(c.length||
128
+ !a.nodeName)return c;v=h(a).closest("*[data-dt-row]");return v.length?[{row:v.data("dt-row"),column:v.data("dt-column")}]:[]},b,e)});var d=this.columns(b,c),e=this.rows(a,c),f,g,j,i,n,l=this.iterator("table",function(a,b){f=[];g=0;for(j=e[b].length;g<j;g++){i=0;for(n=d[b].length;i<n;i++)f.push({row:e[b][g],column:d[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});u("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b])&&
129
+ a.anCells?a.anCells[c]:k},1)});o("cells().data()",function(){return this.iterator("cell",function(a,b,c){return B(a,b,c)},1)});u("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,d){return b.aoData[c][a][d]},1)});u("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,d){return B(b,c,d,a)},1)});u("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,
130
+ b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});u("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,d){ca(b,c,a,d)})});o("cell()",function(a,b,c){return ab(this.cells(a,b,c))});o("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?B(b[0],c[0].row,c[0].column):k;ib(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});o("order()",function(a,b){var c=this.context;if(a===k)return 0!==
131
+ c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:a.length&&!h.isArray(a[0])&&(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});o("order.listener()",function(a,b,c){return this.iterator("table",function(d){La(d,a,b,c)})});o("order.fixed()",function(a){if(!a){var b=this.context,b=b.length?b[0].aaSortingFixed:k;return h.isArray(b)?{pre:b}:b}return this.iterator("table",function(b){b.aaSortingFixed=h.extend(!0,{},a)})});o(["columns().order()",
132
+ "column().order()"],function(a){var b=this;return this.iterator("table",function(c,d){var e=[];h.each(b[d],function(b,c){e.push([c,a])});c.aaSorting=e})});o("search()",function(a,b,c,d){var e=this.context;return a===k?0!==e.length?e[0].oPreviousSearch.sSearch:k:this.iterator("table",function(e){e.oFeatures.bFilter&&fa(e,h.extend({},e.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),1)})});u("columns().search()","column().search()",function(a,
133
+ b,c,d){return this.iterator("column",function(e,f){var g=e.aoPreSearchCols;if(a===k)return g[f].sSearch;e.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===d?!0:d}),fa(e,e.oPreviousSearch,1))})});o("state()",function(){return this.context.length?this.context[0].oSavedState:null});o("state.clear()",function(){return this.iterator("table",function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});o("state.loaded()",function(){return this.context.length?
134
+ this.context[0].oLoadedState:null});o("state.save()",function(){return this.iterator("table",function(a){xa(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,d,e=0,f=a.length;e<f;e++)if(c=parseInt(b[e],10)||0,d=parseInt(a[e],10)||0,c!==d)return c>d;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;if(a instanceof m.Api)return!0;h.each(m.settings,function(a,e){var f=e.nScrollHead?h("table",e.nScrollHead)[0]:null,g=e.nScrollFoot?
135
+ h("table",e.nScrollFoot)[0]:null;if(e.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){var b=!1;h.isPlainObject(a)&&(b=a.api,a=a.visible);var c=h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable});return b?new s(c):c};m.camelToHungarian=I;o("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,b){o(b+"()",function(){var a=Array.prototype.slice.call(arguments);
136
+ a[0]=h.map(a[0].split(/\s/),function(a){return!a.match(/\.dt\b/)?a+".dt":a}).join(" ");var d=h(this.tables().nodes());d[b].apply(d,a);return this})});o("clear()",function(){return this.iterator("table",function(a){na(a)})});o("settings()",function(){return new s(this.context,this.context)});o("init()",function(){var a=this.context;return a.length?a[0].oInit:null});o("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});o("destroy()",function(a){a=a||
137
+ !1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,d=b.oClasses,e=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(e),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),o;b.bDestroying=!0;r(b,"aoDestroyCallback","destroy",[b]);a||(new s(b)).columns().visible(!0);k.off(".DT").find(":not(tbody *)").off(".DT");h(E).off(".DT-"+b.sInstance);e!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&e!=j.parentNode&&(i.children("tfoot").detach(),i.append(j));
138
+ b.aaSorting=[];b.aaSortingFixed=[];wa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(d.sSortable+" "+d.sSortableAsc+" "+d.sSortableDesc+" "+d.sSortableNone);f.children().detach();f.append(l);g=a?"remove":"detach";i[g]();k[g]();!a&&c&&(c.insertBefore(e,b.nTableReinsertBefore),i.css("width",b.sDestroyWidth).removeClass(d.sTable),(o=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%o])}));c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,
139
+ 1)})});h.each(["column","row","cell"],function(a,b){o(b+"s().every()",function(a){var d=this.selector.opts,e=this;return this.iterator(b,function(f,g,h,i,n){a.call(e[b](g,"cell"===b?h:d,"cell"===b?d:k),g,h,i,n)})})});o("i18n()",function(a,b,c){var d=this.context[0],a=Q(a)(d.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.16";m.settings=[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow=
140
+ {nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null,idx:-1};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,
141
+ sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
142
+ this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+
143
+ "_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",
144
+ sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null,rowId:"DT_RowId"};
145
+ X(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};X(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,
146
+ bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1,bBounding:!1,barWidth:0},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aIds:{},aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],
147
+ aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,
148
+ aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==y(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==y(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,
149
+ b=this._iDisplayStart,c=b+a,d=this.aiDisplay.length,e=this.oFeatures,f=e.bPaginate;return e.bServerSide?!1===f||-1===a?b+d:Math.min(b+a,this._iRecordsDisplay):!f||c>d||-1===a?d:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{},rowIdFn:null,rowId:null};m.ext=x={buttons:{},classes:{},builder:"-source-",errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},
150
+ order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(x,{afnFiltering:x.search,aTypes:x.type.detect,ofnSearch:x.type.search,oSort:x.type.order,afnSortData:x.order,aoFeatures:x.feature,oApi:x.internal,oStdClasses:x.classes,oPagination:x.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
151
+ sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
152
+ sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Kb=m.ext.pager;h.extend(Kb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},numbers:function(a,b){return[ha(a,
153
+ b)]},simple_numbers:function(a,b){return["previous",ha(a,b),"next"]},full_numbers:function(a,b){return["first","previous",ha(a,b),"next","last"]},first_last_numbers:function(a,b){return["first",ha(a,b),"last"]},_numbers:ha,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,d,e,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i=a.oLanguage.oAria.paginate||{},n,l,m=0,o=function(b,d){var k,s,u,r,v=function(b){Sa(a,b.data.action,true)};k=0;for(s=d.length;k<s;k++){r=d[k];if(h.isArray(r)){u=
154
+ h("<"+(r.DT_el||"div")+"/>").appendTo(b);o(u,r)}else{n=null;l="";switch(r){case "ellipsis":b.append('<span class="ellipsis">&#x2026;</span>');break;case "first":n=j.sFirst;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "previous":n=j.sPrevious;l=r+(e>0?"":" "+g.sPageButtonDisabled);break;case "next":n=j.sNext;l=r+(e<f-1?"":" "+g.sPageButtonDisabled);break;case "last":n=j.sLast;l=r+(e<f-1?"":" "+g.sPageButtonDisabled);break;default:n=r+1;l=e===r?g.sPageButtonActive:""}if(n!==null){u=h("<a>",{"class":g.sPageButton+
155
+ " "+l,"aria-controls":a.sTableId,"aria-label":i[r],"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof r==="string"?a.sTableId+"_"+r:null}).html(n).appendTo(b);Va(u,{action:r},v);m++}}}},s;try{s=h(b).find(G.activeElement).data("dt-idx")}catch(u){}o(h(b).empty(),d);s!==k&&h(b).find("[data-dt-idx="+s+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&!Zb.test(a))return null;var b=Date.parse(a);
156
+ return null!==b&&!isNaN(b)||L(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Pb(a,c,!0)?"html-num-fmt"+c:null},function(a){return L(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return L(a)?a:"string"===typeof a?a.replace(Mb," ").replace(Aa,""):""},string:function(a){return L(a)?
157
+ a:"string"===typeof a?a.replace(Mb," "):a}});var za=function(a,b,c,d){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Ob(a,b));a.replace&&(c&&(a=a.replace(c,"")),d&&(a=a.replace(d,"")));return 1*a};h.extend(x.type.order,{"date-pre":function(a){return Date.parse(a)||-Infinity},"html-pre":function(a){return L(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return L(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<
158
+ b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});cb("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,d){h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(c.sSortingClass+" "+d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,d){h("<div/>").addClass(d.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(d.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);
159
+ h(a.nTable).on("order.dt.DT",function(e,f,g,h){if(a===f){e=c.idx;b.removeClass(d.sSortAsc+" "+d.sSortDesc).addClass(h[e]=="asc"?d.sSortAsc:h[e]=="desc"?d.sSortDesc:c.sSortingClass);b.find("span."+d.sSortIcon).removeClass(d.sSortJUIAsc+" "+d.sSortJUIDesc+" "+d.sSortJUI+" "+d.sSortJUIAscAllowed+" "+d.sSortJUIDescAllowed).addClass(h[e]=="asc"?d.sSortJUIAsc:h[e]=="desc"?d.sSortJUIDesc:c.sSortingClassJUI)}})}}});var Vb=function(a){return"string"===typeof a?a.replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,
160
+ "&quot;"):a};m.render={number:function(a,b,c,d,e){return{display:function(f){if("number"!==typeof f&&"string"!==typeof f)return f;var g=0>f?"-":"",h=parseFloat(f);if(isNaN(h))return Vb(f);h=h.toFixed(c);f=Math.abs(h);h=parseInt(f,10);f=c?b+(f-h).toFixed(c).substring(2):"";return g+(d||"")+h.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+f+(e||"")}}},text:function(){return{display:Vb}}};h.extend(m.ext.internal,{_fnExternApiFunc:Lb,_fnBuildAjax:sa,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub,
161
+ _fnAjaxDataSrc:ta,_fnAddColumn:Da,_fnColumnOptions:ja,_fnAdjustColumnSizing:Y,_fnVisibleToColumnIndex:Z,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:la,_fnColumnTypes:Fa,_fnApplyColumnDefs:hb,_fnHungarianMap:X,_fnCamelToHungarian:I,_fnLanguageCompat:Ca,_fnBrowserDetect:fb,_fnAddData:M,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:B,_fnSetCellData:ib,
162
+ _fnSplitObjNotation:Ia,_fnGetObjectDataFn:Q,_fnSetObjectDataFn:R,_fnGetDataMaster:Ja,_fnClearTable:na,_fnDeleteIndex:oa,_fnInvalidate:ca,_fnGetRowElements:Ha,_fnCreateTr:Ga,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:N,_fnReDraw:S,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:ra,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Oa,_fnEscapeRegex:Pa,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga,
163
+ _fnInitComplete:ua,_fnLengthChange:Qa,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Sa,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:ka,_fnApplyToChildren:H,_fnCalculateColumnWidths:Ea,_fnThrottle:Na,_fnConvertToWidth:Db,_fnGetWidestNode:Eb,_fnGetMaxLenString:Fb,_fnStringToCss:v,_fnSortFlatten:V,_fnSort:lb,_fnSortAria:Hb,_fnSortListener:Ua,_fnSortAttachListener:La,_fnSortingClasses:wa,_fnSortData:Gb,_fnSaveState:xa,_fnLoadState:Ib,_fnSettingsFromNode:ya,
164
+ _fnLog:J,_fnMap:F,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:r,_fnLengthOverflow:Ra,_fnRenderer:Ma,_fnDataSource:y,_fnRowAttributes:Ka,_fnCalculateEnd:function(){}});h.fn.dataTable=m;m.$=h;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=b});return h.fn.dataTable});
165
+ /*!
166
+ Responsive 2.1.1
167
+ 2014-2016 SpryMedia Ltd - datatables.net/license
168
+ */
169
+ (function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(l){return c(l,window,document)}):"object"===typeof exports?module.exports=function(l,k){l||(l=window);if(!k||!k.fn.dataTable)k=require("datatables.net")(l,k).$;return c(k,l,l.document)}:c(jQuery,window,document)})(function(c,l,k,p){var m=c.fn.dataTable,j=function(b,a){if(!m.versionCheck||!m.versionCheck("1.10.3"))throw"DataTables Responsive requires DataTables 1.10.3 or newer";this.s={dt:new m.Api(b),columns:[],
170
+ current:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details?a.details={type:a.details}:a&&!1===a.details?a.details={type:!1}:a&&!0===a.details&&(a.details={type:"inline"}),this.c=c.extend(!0,{},j.defaults,m.defaults.responsive,a),b.responsive=this,this._constructor())};c.extend(j.prototype,{_constructor:function(){var b=this,a=this.s.dt,d=a.settings()[0],e=c(l).width();a.settings()[0]._responsive=this;c(l).on("resize.dtr orientationchange.dtr",m.util.throttle(function(){var a=
171
+ c(l).width();a!==e&&(b._resize(),e=a)}));d.oApi._fnCallbackReg(d,"aoRowCreatedCallback",function(e){-1!==c.inArray(!1,b.s.current)&&c(">td, >th",e).each(function(e){e=a.column.index("toData",e);!1===b.s.current[e]&&c(this).css("display","none")})});a.on("destroy.dtr",function(){a.off(".dtr");c(a.table().body()).off(".dtr");c(l).off("resize.dtr orientationchange.dtr");c.each(b.s.current,function(a,e){!1===e&&b._setColumnVis(a,!0)})});this.c.breakpoints.sort(function(a,b){return a.width<b.width?1:a.width>
172
+ b.width?-1:0});this._classLogic();this._resizeAuto();d=this.c.details;!1!==d.type&&(b._detailsInit(),a.on("column-visibility.dtr",function(){b._classLogic();b._resizeAuto();b._resize()}),a.on("draw.dtr",function(){b._redrawChildren()}),c(a.table().node()).addClass("dtr-"+d.type));a.on("column-reorder.dtr",function(){b._classLogic();b._resizeAuto();b._resize()});a.on("column-sizing.dtr",function(){b._resizeAuto();b._resize()});a.on("preXhr.dtr",function(){var e=[];a.rows().every(function(){this.child.isShown()&&
173
+ e.push(this.id(true))});a.one("draw.dtr",function(){a.rows(e).every(function(){b._detailsDisplay(this,false)})})});a.on("init.dtr",function(){b._resizeAuto();b._resize();c.inArray(false,b.s.current)&&a.columns.adjust()});this._resize()},_columnsVisiblity:function(b){var a=this.s.dt,d=this.s.columns,e,f,g=d.map(function(a,b){return{columnIdx:b,priority:a.priority}}).sort(function(a,b){return a.priority!==b.priority?a.priority-b.priority:a.columnIdx-b.columnIdx}),h=c.map(d,function(a){return a.auto&&
174
+ null===a.minWidth?!1:!0===a.auto?"-":-1!==c.inArray(b,a.includeIn)}),n=0;e=0;for(f=h.length;e<f;e++)!0===h[e]&&(n+=d[e].minWidth);e=a.settings()[0].oScroll;e=e.sY||e.sX?e.iBarWidth:0;a=a.table().container().offsetWidth-e-n;e=0;for(f=h.length;e<f;e++)d[e].control&&(a-=d[e].minWidth);n=!1;e=0;for(f=g.length;e<f;e++){var i=g[e].columnIdx;"-"===h[i]&&(!d[i].control&&d[i].minWidth)&&(n||0>a-d[i].minWidth?(n=!0,h[i]=!1):h[i]=!0,a-=d[i].minWidth)}g=!1;e=0;for(f=d.length;e<f;e++)if(!d[e].control&&!d[e].never&&
175
+ !h[e]){g=!0;break}e=0;for(f=d.length;e<f;e++)d[e].control&&(h[e]=g);-1===c.inArray(!0,h)&&(h[0]=!0);return h},_classLogic:function(){var b=this,a=this.c.breakpoints,d=this.s.dt,e=d.columns().eq(0).map(function(a){var b=this.column(a),e=b.header().className,a=d.settings()[0].aoColumns[a].responsivePriority;a===p&&(b=c(b.header()).data("priority"),a=b!==p?1*b:1E4);return{className:e,includeIn:[],auto:!1,control:!1,never:e.match(/\bnever\b/)?!0:!1,priority:a}}),f=function(a,b){var d=e[a].includeIn;-1===
176
+ c.inArray(b,d)&&d.push(b)},g=function(c,d,i,g){if(i)if("max-"===i){g=b._find(d).width;d=0;for(i=a.length;d<i;d++)a[d].width<=g&&f(c,a[d].name)}else if("min-"===i){g=b._find(d).width;d=0;for(i=a.length;d<i;d++)a[d].width>=g&&f(c,a[d].name)}else{if("not-"===i){d=0;for(i=a.length;d<i;d++)-1===a[d].name.indexOf(g)&&f(c,a[d].name)}}else e[c].includeIn.push(d)};e.each(function(b,e){for(var d=b.className.split(" "),f=!1,j=0,l=d.length;j<l;j++){var k=c.trim(d[j]);if("all"===k){f=!0;b.includeIn=c.map(a,function(a){return a.name});
177
+ return}if("none"===k||b.never){f=!0;return}if("control"===k){f=!0;b.control=!0;return}c.each(a,function(a,b){var d=b.name.split("-"),c=k.match(RegExp("(min\\-|max\\-|not\\-)?("+d[0]+")(\\-[_a-zA-Z0-9])?"));c&&(f=!0,c[2]===d[0]&&c[3]==="-"+d[1]?g(e,b.name,c[1],c[2]+c[3]):c[2]===d[0]&&!c[3]&&g(e,b.name,c[1],c[2]))})}f||(b.auto=!0)});this.s.columns=e},_detailsDisplay:function(b,a){var d=this,e=this.s.dt,f=this.c.details;if(f&&!1!==f.type){var g=f.display(b,a,function(){return f.renderer(e,b[0],d._detailsObj(b[0]))});
178
+ (!0===g||!1===g)&&c(e.table().node()).triggerHandler("responsive-display.dt",[e,b,g,a])}},_detailsInit:function(){var b=this,a=this.s.dt,d=this.c.details;"inline"===d.type&&(d.target="td:first-child, th:first-child");a.on("draw.dtr",function(){b._tabIndexes()});b._tabIndexes();c(a.table().body()).on("keyup.dtr","td, th",function(b){b.keyCode===13&&c(this).data("dtr-keyboard")&&c(this).click()});var e=d.target;c(a.table().body()).on("click.dtr mousedown.dtr mouseup.dtr","string"===typeof e?e:"td, th",
179
+ function(d){if(c(a.table().node()).hasClass("collapsed")&&c.inArray(c(this).closest("tr").get(0),a.rows().nodes().toArray())!==-1){if(typeof e==="number"){var g=e<0?a.columns().eq(0).length+e:e;if(a.cell(this).index().column!==g)return}g=a.row(c(this).closest("tr"));d.type==="click"?b._detailsDisplay(g,false):d.type==="mousedown"?c(this).css("outline","none"):d.type==="mouseup"&&c(this).blur().css("outline","")}})},_detailsObj:function(b){var a=this,d=this.s.dt;return c.map(this.s.columns,function(e,
180
+ c){if(!e.never&&!e.control)return{title:d.settings()[0].aoColumns[c].sTitle,data:d.cell(b,c).render(a.c.orthogonal),hidden:d.column(c).visible()&&!a.s.current[c],columnIndex:c,rowIndex:b}})},_find:function(b){for(var a=this.c.breakpoints,d=0,c=a.length;d<c;d++)if(a[d].name===b)return a[d]},_redrawChildren:function(){var b=this,a=this.s.dt;a.rows({page:"current"}).iterator("row",function(c,e){a.row(e);b._detailsDisplay(a.row(e),!0)})},_resize:function(){var b=this,a=this.s.dt,d=c(l).width(),e=this.c.breakpoints,
181
+ f=e[0].name,g=this.s.columns,h,j=this.s.current.slice();for(h=e.length-1;0<=h;h--)if(d<=e[h].width){f=e[h].name;break}var i=this._columnsVisiblity(f);this.s.current=i;e=!1;h=0;for(d=g.length;h<d;h++)if(!1===i[h]&&!g[h].never&&!g[h].control){e=!0;break}c(a.table().node()).toggleClass("collapsed",e);var k=!1;a.columns().eq(0).each(function(a,c){i[c]!==j[c]&&(k=!0,b._setColumnVis(a,i[c]))});k&&(this._redrawChildren(),c(a.table().node()).trigger("responsive-resize.dt",[a,this.s.current]))},_resizeAuto:function(){var b=
182
+ this.s.dt,a=this.s.columns;if(this.c.auto&&-1!==c.inArray(!0,c.map(a,function(b){return b.auto}))){b.table().node();var d=b.table().node().cloneNode(!1),e=c(b.table().header().cloneNode(!1)).appendTo(d),f=c(b.table().body()).clone(!1,!1).empty().appendTo(d),g=b.columns().header().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell");c(f).append(c(b.rows({page:"current"}).nodes()).clone(!1)).find("th, td").css("display","");if(f=b.table().footer()){var f=c(f.cloneNode(!1)).appendTo(d),
183
+ h=b.columns().footer().filter(function(a){return b.column(a).visible()}).to$().clone(!1).css("display","table-cell");c("<tr/>").append(h).appendTo(f)}c("<tr/>").append(g).appendTo(e);"inline"===this.c.details.type&&c(d).addClass("dtr-inline collapsed");c(d).find("[name]").removeAttr("name");d=c("<div/>").css({width:1,height:1,overflow:"hidden"}).append(d);d.insertBefore(b.table().node());g.each(function(c){c=b.column.index("fromVisible",c);a[c].minWidth=this.offsetWidth||0});d.remove()}},_setColumnVis:function(b,
184
+ a){var d=this.s.dt,e=a?"":"none";c(d.column(b).header()).css("display",e);c(d.column(b).footer()).css("display",e);d.column(b).nodes().to$().css("display",e)},_tabIndexes:function(){var b=this.s.dt,a=b.cells({page:"current"}).nodes().to$(),d=b.settings()[0],e=this.c.details.target;a.filter("[data-dtr-keyboard]").removeData("[data-dtr-keyboard]");a="number"===typeof e?":eq("+e+")":e;"td:first-child, th:first-child"===a&&(a=">td:first-child, >th:first-child");c(a,b.rows({page:"current"}).nodes()).attr("tabIndex",
185
+ d.iTabIndex).data("dtr-keyboard",1)}});j.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];j.display={childRow:function(b,a,d){if(a){if(c(b.node()).hasClass("parent"))return b.child(d(),"child").show(),!0}else{if(b.child.isShown())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0}},childRowImmediate:function(b,a,d){if(!a&&
186
+ b.child.isShown()||!b.responsive.hasHidden())return b.child(!1),c(b.node()).removeClass("parent"),!1;b.child(d(),"child").show();c(b.node()).addClass("parent");return!0},modal:function(b){return function(a,d,e){if(d)c("div.dtr-modal-content").empty().append(e());else{var f=function(){g.remove();c(k).off("keypress.dtr")},g=c('<div class="dtr-modal"/>').append(c('<div class="dtr-modal-display"/>').append(c('<div class="dtr-modal-content"/>').append(e())).append(c('<div class="dtr-modal-close">&times;</div>').click(function(){f()}))).append(c('<div class="dtr-modal-background"/>').click(function(){f()})).appendTo("body");
187
+ c(k).on("keyup.dtr",function(a){27===a.keyCode&&(a.stopPropagation(),f())})}b&&b.header&&c("div.dtr-modal-content").prepend("<h2>"+b.header(a)+"</h2>")}}};j.renderer={listHidden:function(){return function(b,a,d){return(b=c.map(d,function(a){return a.hidden?'<li data-dtr-index="'+a.columnIndex+'" data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><span class="dtr-title">'+a.title+'</span> <span class="dtr-data">'+a.data+"</span></li>":""}).join(""))?c('<ul data-dtr-index="'+a+'" class="dtr-details"/>').append(b):
188
+ !1}},tableAll:function(b){b=c.extend({tableClass:""},b);return function(a,d,e){a=c.map(e,function(a){return'<tr data-dt-row="'+a.rowIndex+'" data-dt-column="'+a.columnIndex+'"><td>'+a.title+":</td> <td>"+a.data+"</td></tr>"}).join("");return c('<table class="'+b.tableClass+' dtr-details" width="100%"/>').append(a)}}};j.defaults={breakpoints:j.breakpoints,auto:!0,details:{display:j.display.childRow,renderer:j.renderer.listHidden(),target:0,type:"inline"},orthogonal:"display"};var o=c.fn.dataTable.Api;
189
+ o.register("responsive()",function(){return this});o.register("responsive.index()",function(b){b=c(b);return{column:b.data("dtr-index"),row:b.parent().data("dtr-index")}});o.register("responsive.rebuild()",function(){return this.iterator("table",function(b){b._responsive&&b._responsive._classLogic()})});o.register("responsive.recalc()",function(){return this.iterator("table",function(b){b._responsive&&(b._responsive._resizeAuto(),b._responsive._resize())})});o.register("responsive.hasHidden()",function(){var b=
190
+ this.context[0];return b._responsive?-1!==c.inArray(!1,b._responsive.s.current):!1});j.version="2.1.1";c.fn.dataTable.Responsive=j;c.fn.DataTable.Responsive=j;c(k).on("preInit.dt.dtr",function(b,a){if("dt"===b.namespace&&(c(a.nTable).hasClass("responsive")||c(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||m.defaults.responsive)){var d=a.oInit.responsive;!1!==d&&new j(a,c.isPlainObject(d)?d:{})}});return j});
191
+ /*!***************************************************
192
+ * mark.js v8.11.0
193
+ * https://github.com/julmot/mark.js
194
+ * Copyright (c) 2014–2017, Julian Motz
195
+ * Released under the MIT license https://git.io/vwTVl
196
+ *****************************************************/
197
+ "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _extends=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},_createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(e,t,n){"function"==typeof define&&define.amd?define(["jquery"],function(r){return e(t,n,r)}):"object"===("undefined"==typeof module?"undefined":_typeof(module))&&module.exports?module.exports=e(t,n,require("jquery")):e(t,n,jQuery)}(function(e,t,n){var r=function(){function n(t){_classCallCheck(this,n),this.ctx=t,this.ie=!1;var r=e.navigator.userAgent;(r.indexOf("MSIE")>-1||r.indexOf("Trident")>-1)&&(this.ie=!0)}return _createClass(n,[{key:"log",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",n=this.opt.log;this.opt.debug&&"object"===(void 0===n?"undefined":_typeof(n))&&"function"==typeof n[t]&&n[t]("mark.js: "+e)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+a+"|"+s+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return s=s>o?o:s,(r=s+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,n,r){var i=this.opt.element?this.opt.element:"mark",o=e.splitText(n),a=o.splitText(r-n),s=t.createElement(i);return s.setAttribute("data-markjs","true"),this.opt.className&&s.setAttribute("class",this.opt.className),s.textContent=o.textContent,o.parentNode.replaceChild(s,o),a}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c<a;c++)s+=i[c].length;t=o.wrapRangeInTextNode(t,s,s+i[a].length),r(t.previousSibling),e.lastIndex=0}}),i()})}},{key:"wrapMatchesAcrossElements",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){for(var s=void 0;null!==(s=e.exec(t.value))&&""!==s[a];){var c=s.index;if(0!==a)for(var u=1;u<a;u++)c+=s[u].length;var l=c+s[a].length;o.wrapRangeInMappedTextNode(t,c,l,function(e){return n(s[a],e)},function(t,n){e.lastIndex=n,r(t)})}i()})}},{key:"wrapRangeFromIndex",value:function(e,t,n,r){var i=this;this.getTextNodes(function(o){var a=o.value.length;e.forEach(function(e,r){var s=i.checkWhitespaceRanges(e,a,o.value),c=s.start,u=s.end;s.valid&&i.wrapRangeInMappedTextNode(o,c,u,function(n){return t(n,e,o.value.substring(c,u),r)},function(t){n(t,e)})}),r()})}},{key:"unwrapMatches",value:function(e){for(var n=e.parentNode,r=t.createDocumentFragment();e.firstChild;)r.appendChild(e.removeChild(e.firstChild));n.replaceChild(r,e),this.ie?this.normalizeTextNode(n):n.normalize()}},{key:"normalizeTextNode",value:function(e){if(e){if(3===e.nodeType)for(;e.nextSibling&&3===e.nextSibling.nodeType;)e.nodeValue+=e.nextSibling.nodeValue,e.parentNode.removeChild(e.nextSibling);else this.normalizeTextNode(e.firstChild);this.normalizeTextNode(e.nextSibling)}}},{key:"markRegExp",value:function(e,t){var n=this;this.opt=t,this.log('Searching with expression "'+e+'"');var r=0,i="wrapMatches";this.opt.acrossElements&&(i="wrapMatchesAcrossElements"),this[i](e,this.opt.ignoreGroups,function(e,t){return n.opt.filter(t,e,r)},function(e){r++,n.opt.each(e)},function(){0===r&&n.opt.noMatch(e),n.opt.done(r)})}},{key:"mark",value:function(e,t){var n=this;this.opt=t;var r=0,i="wrapMatches",o=this.getSeparatedKeywords("string"==typeof e?[e]:e),a=o.keywords,s=o.length,c=this.opt.caseSensitive?"":"i";this.opt.acrossElements&&(i="wrapMatchesAcrossElements"),0===s?this.opt.done(r):function e(t){var o=new RegExp(n.createRegExp(t),"gm"+c),u=0;n.log('Searching with expression "'+o+'"'),n[i](o,1,function(e,i){return n.opt.filter(i,t,r,u)},function(e){u++,r++,n.opt.each(e)},function(){0===u&&n.opt.noMatch(t),a[s-1]===t?n.opt.done(r):e(a[a.indexOf(t)+1])})}(a[0])}},{key:"markRanges",value:function(e,t){var n=this;this.opt=t;var r=0,i=this.checkRanges(e);i&&i.length?(this.log("Starting to mark with the following ranges: "+JSON.stringify(i)),this.wrapRangeFromIndex(i,function(e,t,r,i){return n.opt.filter(e,t,r,i)},function(e,t){r++,n.opt.each(e,t)},function(){n.opt.done(r)})):this.opt.done(r)}},{key:"unmark",value:function(e){var t=this;this.opt=e;var n=this.opt.element?this.opt.element:"*";n+="[data-markjs]",this.opt.className&&(n+="."+this.opt.className),this.log('Removal selector "'+n+'"'),this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT,function(e){t.unwrapMatches(e)},function(e){var r=i.matches(e,n),o=t.matchesExclude(e);return!r||o?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},this.opt.done)}},{key:"opt",set:function(t){this._opt=_extends({},{element:"",className:"",exclude:[],iframes:!1,iframesTimeout:5e3,separateWordSearch:!0,diacritics:!0,synonyms:{},accuracy:"partially",acrossElements:!1,caseSensitive:!1,ignoreJoiners:!1,ignoreGroups:0,ignorePunctuation:[],wildcards:"disabled",each:function(){},noMatch:function(){},filter:function(){return!0},done:function(){},debug:!1,log:e.console},t)},get:function(){return this._opt}},{key:"iterator",get:function(){return new i(this.ctx,this.opt.iframes,this.opt.exclude,this.opt.iframesTimeout)}}]),n}(),i=function(){function e(t){var n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;_classCallCheck(this,e),this.ctx=t,this.iframes=n,this.exclude=r,this.iframesTimeout=i}return _createClass(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(t.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t="about:blank",n=e.getAttribute("src").trim();return e.contentWindow.location.href===t&&n!==t&&n}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,n,r){return t.createNodeIterator(e,n,r,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode(),n=void 0;return n=null===t?e.nextNode():e.nextNode()&&e.nextNode(),{prevNode:t,node:n}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o=this,a=this.createIterator(t,e,r),s=[],c=[],u=void 0,l=void 0;function(){var e=o.getIteratorNode(a);return l=e.prevNode,u=e.node}();)this.iframes&&this.forEachIframe(t,function(e){return o.checkIframeFilter(u,l,e,s)},function(t){o.createInstanceOnIframe(t).forEachNode(e,function(e){return c.push(e)},r)}),c.push(u);c.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(s,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}();return n.fn.mark=function(e,t){return new r(this.get()).mark(e,t),this},n.fn.markRegExp=function(e,t){return new r(this.get()).markRegExp(e,t),this},n.fn.markRanges=function(e,t){return new r(this.get()).markRanges(e,t),this},n.fn.unmark=function(e){return new r(this.get()).unmark(e),this},n},window,document);
198
+ /*!***************************************************
199
+ * datatables.mark.js v2.0.1
200
+ * https://github.com/julmot/datatables.mark.js
201
+ * Copyright (c) 2016–2017, Julian Motz
202
+ * Released under the MIT license https://git.io/voRZ7
203
+ *****************************************************/
204
+ "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(e,t,n){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))){var r=require("jquery");require("datatables.net"),require("mark.js/dist/jquery.mark.js"),module.exports=e(t,n,r)}else"function"==typeof define&&define.amd?define(["jquery","datatables.net","markjs"],function(r){return e(t,n,r)}):e(t,n,jQuery)}(function(e,t,n){var r=function(){function e(t,r){if(_classCallCheck(this,e),!n.fn.mark||!n.fn.unmark)throw new Error("jquery.mark.js is necessary for datatables.mark.js");this.instance=t,this.options="object"===(void 0===r?"undefined":_typeof(r))?r:{},this.intervalThreshold=49,this.intervalMs=300,this.initMarkListener()}return _createClass(e,[{key:"initMarkListener",value:function(){var e=this,t="draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth",n=null;this.instance.on(t,function(){e.instance.rows({filter:"applied",page:"current"}).nodes().length>e.intervalThreshold?(clearTimeout(n),n=setTimeout(function(){e.mark()},e.intervalMs)):e.mark()}),this.instance.on("destroy",function(){e.instance.off(t)}),this.mark()}},{key:"mark",value:function(){var e=this,t=this.instance.search();n(this.instance.table().body()).unmark(this.options),this.instance.columns({search:"applied",page:"current"}).nodes().each(function(r,a){var i=e.instance.column(a).search()||t;i&&r.forEach(function(t){n(t).mark(i,e.options)})})}}]),e}();n(t).on("init.dt.dth",function(e,t){if("dt"===e.namespace){var a=n.fn.dataTable.Api(t),i=null;a.init().mark?i=a.init().mark:n.fn.dataTable.defaults.mark&&(i=n.fn.dataTable.defaults.mark),null!==i&&new r(a,i)}})},window,document);
admin/datatables/js/datatables.mark.js ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!***************************************************
2
+ * datatables.mark.js v2.0.1
3
+ * https://github.com/julmot/datatables.mark.js
4
+ * Copyright (c) 2016–2017, Julian Motz
5
+ * Released under the MIT license https://git.io/voRZ7
6
+ *****************************************************/
7
+
8
+ 'use strict';
9
+
10
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
11
+
12
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
13
+
14
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
15
+
16
+ (function (factory, window, document) {
17
+ if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') {
18
+ var jquery = require('jquery');
19
+ require('datatables.net');
20
+ require('mark.js/dist/jquery.mark.js');
21
+ module.exports = factory(window, document, jquery);
22
+ } else if (typeof define === 'function' && define.amd) {
23
+ define(['jquery', 'datatables.net', 'markjs'], function (jQuery) {
24
+ return factory(window, document, jQuery);
25
+ });
26
+ } else {
27
+ factory(window, document, jQuery);
28
+ }
29
+ })(function (window, document, $) {
30
+ var MarkDataTables = function () {
31
+ function MarkDataTables(dtInstance, options) {
32
+ _classCallCheck(this, MarkDataTables);
33
+
34
+ if (!$.fn.mark || !$.fn.unmark) {
35
+ throw new Error('jquery.mark.js is necessary for datatables.mark.js');
36
+ }
37
+ this.instance = dtInstance;
38
+ this.options = (typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' ? options : {};
39
+ this.intervalThreshold = 49;
40
+ this.intervalMs = 300;
41
+ this.initMarkListener();
42
+ }
43
+
44
+ _createClass(MarkDataTables, [{
45
+ key: 'initMarkListener',
46
+ value: function initMarkListener() {
47
+ var _this = this;
48
+
49
+ var ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth';
50
+ var intvl = null;
51
+ this.instance.on(ev, function () {
52
+ var rows = _this.instance.rows({
53
+ filter: 'applied',
54
+ page: 'current'
55
+ }).nodes().length;
56
+ if (rows > _this.intervalThreshold) {
57
+ clearTimeout(intvl);
58
+ intvl = setTimeout(function () {
59
+ _this.mark();
60
+ }, _this.intervalMs);
61
+ } else {
62
+ _this.mark();
63
+ }
64
+ });
65
+ this.instance.on('destroy', function () {
66
+ _this.instance.off(ev);
67
+ });
68
+ this.mark();
69
+ }
70
+ }, {
71
+ key: 'mark',
72
+ value: function mark() {
73
+ var _this2 = this;
74
+
75
+ var globalSearch = this.instance.search();
76
+ $(this.instance.table().body()).unmark(this.options);
77
+ this.instance.columns({
78
+ search: 'applied',
79
+ page: 'current'
80
+ }).nodes().each(function (nodes, colIndex) {
81
+ var columnSearch = _this2.instance.column(colIndex).search(),
82
+ searchVal = columnSearch || globalSearch;
83
+ if (searchVal) {
84
+ nodes.forEach(function (node) {
85
+ $(node).mark(searchVal, _this2.options);
86
+ });
87
+ }
88
+ });
89
+ }
90
+ }]);
91
+
92
+ return MarkDataTables;
93
+ }();
94
+
95
+ $(document).on('init.dt.dth', function (event, settings) {
96
+ if (event.namespace !== 'dt') {
97
+ return;
98
+ }
99
+
100
+ var dtInstance = $.fn.dataTable.Api(settings);
101
+
102
+ var options = null;
103
+ if (dtInstance.init().mark) {
104
+ options = dtInstance.init().mark;
105
+ } else if ($.fn.dataTable.defaults.mark) {
106
+ options = $.fn.dataTable.defaults.mark;
107
+ }
108
+ if (options === null) {
109
+ return;
110
+ }
111
+
112
+ new MarkDataTables(dtInstance, options);
113
+ });
114
+ }, window, document);
admin/datatables/js/datatables.mark.min.js ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ /*!***************************************************
2
+ * datatables.mark.js v2.0.1
3
+ * https://github.com/julmot/datatables.mark.js
4
+ * Copyright (c) 2016–2017, Julian Motz
5
+ * Released under the MIT license https://git.io/voRZ7
6
+ *****************************************************/
7
+ "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};!function(e,t,n){if("object"===("undefined"==typeof exports?"undefined":_typeof(exports))){var r=require("jquery");require("datatables.net"),require("mark.js/dist/jquery.mark.js"),module.exports=e(t,n,r)}else"function"==typeof define&&define.amd?define(["jquery","datatables.net","markjs"],function(r){return e(t,n,r)}):e(t,n,jQuery)}(function(e,t,n){var r=function(){function e(t,r){if(_classCallCheck(this,e),!n.fn.mark||!n.fn.unmark)throw new Error("jquery.mark.js is necessary for datatables.mark.js");this.instance=t,this.options="object"===(void 0===r?"undefined":_typeof(r))?r:{},this.intervalThreshold=49,this.intervalMs=300,this.initMarkListener()}return _createClass(e,[{key:"initMarkListener",value:function(){var e=this,t="draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth",n=null;this.instance.on(t,function(){e.instance.rows({filter:"applied",page:"current"}).nodes().length>e.intervalThreshold?(clearTimeout(n),n=setTimeout(function(){e.mark()},e.intervalMs)):e.mark()}),this.instance.on("destroy",function(){e.instance.off(t)}),this.mark()}},{key:"mark",value:function(){var e=this,t=this.instance.search();n(this.instance.table().body()).unmark(this.options),this.instance.columns({search:"applied",page:"current"}).nodes().each(function(r,a){var i=e.instance.column(a).search()||t;i&&r.forEach(function(t){n(t).mark(i,e.options)})})}}]),e}();n(t).on("init.dt.dth",function(e,t){if("dt"===e.namespace){var a=n.fn.dataTable.Api(t),i=null;a.init().mark?i=a.init().mark:n.fn.dataTable.defaults.mark&&(i=n.fn.dataTable.defaults.mark),null!==i&&new r(a,i)}})},window,document);
admin/datatables/js/jquery.dataTables.js ADDED
@@ -0,0 +1,15243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.16
2
+ * 2008-2017 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary DataTables
7
+ * @description Paginate, search and order HTML tables
8
+ * @version 1.10.16
9
+ * @file jquery.dataTables.js
10
+ * @author SpryMedia Ltd
11
+ * @contact www.datatables.net
12
+ * @copyright Copyright 2008-2017 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,_fnInvalidate,_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,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
+
27
+ (function( factory ) {
28
+ "use strict";
29
+
30
+ if ( typeof define === 'function' && define.amd ) {
31
+ // AMD
32
+ define( ['jquery'], function ( $ ) {
33
+ return factory( $, window, document );
34
+ } );
35
+ }
36
+ else if ( typeof exports === 'object' ) {
37
+ // CommonJS
38
+ module.exports = function (root, $) {
39
+ if ( ! root ) {
40
+ // CommonJS environments without a window global must pass a
41
+ // root. This will give an error otherwise
42
+ root = window;
43
+ }
44
+
45
+ if ( ! $ ) {
46
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
47
+ require('jquery') :
48
+ require('jquery')( root );
49
+ }
50
+
51
+ return factory( $, root, root.document );
52
+ };
53
+ }
54
+ else {
55
+ // Browser
56
+ factory( jQuery, window, document );
57
+ }
58
+ }
59
+ (function( $, window, document, undefined ) {
60
+ "use strict";
61
+
62
+ /**
63
+ * DataTables is a plug-in for the jQuery Javascript library. It is a highly
64
+ * flexible tool, based upon the foundations of progressive enhancement,
65
+ * which will add advanced interaction controls to any HTML table. For a
66
+ * full list of features please refer to
67
+ * [DataTables.net](href="http://datatables.net).
68
+ *
69
+ * Note that the `DataTable` object is not a global variable but is aliased
70
+ * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
71
+ * be accessed.
72
+ *
73
+ * @class
74
+ * @param {object} [init={}] Configuration object for DataTables. Options
75
+ * are defined by {@link DataTable.defaults}
76
+ * @requires jQuery 1.7+
77
+ *
78
+ * @example
79
+ * // Basic initialisation
80
+ * $(document).ready( function {
81
+ * $('#example').dataTable();
82
+ * } );
83
+ *
84
+ * @example
85
+ * // Initialisation with configuration options - in this case, disable
86
+ * // pagination and sorting.
87
+ * $(document).ready( function {
88
+ * $('#example').dataTable( {
89
+ * "paginate": false,
90
+ * "sort": false
91
+ * } );
92
+ * } );
93
+ */
94
+ var DataTable = function ( options )
95
+ {
96
+ /**
97
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
98
+ * return the resulting jQuery object.
99
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
100
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
101
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
102
+ * criterion ("applied") or all TR elements (i.e. no filter).
103
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
104
+ * Can be either 'current', whereby the current sorting of the table is used, or
105
+ * 'original' whereby the original order the data was read into the table is used.
106
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
107
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
108
+ * 'current' and filter is 'applied', regardless of what they might be given as.
109
+ * @returns {object} jQuery object, filtered by the given selector.
110
+ * @dtopt API
111
+ * @deprecated Since v1.10
112
+ *
113
+ * @example
114
+ * $(document).ready(function() {
115
+ * var oTable = $('#example').dataTable();
116
+ *
117
+ * // Highlight every second row
118
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
119
+ * } );
120
+ *
121
+ * @example
122
+ * $(document).ready(function() {
123
+ * var oTable = $('#example').dataTable();
124
+ *
125
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
126
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
127
+ * oTable.fnFilter('Webkit');
128
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
129
+ * oTable.fnFilter('');
130
+ * } );
131
+ */
132
+ this.$ = function ( sSelector, oOpts )
133
+ {
134
+ return this.api(true).$( sSelector, oOpts );
135
+ };
136
+
137
+
138
+ /**
139
+ * Almost identical to $ in operation, but in this case returns the data for the matched
140
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
141
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
142
+ * rows are found, the data returned is the original data array/object that was used to
143
+ * create the row (or a generated array if from a DOM source).
144
+ *
145
+ * This method is often useful in-combination with $ where both functions are given the
146
+ * same parameters and the array indexes will match identically.
147
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
148
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
149
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
150
+ * criterion ("applied") or all elements (i.e. no filter).
151
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
152
+ * Can be either 'current', whereby the current sorting of the table is used, or
153
+ * 'original' whereby the original order the data was read into the table is used.
154
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
155
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
156
+ * 'current' and filter is 'applied', regardless of what they might be given as.
157
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
158
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
159
+ * entry in the array.
160
+ * @dtopt API
161
+ * @deprecated Since v1.10
162
+ *
163
+ * @example
164
+ * $(document).ready(function() {
165
+ * var oTable = $('#example').dataTable();
166
+ *
167
+ * // Get the data from the first row in the table
168
+ * var data = oTable._('tr:first');
169
+ *
170
+ * // Do something useful with the data
171
+ * alert( "First cell is: "+data[0] );
172
+ * } );
173
+ *
174
+ * @example
175
+ * $(document).ready(function() {
176
+ * var oTable = $('#example').dataTable();
177
+ *
178
+ * // Filter to 'Webkit' and get all data for
179
+ * oTable.fnFilter('Webkit');
180
+ * var data = oTable._('tr', {"search": "applied"});
181
+ *
182
+ * // Do something with the data
183
+ * alert( data.length+" rows matched the search" );
184
+ * } );
185
+ */
186
+ this._ = function ( sSelector, oOpts )
187
+ {
188
+ return this.api(true).rows( sSelector, oOpts ).data();
189
+ };
190
+
191
+
192
+ /**
193
+ * Create a DataTables Api instance, with the currently selected tables for
194
+ * the Api's context.
195
+ * @param {boolean} [traditional=false] Set the API instance's context to be
196
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
197
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
198
+ * or if all tables captured in the jQuery object should be used.
199
+ * @return {DataTables.Api}
200
+ */
201
+ this.api = function ( traditional )
202
+ {
203
+ return traditional ?
204
+ new _Api(
205
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
206
+ ) :
207
+ new _Api( this );
208
+ };
209
+
210
+
211
+ /**
212
+ * Add a single new row or multiple rows of data to the table. Please note
213
+ * that this is suitable for client-side processing only - if you are using
214
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
215
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
216
+ * @param {array|object} data The data to be added to the table. This can be:
217
+ * <ul>
218
+ * <li>1D array of data - add a single row with the data provided</li>
219
+ * <li>2D array of arrays - add multiple rows in a single call</li>
220
+ * <li>object - data object when using <i>mData</i></li>
221
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
222
+ * </ul>
223
+ * @param {bool} [redraw=true] redraw the table or not
224
+ * @returns {array} An array of integers, representing the list of indexes in
225
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
226
+ * the table.
227
+ * @dtopt API
228
+ * @deprecated Since v1.10
229
+ *
230
+ * @example
231
+ * // Global var for counter
232
+ * var giCount = 2;
233
+ *
234
+ * $(document).ready(function() {
235
+ * $('#example').dataTable();
236
+ * } );
237
+ *
238
+ * function fnClickAddRow() {
239
+ * $('#example').dataTable().fnAddData( [
240
+ * giCount+".1",
241
+ * giCount+".2",
242
+ * giCount+".3",
243
+ * giCount+".4" ]
244
+ * );
245
+ *
246
+ * giCount++;
247
+ * }
248
+ */
249
+ this.fnAddData = function( data, redraw )
250
+ {
251
+ var api = this.api( true );
252
+
253
+ /* Check if we want to add multiple rows or not */
254
+ var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
255
+ api.rows.add( data ) :
256
+ api.row.add( data );
257
+
258
+ if ( redraw === undefined || redraw ) {
259
+ api.draw();
260
+ }
261
+
262
+ return rows.flatten().toArray();
263
+ };
264
+
265
+
266
+ /**
267
+ * This function will make DataTables recalculate the column sizes, based on the data
268
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
269
+ * through the sWidth parameter). This can be useful when the width of the table's
270
+ * parent element changes (for example a window resize).
271
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
272
+ * @dtopt API
273
+ * @deprecated Since v1.10
274
+ *
275
+ * @example
276
+ * $(document).ready(function() {
277
+ * var oTable = $('#example').dataTable( {
278
+ * "sScrollY": "200px",
279
+ * "bPaginate": false
280
+ * } );
281
+ *
282
+ * $(window).on('resize', function () {
283
+ * oTable.fnAdjustColumnSizing();
284
+ * } );
285
+ * } );
286
+ */
287
+ this.fnAdjustColumnSizing = function ( bRedraw )
288
+ {
289
+ var api = this.api( true ).columns.adjust();
290
+ var settings = api.settings()[0];
291
+ var scroll = settings.oScroll;
292
+
293
+ if ( bRedraw === undefined || bRedraw ) {
294
+ api.draw( false );
295
+ }
296
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
297
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
298
+ _fnScrollDraw( settings );
299
+ }
300
+ };
301
+
302
+
303
+ /**
304
+ * Quickly and simply clear a table
305
+ * @param {bool} [bRedraw=true] redraw the table or not
306
+ * @dtopt API
307
+ * @deprecated Since v1.10
308
+ *
309
+ * @example
310
+ * $(document).ready(function() {
311
+ * var oTable = $('#example').dataTable();
312
+ *
313
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
314
+ * oTable.fnClearTable();
315
+ * } );
316
+ */
317
+ this.fnClearTable = function( bRedraw )
318
+ {
319
+ var api = this.api( true ).clear();
320
+
321
+ if ( bRedraw === undefined || bRedraw ) {
322
+ api.draw();
323
+ }
324
+ };
325
+
326
+
327
+ /**
328
+ * The exact opposite of 'opening' a row, this function will close any rows which
329
+ * are currently 'open'.
330
+ * @param {node} nTr the table row to 'close'
331
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
332
+ * @dtopt API
333
+ * @deprecated Since v1.10
334
+ *
335
+ * @example
336
+ * $(document).ready(function() {
337
+ * var oTable;
338
+ *
339
+ * // 'open' an information row when a row is clicked on
340
+ * $('#example tbody tr').click( function () {
341
+ * if ( oTable.fnIsOpen(this) ) {
342
+ * oTable.fnClose( this );
343
+ * } else {
344
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
345
+ * }
346
+ * } );
347
+ *
348
+ * oTable = $('#example').dataTable();
349
+ * } );
350
+ */
351
+ this.fnClose = function( nTr )
352
+ {
353
+ this.api( true ).row( nTr ).child.hide();
354
+ };
355
+
356
+
357
+ /**
358
+ * Remove a row for the table
359
+ * @param {mixed} target The index of the row from aoData to be deleted, or
360
+ * the TR element you want to delete
361
+ * @param {function|null} [callBack] Callback function
362
+ * @param {bool} [redraw=true] Redraw the table or not
363
+ * @returns {array} The row that was deleted
364
+ * @dtopt API
365
+ * @deprecated Since v1.10
366
+ *
367
+ * @example
368
+ * $(document).ready(function() {
369
+ * var oTable = $('#example').dataTable();
370
+ *
371
+ * // Immediately remove the first row
372
+ * oTable.fnDeleteRow( 0 );
373
+ * } );
374
+ */
375
+ this.fnDeleteRow = function( target, callback, redraw )
376
+ {
377
+ var api = this.api( true );
378
+ var rows = api.rows( target );
379
+ var settings = rows.settings()[0];
380
+ var data = settings.aoData[ rows[0][0] ];
381
+
382
+ rows.remove();
383
+
384
+ if ( callback ) {
385
+ callback.call( this, settings, data );
386
+ }
387
+
388
+ if ( redraw === undefined || redraw ) {
389
+ api.draw();
390
+ }
391
+
392
+ return data;
393
+ };
394
+
395
+
396
+ /**
397
+ * Restore the table to it's original state in the DOM by removing all of DataTables
398
+ * enhancements, alterations to the DOM structure of the table and event listeners.
399
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
400
+ * @dtopt API
401
+ * @deprecated Since v1.10
402
+ *
403
+ * @example
404
+ * $(document).ready(function() {
405
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
406
+ * var oTable = $('#example').dataTable();
407
+ * oTable.fnDestroy();
408
+ * } );
409
+ */
410
+ this.fnDestroy = function ( remove )
411
+ {
412
+ this.api( true ).destroy( remove );
413
+ };
414
+
415
+
416
+ /**
417
+ * Redraw the table
418
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
419
+ * @dtopt API
420
+ * @deprecated Since v1.10
421
+ *
422
+ * @example
423
+ * $(document).ready(function() {
424
+ * var oTable = $('#example').dataTable();
425
+ *
426
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
427
+ * oTable.fnDraw();
428
+ * } );
429
+ */
430
+ this.fnDraw = function( complete )
431
+ {
432
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
433
+ // into account the new data, but can hold position.
434
+ this.api( true ).draw( complete );
435
+ };
436
+
437
+
438
+ /**
439
+ * Filter the input based on data
440
+ * @param {string} sInput String to filter the table on
441
+ * @param {int|null} [iColumn] Column to limit filtering to
442
+ * @param {bool} [bRegex=false] Treat as regular expression or not
443
+ * @param {bool} [bSmart=true] Perform smart filtering or not
444
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
445
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
446
+ * @dtopt API
447
+ * @deprecated Since v1.10
448
+ *
449
+ * @example
450
+ * $(document).ready(function() {
451
+ * var oTable = $('#example').dataTable();
452
+ *
453
+ * // Sometime later - filter...
454
+ * oTable.fnFilter( 'test string' );
455
+ * } );
456
+ */
457
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
458
+ {
459
+ var api = this.api( true );
460
+
461
+ if ( iColumn === null || iColumn === undefined ) {
462
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
463
+ }
464
+ else {
465
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
466
+ }
467
+
468
+ api.draw();
469
+ };
470
+
471
+
472
+ /**
473
+ * Get the data for the whole table, an individual row or an individual cell based on the
474
+ * provided parameters.
475
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
476
+ * a TR node then the data source for the whole row will be returned. If given as a
477
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
478
+ * cell returned. If given as an integer, then this is treated as the aoData internal
479
+ * data index for the row (see fnGetPosition) and the data for that row used.
480
+ * @param {int} [col] Optional column index that you want the data of.
481
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
482
+ * returned. If mRow is defined, just data for that row, and is iCol is
483
+ * defined, only data for the designated cell is returned.
484
+ * @dtopt API
485
+ * @deprecated Since v1.10
486
+ *
487
+ * @example
488
+ * // Row data
489
+ * $(document).ready(function() {
490
+ * oTable = $('#example').dataTable();
491
+ *
492
+ * oTable.$('tr').click( function () {
493
+ * var data = oTable.fnGetData( this );
494
+ * // ... do something with the array / object of data for the row
495
+ * } );
496
+ * } );
497
+ *
498
+ * @example
499
+ * // Individual cell data
500
+ * $(document).ready(function() {
501
+ * oTable = $('#example').dataTable();
502
+ *
503
+ * oTable.$('td').click( function () {
504
+ * var sData = oTable.fnGetData( this );
505
+ * alert( 'The cell clicked on had the value of '+sData );
506
+ * } );
507
+ * } );
508
+ */
509
+ this.fnGetData = function( src, col )
510
+ {
511
+ var api = this.api( true );
512
+
513
+ if ( src !== undefined ) {
514
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
515
+
516
+ return col !== undefined || type == 'td' || type == 'th' ?
517
+ api.cell( src, col ).data() :
518
+ api.row( src ).data() || null;
519
+ }
520
+
521
+ return api.data().toArray();
522
+ };
523
+
524
+
525
+ /**
526
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
527
+ * typically want to use the '$' API method in preference to this as it is more
528
+ * flexible.
529
+ * @param {int} [iRow] Optional row index for the TR element you want
530
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
531
+ * in the table's body, or iRow is defined, just the TR element requested.
532
+ * @dtopt API
533
+ * @deprecated Since v1.10
534
+ *
535
+ * @example
536
+ * $(document).ready(function() {
537
+ * var oTable = $('#example').dataTable();
538
+ *
539
+ * // Get the nodes from the table
540
+ * var nNodes = oTable.fnGetNodes( );
541
+ * } );
542
+ */
543
+ this.fnGetNodes = function( iRow )
544
+ {
545
+ var api = this.api( true );
546
+
547
+ return iRow !== undefined ?
548
+ api.row( iRow ).node() :
549
+ api.rows().nodes().flatten().toArray();
550
+ };
551
+
552
+
553
+ /**
554
+ * Get the array indexes of a particular cell from it's DOM element
555
+ * and column index including hidden columns
556
+ * @param {node} node this can either be a TR, TD or TH in the table's body
557
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
558
+ * if given as a cell, an array of [row index, column index (visible),
559
+ * column index (all)] is given.
560
+ * @dtopt API
561
+ * @deprecated Since v1.10
562
+ *
563
+ * @example
564
+ * $(document).ready(function() {
565
+ * $('#example tbody td').click( function () {
566
+ * // Get the position of the current data from the node
567
+ * var aPos = oTable.fnGetPosition( this );
568
+ *
569
+ * // Get the data array for this row
570
+ * var aData = oTable.fnGetData( aPos[0] );
571
+ *
572
+ * // Update the data array and return the value
573
+ * aData[ aPos[1] ] = 'clicked';
574
+ * this.innerHTML = 'clicked';
575
+ * } );
576
+ *
577
+ * // Init DataTables
578
+ * oTable = $('#example').dataTable();
579
+ * } );
580
+ */
581
+ this.fnGetPosition = function( node )
582
+ {
583
+ var api = this.api( true );
584
+ var nodeName = node.nodeName.toUpperCase();
585
+
586
+ if ( nodeName == 'TR' ) {
587
+ return api.row( node ).index();
588
+ }
589
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
590
+ var cell = api.cell( node ).index();
591
+
592
+ return [
593
+ cell.row,
594
+ cell.columnVisible,
595
+ cell.column
596
+ ];
597
+ }
598
+ return null;
599
+ };
600
+
601
+
602
+ /**
603
+ * Check to see if a row is 'open' or not.
604
+ * @param {node} nTr the table row to check
605
+ * @returns {boolean} true if the row is currently open, false otherwise
606
+ * @dtopt API
607
+ * @deprecated Since v1.10
608
+ *
609
+ * @example
610
+ * $(document).ready(function() {
611
+ * var oTable;
612
+ *
613
+ * // 'open' an information row when a row is clicked on
614
+ * $('#example tbody tr').click( function () {
615
+ * if ( oTable.fnIsOpen(this) ) {
616
+ * oTable.fnClose( this );
617
+ * } else {
618
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
619
+ * }
620
+ * } );
621
+ *
622
+ * oTable = $('#example').dataTable();
623
+ * } );
624
+ */
625
+ this.fnIsOpen = function( nTr )
626
+ {
627
+ return this.api( true ).row( nTr ).child.isShown();
628
+ };
629
+
630
+
631
+ /**
632
+ * This function will place a new row directly after a row which is currently
633
+ * on display on the page, with the HTML contents that is passed into the
634
+ * function. This can be used, for example, to ask for confirmation that a
635
+ * particular record should be deleted.
636
+ * @param {node} nTr The table row to 'open'
637
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
638
+ * @param {string} sClass Class to give the new TD cell
639
+ * @returns {node} The row opened. Note that if the table row passed in as the
640
+ * first parameter, is not found in the table, this method will silently
641
+ * return.
642
+ * @dtopt API
643
+ * @deprecated Since v1.10
644
+ *
645
+ * @example
646
+ * $(document).ready(function() {
647
+ * var oTable;
648
+ *
649
+ * // 'open' an information row when a row is clicked on
650
+ * $('#example tbody tr').click( function () {
651
+ * if ( oTable.fnIsOpen(this) ) {
652
+ * oTable.fnClose( this );
653
+ * } else {
654
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
655
+ * }
656
+ * } );
657
+ *
658
+ * oTable = $('#example').dataTable();
659
+ * } );
660
+ */
661
+ this.fnOpen = function( nTr, mHtml, sClass )
662
+ {
663
+ return this.api( true )
664
+ .row( nTr )
665
+ .child( mHtml, sClass )
666
+ .show()
667
+ .child()[0];
668
+ };
669
+
670
+
671
+ /**
672
+ * Change the pagination - provides the internal logic for pagination in a simple API
673
+ * function. With this function you can have a DataTables table go to the next,
674
+ * previous, first or last pages.
675
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
676
+ * or page number to jump to (integer), note that page 0 is the first page.
677
+ * @param {bool} [bRedraw=true] Redraw the table or not
678
+ * @dtopt API
679
+ * @deprecated Since v1.10
680
+ *
681
+ * @example
682
+ * $(document).ready(function() {
683
+ * var oTable = $('#example').dataTable();
684
+ * oTable.fnPageChange( 'next' );
685
+ * } );
686
+ */
687
+ this.fnPageChange = function ( mAction, bRedraw )
688
+ {
689
+ var api = this.api( true ).page( mAction );
690
+
691
+ if ( bRedraw === undefined || bRedraw ) {
692
+ api.draw(false);
693
+ }
694
+ };
695
+
696
+
697
+ /**
698
+ * Show a particular column
699
+ * @param {int} iCol The column whose display should be changed
700
+ * @param {bool} bShow Show (true) or hide (false) the column
701
+ * @param {bool} [bRedraw=true] Redraw the table or not
702
+ * @dtopt API
703
+ * @deprecated Since v1.10
704
+ *
705
+ * @example
706
+ * $(document).ready(function() {
707
+ * var oTable = $('#example').dataTable();
708
+ *
709
+ * // Hide the second column after initialisation
710
+ * oTable.fnSetColumnVis( 1, false );
711
+ * } );
712
+ */
713
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
714
+ {
715
+ var api = this.api( true ).column( iCol ).visible( bShow );
716
+
717
+ if ( bRedraw === undefined || bRedraw ) {
718
+ api.columns.adjust().draw();
719
+ }
720
+ };
721
+
722
+
723
+ /**
724
+ * Get the settings for a particular table for external manipulation
725
+ * @returns {object} DataTables settings object. See
726
+ * {@link DataTable.models.oSettings}
727
+ * @dtopt API
728
+ * @deprecated Since v1.10
729
+ *
730
+ * @example
731
+ * $(document).ready(function() {
732
+ * var oTable = $('#example').dataTable();
733
+ * var oSettings = oTable.fnSettings();
734
+ *
735
+ * // Show an example parameter from the settings
736
+ * alert( oSettings._iDisplayStart );
737
+ * } );
738
+ */
739
+ this.fnSettings = function()
740
+ {
741
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
742
+ };
743
+
744
+
745
+ /**
746
+ * Sort the table by a particular column
747
+ * @param {int} iCol the data index to sort on. Note that this will not match the
748
+ * 'display index' if you have hidden data entries
749
+ * @dtopt API
750
+ * @deprecated Since v1.10
751
+ *
752
+ * @example
753
+ * $(document).ready(function() {
754
+ * var oTable = $('#example').dataTable();
755
+ *
756
+ * // Sort immediately with columns 0 and 1
757
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
758
+ * } );
759
+ */
760
+ this.fnSort = function( aaSort )
761
+ {
762
+ this.api( true ).order( aaSort ).draw();
763
+ };
764
+
765
+
766
+ /**
767
+ * Attach a sort listener to an element for a given column
768
+ * @param {node} nNode the element to attach the sort listener to
769
+ * @param {int} iColumn the column that a click on this node will sort on
770
+ * @param {function} [fnCallback] callback function when sort is run
771
+ * @dtopt API
772
+ * @deprecated Since v1.10
773
+ *
774
+ * @example
775
+ * $(document).ready(function() {
776
+ * var oTable = $('#example').dataTable();
777
+ *
778
+ * // Sort on column 1, when 'sorter' is clicked on
779
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
780
+ * } );
781
+ */
782
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
783
+ {
784
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
785
+ };
786
+
787
+
788
+ /**
789
+ * Update a table cell or row - this method will accept either a single value to
790
+ * update the cell with, an array of values with one element for each column or
791
+ * an object in the same format as the original data source. The function is
792
+ * self-referencing in order to make the multi column updates easier.
793
+ * @param {object|array|string} mData Data to update the cell/row with
794
+ * @param {node|int} mRow TR element you want to update or the aoData index
795
+ * @param {int} [iColumn] The column to update, give as null or undefined to
796
+ * update a whole row.
797
+ * @param {bool} [bRedraw=true] Redraw the table or not
798
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
799
+ * @returns {int} 0 on success, 1 on error
800
+ * @dtopt API
801
+ * @deprecated Since v1.10
802
+ *
803
+ * @example
804
+ * $(document).ready(function() {
805
+ * var oTable = $('#example').dataTable();
806
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
807
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
808
+ * } );
809
+ */
810
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
811
+ {
812
+ var api = this.api( true );
813
+
814
+ if ( iColumn === undefined || iColumn === null ) {
815
+ api.row( mRow ).data( mData );
816
+ }
817
+ else {
818
+ api.cell( mRow, iColumn ).data( mData );
819
+ }
820
+
821
+ if ( bAction === undefined || bAction ) {
822
+ api.columns.adjust();
823
+ }
824
+
825
+ if ( bRedraw === undefined || bRedraw ) {
826
+ api.draw();
827
+ }
828
+ return 0;
829
+ };
830
+
831
+
832
+ /**
833
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
834
+ * to ensure compatibility.
835
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
836
+ * formats "X" and "X.Y" are also acceptable.
837
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
838
+ * version, or false if this version of DataTales is not suitable
839
+ * @method
840
+ * @dtopt API
841
+ * @deprecated Since v1.10
842
+ *
843
+ * @example
844
+ * $(document).ready(function() {
845
+ * var oTable = $('#example').dataTable();
846
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
847
+ * } );
848
+ */
849
+ this.fnVersionCheck = _ext.fnVersionCheck;
850
+
851
+
852
+ var _that = this;
853
+ var emptyInit = options === undefined;
854
+ var len = this.length;
855
+
856
+ if ( emptyInit ) {
857
+ options = {};
858
+ }
859
+
860
+ this.oApi = this.internal = _ext.internal;
861
+
862
+ // Extend with old style plug-in API methods
863
+ for ( var fn in DataTable.ext.internal ) {
864
+ if ( fn ) {
865
+ this[fn] = _fnExternApiFunc(fn);
866
+ }
867
+ }
868
+
869
+ this.each(function() {
870
+ // For each initialisation we want to give it a clean initialisation
871
+ // object that can be bashed around
872
+ var o = {};
873
+ var oInit = len > 1 ? // optimisation for single table case
874
+ _fnExtend( o, options, true ) :
875
+ options;
876
+
877
+ /*global oInit,_that,emptyInit*/
878
+ var i=0, iLen, j, jLen, k, kLen;
879
+ var sId = this.getAttribute( 'id' );
880
+ var bInitHandedOff = false;
881
+ var defaults = DataTable.defaults;
882
+ var $this = $(this);
883
+
884
+
885
+ /* Sanity check */
886
+ if ( this.nodeName.toLowerCase() != 'table' )
887
+ {
888
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
889
+ return;
890
+ }
891
+
892
+ /* Backwards compatibility for the defaults */
893
+ _fnCompatOpts( defaults );
894
+ _fnCompatCols( defaults.column );
895
+
896
+ /* Convert the camel-case defaults to Hungarian */
897
+ _fnCamelToHungarian( defaults, defaults, true );
898
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
899
+
900
+ /* Setting up the initialisation object */
901
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) );
902
+
903
+
904
+
905
+ /* Check to see if we are re-initialising a table */
906
+ var allSettings = DataTable.settings;
907
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
908
+ {
909
+ var s = allSettings[i];
910
+
911
+ /* Base check on table node */
912
+ if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) )
913
+ {
914
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
915
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
916
+
917
+ if ( emptyInit || bRetrieve )
918
+ {
919
+ return s.oInstance;
920
+ }
921
+ else if ( bDestroy )
922
+ {
923
+ s.oInstance.fnDestroy();
924
+ break;
925
+ }
926
+ else
927
+ {
928
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
929
+ return;
930
+ }
931
+ }
932
+
933
+ /* If the element we are initialising has the same ID as a table which was previously
934
+ * initialised, but the table nodes don't match (from before) then we destroy the old
935
+ * instance by simply deleting it. This is under the assumption that the table has been
936
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
937
+ */
938
+ if ( s.sTableId == this.id )
939
+ {
940
+ allSettings.splice( i, 1 );
941
+ break;
942
+ }
943
+ }
944
+
945
+ /* Ensure the table has an ID - required for accessibility */
946
+ if ( sId === null || sId === "" )
947
+ {
948
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
949
+ this.id = sId;
950
+ }
951
+
952
+ /* Create the settings object for this table and set some of the default parameters */
953
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
954
+ "sDestroyWidth": $this[0].style.width,
955
+ "sInstance": sId,
956
+ "sTableId": sId
957
+ } );
958
+ oSettings.nTable = this;
959
+ oSettings.oApi = _that.internal;
960
+ oSettings.oInit = oInit;
961
+
962
+ allSettings.push( oSettings );
963
+
964
+ // Need to add the instance after the instance after the settings object has been added
965
+ // to the settings array, so we can self reference the table instance if more than one
966
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
967
+
968
+ // Backwards compatibility, before we apply all the defaults
969
+ _fnCompatOpts( oInit );
970
+
971
+ if ( oInit.oLanguage )
972
+ {
973
+ _fnLanguageCompat( oInit.oLanguage );
974
+ }
975
+
976
+ // If the length menu is given, but the init display length is not, use the length menu
977
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
978
+ {
979
+ oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
980
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
981
+ }
982
+
983
+ // Apply the defaults and init options to make a single init object will all
984
+ // options defined from defaults and instance options.
985
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
986
+
987
+
988
+ // Map the initialisation options onto the settings object
989
+ _fnMap( oSettings.oFeatures, oInit, [
990
+ "bPaginate",
991
+ "bLengthChange",
992
+ "bFilter",
993
+ "bSort",
994
+ "bSortMulti",
995
+ "bInfo",
996
+ "bProcessing",
997
+ "bAutoWidth",
998
+ "bSortClasses",
999
+ "bServerSide",
1000
+ "bDeferRender"
1001
+ ] );
1002
+ _fnMap( oSettings, oInit, [
1003
+ "asStripeClasses",
1004
+ "ajax",
1005
+ "fnServerData",
1006
+ "fnFormatNumber",
1007
+ "sServerMethod",
1008
+ "aaSorting",
1009
+ "aaSortingFixed",
1010
+ "aLengthMenu",
1011
+ "sPaginationType",
1012
+ "sAjaxSource",
1013
+ "sAjaxDataProp",
1014
+ "iStateDuration",
1015
+ "sDom",
1016
+ "bSortCellsTop",
1017
+ "iTabIndex",
1018
+ "fnStateLoadCallback",
1019
+ "fnStateSaveCallback",
1020
+ "renderer",
1021
+ "searchDelay",
1022
+ "rowId",
1023
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
1024
+ [ "oSearch", "oPreviousSearch" ],
1025
+ [ "aoSearchCols", "aoPreSearchCols" ],
1026
+ [ "iDisplayLength", "_iDisplayLength" ]
1027
+ ] );
1028
+ _fnMap( oSettings.oScroll, oInit, [
1029
+ [ "sScrollX", "sX" ],
1030
+ [ "sScrollXInner", "sXInner" ],
1031
+ [ "sScrollY", "sY" ],
1032
+ [ "bScrollCollapse", "bCollapse" ]
1033
+ ] );
1034
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
1035
+
1036
+ /* Callback functions which are array driven */
1037
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
1038
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
1039
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
1040
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
1041
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
1042
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
1043
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
1044
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
1045
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
1046
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
1047
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
1048
+
1049
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
1050
+
1051
+ /* Browser support detection */
1052
+ _fnBrowserDetect( oSettings );
1053
+
1054
+ var oClasses = oSettings.oClasses;
1055
+
1056
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
1057
+ $this.addClass( oClasses.sTable );
1058
+
1059
+
1060
+ if ( oSettings.iInitDisplayStart === undefined )
1061
+ {
1062
+ /* Display start point, taking into account the save saving */
1063
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
1064
+ oSettings._iDisplayStart = oInit.iDisplayStart;
1065
+ }
1066
+
1067
+ if ( oInit.iDeferLoading !== null )
1068
+ {
1069
+ oSettings.bDeferLoading = true;
1070
+ var tmp = $.isArray( oInit.iDeferLoading );
1071
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
1072
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
1073
+ }
1074
+
1075
+ /* Language definitions */
1076
+ var oLanguage = oSettings.oLanguage;
1077
+ $.extend( true, oLanguage, oInit.oLanguage );
1078
+
1079
+ if ( oLanguage.sUrl )
1080
+ {
1081
+ /* Get the language definitions from a file - because this Ajax call makes the language
1082
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
1083
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
1084
+ */
1085
+ $.ajax( {
1086
+ dataType: 'json',
1087
+ url: oLanguage.sUrl,
1088
+ success: function ( json ) {
1089
+ _fnLanguageCompat( json );
1090
+ _fnCamelToHungarian( defaults.oLanguage, json );
1091
+ $.extend( true, oLanguage, json );
1092
+ _fnInitialise( oSettings );
1093
+ },
1094
+ error: function () {
1095
+ // Error occurred loading language file, continue on as best we can
1096
+ _fnInitialise( oSettings );
1097
+ }
1098
+ } );
1099
+ bInitHandedOff = true;
1100
+ }
1101
+
1102
+ /*
1103
+ * Stripes
1104
+ */
1105
+ if ( oInit.asStripeClasses === null )
1106
+ {
1107
+ oSettings.asStripeClasses =[
1108
+ oClasses.sStripeOdd,
1109
+ oClasses.sStripeEven
1110
+ ];
1111
+ }
1112
+
1113
+ /* Remove row stripe classes if they are already on the table row */
1114
+ var stripeClasses = oSettings.asStripeClasses;
1115
+ var rowOne = $this.children('tbody').find('tr').eq(0);
1116
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
1117
+ return rowOne.hasClass(el);
1118
+ } ) ) !== -1 ) {
1119
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
1120
+ oSettings.asDestroyStripes = stripeClasses.slice();
1121
+ }
1122
+
1123
+ /*
1124
+ * Columns
1125
+ * See if we should load columns automatically or use defined ones
1126
+ */
1127
+ var anThs = [];
1128
+ var aoColumnsInit;
1129
+ var nThead = this.getElementsByTagName('thead');
1130
+ if ( nThead.length !== 0 )
1131
+ {
1132
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
1133
+ anThs = _fnGetUniqueThs( oSettings );
1134
+ }
1135
+
1136
+ /* If not given a column array, generate one with nulls */
1137
+ if ( oInit.aoColumns === null )
1138
+ {
1139
+ aoColumnsInit = [];
1140
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
1141
+ {
1142
+ aoColumnsInit.push( null );
1143
+ }
1144
+ }
1145
+ else
1146
+ {
1147
+ aoColumnsInit = oInit.aoColumns;
1148
+ }
1149
+
1150
+ /* Add the columns */
1151
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
1152
+ {
1153
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
1154
+ }
1155
+
1156
+ /* Apply the column definitions */
1157
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
1158
+ _fnColumnOptions( oSettings, iCol, oDef );
1159
+ } );
1160
+
1161
+ /* HTML5 attribute detection - build an mData object automatically if the
1162
+ * attributes are found
1163
+ */
1164
+ if ( rowOne.length ) {
1165
+ var a = function ( cell, name ) {
1166
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
1167
+ };
1168
+
1169
+ $( rowOne[0] ).children('th, td').each( function (i, cell) {
1170
+ var col = oSettings.aoColumns[i];
1171
+
1172
+ if ( col.mData === i ) {
1173
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
1174
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
1175
+
1176
+ if ( sort !== null || filter !== null ) {
1177
+ col.mData = {
1178
+ _: i+'.display',
1179
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
1180
+ type: sort !== null ? i+'.@data-'+sort : undefined,
1181
+ filter: filter !== null ? i+'.@data-'+filter : undefined
1182
+ };
1183
+
1184
+ _fnColumnOptions( oSettings, i );
1185
+ }
1186
+ }
1187
+ } );
1188
+ }
1189
+
1190
+ var features = oSettings.oFeatures;
1191
+ var loadedInit = function () {
1192
+ /*
1193
+ * Sorting
1194
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
1195
+ */
1196
+
1197
+ // If aaSorting is not defined, then we use the first indicator in asSorting
1198
+ // in case that has been altered, so the default sort reflects that option
1199
+ if ( oInit.aaSorting === undefined ) {
1200
+ var sorting = oSettings.aaSorting;
1201
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
1202
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
1203
+ }
1204
+ }
1205
+
1206
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
1207
+ * account, and also will apply sorting disabled classes if disabled
1208
+ */
1209
+ _fnSortingClasses( oSettings );
1210
+
1211
+ if ( features.bSort ) {
1212
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1213
+ if ( oSettings.bSorted ) {
1214
+ var aSort = _fnSortFlatten( oSettings );
1215
+ var sortedColumns = {};
1216
+
1217
+ $.each( aSort, function (i, val) {
1218
+ sortedColumns[ val.src ] = val.dir;
1219
+ } );
1220
+
1221
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
1222
+ _fnSortAria( oSettings );
1223
+ }
1224
+ } );
1225
+ }
1226
+
1227
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
1228
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
1229
+ _fnSortingClasses( oSettings );
1230
+ }
1231
+ }, 'sc' );
1232
+
1233
+
1234
+ /*
1235
+ * Final init
1236
+ * Cache the header, body and footer as required, creating them if needed
1237
+ */
1238
+
1239
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
1240
+ var captions = $this.children('caption').each( function () {
1241
+ this._captionSide = $(this).css('caption-side');
1242
+ } );
1243
+
1244
+ var thead = $this.children('thead');
1245
+ if ( thead.length === 0 ) {
1246
+ thead = $('<thead/>').appendTo($this);
1247
+ }
1248
+ oSettings.nTHead = thead[0];
1249
+
1250
+ var tbody = $this.children('tbody');
1251
+ if ( tbody.length === 0 ) {
1252
+ tbody = $('<tbody/>').appendTo($this);
1253
+ }
1254
+ oSettings.nTBody = tbody[0];
1255
+
1256
+ var tfoot = $this.children('tfoot');
1257
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
1258
+ // If we are a scrolling table, and no footer has been given, then we need to create
1259
+ // a tfoot element for the caption element to be appended to
1260
+ tfoot = $('<tfoot/>').appendTo($this);
1261
+ }
1262
+
1263
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
1264
+ $this.addClass( oClasses.sNoFooter );
1265
+ }
1266
+ else if ( tfoot.length > 0 ) {
1267
+ oSettings.nTFoot = tfoot[0];
1268
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
1269
+ }
1270
+
1271
+ /* Check if there is data passing into the constructor */
1272
+ if ( oInit.aaData ) {
1273
+ for ( i=0 ; i<oInit.aaData.length ; i++ ) {
1274
+ _fnAddData( oSettings, oInit.aaData[ i ] );
1275
+ }
1276
+ }
1277
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
1278
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
1279
+ * source since there is no point in reading the DOM data if we are then going
1280
+ * to replace it with Ajax data
1281
+ */
1282
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
1283
+ }
1284
+
1285
+ /* Copy the data index array */
1286
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1287
+
1288
+ /* Initialisation complete - table can be drawn */
1289
+ oSettings.bInitialised = true;
1290
+
1291
+ /* Check if we need to initialise the table (it might not have been handed off to the
1292
+ * language processor)
1293
+ */
1294
+ if ( bInitHandedOff === false ) {
1295
+ _fnInitialise( oSettings );
1296
+ }
1297
+ };
1298
+
1299
+ /* Must be done after everything which can be overridden by the state saving! */
1300
+ if ( oInit.bStateSave )
1301
+ {
1302
+ features.bStateSave = true;
1303
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
1304
+ _fnLoadState( oSettings, oInit, loadedInit );
1305
+ }
1306
+ else {
1307
+ loadedInit();
1308
+ }
1309
+
1310
+ } );
1311
+ _that = null;
1312
+ return this;
1313
+ };
1314
+
1315
+
1316
+ /*
1317
+ * It is useful to have variables which are scoped locally so only the
1318
+ * DataTables functions can access them and they don't leak into global space.
1319
+ * At the same time these functions are often useful over multiple files in the
1320
+ * core and API, so we list, or at least document, all variables which are used
1321
+ * by DataTables as private variables here. This also ensures that there is no
1322
+ * clashing of variable names and that they can easily referenced for reuse.
1323
+ */
1324
+
1325
+
1326
+ // Defined else where
1327
+ // _selector_run
1328
+ // _selector_opts
1329
+ // _selector_first
1330
+ // _selector_row_indexes
1331
+
1332
+ var _ext; // DataTable.ext
1333
+ var _Api; // DataTable.Api
1334
+ var _api_register; // DataTable.Api.register
1335
+ var _api_registerPlural; // DataTable.Api.registerPlural
1336
+
1337
+ var _re_dic = {};
1338
+ var _re_new_lines = /[\r\n]/g;
1339
+ var _re_html = /<.*?>/g;
1340
+
1341
+ // This is not strict ISO8601 - Date.parse() is quite lax, although
1342
+ // implementations differ between browsers.
1343
+ var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
1344
+
1345
+ // Escape regular expression special characters
1346
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
1347
+
1348
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
1349
+ // - \u20BD - Russian ruble.
1350
+ // - \u20a9 - South Korean Won
1351
+ // - \u20BA - Turkish Lira
1352
+ // - \u20B9 - Indian Rupee
1353
+ // - R - Brazil (R$) and South Africa
1354
+ // - fr - Swiss Franc
1355
+ // - kr - Swedish krona, Norwegian krone and Danish krone
1356
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
1357
+ // standards as thousands separators.
1358
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi;
1359
+
1360
+
1361
+ var _empty = function ( d ) {
1362
+ return !d || d === true || d === '-' ? true : false;
1363
+ };
1364
+
1365
+
1366
+ var _intVal = function ( s ) {
1367
+ var integer = parseInt( s, 10 );
1368
+ return !isNaN(integer) && isFinite(s) ? integer : null;
1369
+ };
1370
+
1371
+ // Convert from a formatted number with characters other than `.` as the
1372
+ // decimal place, to a Javascript number
1373
+ var _numToDecimal = function ( num, decimalPoint ) {
1374
+ // Cache created regular expressions for speed as this function is called often
1375
+ if ( ! _re_dic[ decimalPoint ] ) {
1376
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
1377
+ }
1378
+ return typeof num === 'string' && decimalPoint !== '.' ?
1379
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
1380
+ num;
1381
+ };
1382
+
1383
+
1384
+ var _isNumber = function ( d, decimalPoint, formatted ) {
1385
+ var strType = typeof d === 'string';
1386
+
1387
+ // If empty return immediately so there must be a number if it is a
1388
+ // formatted string (this stops the string "k", or "kr", etc being detected
1389
+ // as a formatted number for currency
1390
+ if ( _empty( d ) ) {
1391
+ return true;
1392
+ }
1393
+
1394
+ if ( decimalPoint && strType ) {
1395
+ d = _numToDecimal( d, decimalPoint );
1396
+ }
1397
+
1398
+ if ( formatted && strType ) {
1399
+ d = d.replace( _re_formatted_numeric, '' );
1400
+ }
1401
+
1402
+ return !isNaN( parseFloat(d) ) && isFinite( d );
1403
+ };
1404
+
1405
+
1406
+ // A string without HTML in it can be considered to be HTML still
1407
+ var _isHtml = function ( d ) {
1408
+ return _empty( d ) || typeof d === 'string';
1409
+ };
1410
+
1411
+
1412
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
1413
+ if ( _empty( d ) ) {
1414
+ return true;
1415
+ }
1416
+
1417
+ var html = _isHtml( d );
1418
+ return ! html ?
1419
+ null :
1420
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
1421
+ true :
1422
+ null;
1423
+ };
1424
+
1425
+
1426
+ var _pluck = function ( a, prop, prop2 ) {
1427
+ var out = [];
1428
+ var i=0, ien=a.length;
1429
+
1430
+ // Could have the test in the loop for slightly smaller code, but speed
1431
+ // is essential here
1432
+ if ( prop2 !== undefined ) {
1433
+ for ( ; i<ien ; i++ ) {
1434
+ if ( a[i] && a[i][ prop ] ) {
1435
+ out.push( a[i][ prop ][ prop2 ] );
1436
+ }
1437
+ }
1438
+ }
1439
+ else {
1440
+ for ( ; i<ien ; i++ ) {
1441
+ if ( a[i] ) {
1442
+ out.push( a[i][ prop ] );
1443
+ }
1444
+ }
1445
+ }
1446
+
1447
+ return out;
1448
+ };
1449
+
1450
+
1451
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
1452
+ // as the indexes to pick from `a`
1453
+ var _pluck_order = function ( a, order, prop, prop2 )
1454
+ {
1455
+ var out = [];
1456
+ var i=0, ien=order.length;
1457
+
1458
+ // Could have the test in the loop for slightly smaller code, but speed
1459
+ // is essential here
1460
+ if ( prop2 !== undefined ) {
1461
+ for ( ; i<ien ; i++ ) {
1462
+ if ( a[ order[i] ][ prop ] ) {
1463
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
1464
+ }
1465
+ }
1466
+ }
1467
+ else {
1468
+ for ( ; i<ien ; i++ ) {
1469
+ out.push( a[ order[i] ][ prop ] );
1470
+ }
1471
+ }
1472
+
1473
+ return out;
1474
+ };
1475
+
1476
+
1477
+ var _range = function ( len, start )
1478
+ {
1479
+ var out = [];
1480
+ var end;
1481
+
1482
+ if ( start === undefined ) {
1483
+ start = 0;
1484
+ end = len;
1485
+ }
1486
+ else {
1487
+ end = start;
1488
+ start = len;
1489
+ }
1490
+
1491
+ for ( var i=start ; i<end ; i++ ) {
1492
+ out.push( i );
1493
+ }
1494
+
1495
+ return out;
1496
+ };
1497
+
1498
+
1499
+ var _removeEmpty = function ( a )
1500
+ {
1501
+ var out = [];
1502
+
1503
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1504
+ if ( a[i] ) { // careful - will remove all falsy values!
1505
+ out.push( a[i] );
1506
+ }
1507
+ }
1508
+
1509
+ return out;
1510
+ };
1511
+
1512
+
1513
+ var _stripHtml = function ( d ) {
1514
+ return d.replace( _re_html, '' );
1515
+ };
1516
+
1517
+
1518
+ /**
1519
+ * Determine if all values in the array are unique. This means we can short
1520
+ * cut the _unique method at the cost of a single loop. A sorted array is used
1521
+ * to easily check the values.
1522
+ *
1523
+ * @param {array} src Source array
1524
+ * @return {boolean} true if all unique, false otherwise
1525
+ * @ignore
1526
+ */
1527
+ var _areAllUnique = function ( src ) {
1528
+ if ( src.length < 2 ) {
1529
+ return true;
1530
+ }
1531
+
1532
+ var sorted = src.slice().sort();
1533
+ var last = sorted[0];
1534
+
1535
+ for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
1536
+ if ( sorted[i] === last ) {
1537
+ return false;
1538
+ }
1539
+
1540
+ last = sorted[i];
1541
+ }
1542
+
1543
+ return true;
1544
+ };
1545
+
1546
+
1547
+ /**
1548
+ * Find the unique elements in a source array.
1549
+ *
1550
+ * @param {array} src Source array
1551
+ * @return {array} Array of unique items
1552
+ * @ignore
1553
+ */
1554
+ var _unique = function ( src )
1555
+ {
1556
+ if ( _areAllUnique( src ) ) {
1557
+ return src.slice();
1558
+ }
1559
+
1560
+ // A faster unique method is to use object keys to identify used values,
1561
+ // but this doesn't work with arrays or objects, which we must also
1562
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
1563
+ // information.
1564
+ var
1565
+ out = [],
1566
+ val,
1567
+ i, ien=src.length,
1568
+ j, k=0;
1569
+
1570
+ again: for ( i=0 ; i<ien ; i++ ) {
1571
+ val = src[i];
1572
+
1573
+ for ( j=0 ; j<k ; j++ ) {
1574
+ if ( out[j] === val ) {
1575
+ continue again;
1576
+ }
1577
+ }
1578
+
1579
+ out.push( val );
1580
+ k++;
1581
+ }
1582
+
1583
+ return out;
1584
+ };
1585
+
1586
+
1587
+ /**
1588
+ * DataTables utility methods
1589
+ *
1590
+ * This namespace provides helper methods that DataTables uses internally to
1591
+ * create a DataTable, but which are not exclusively used only for DataTables.
1592
+ * These methods can be used by extension authors to save the duplication of
1593
+ * code.
1594
+ *
1595
+ * @namespace
1596
+ */
1597
+ DataTable.util = {
1598
+ /**
1599
+ * Throttle the calls to a function. Arguments and context are maintained
1600
+ * for the throttled function.
1601
+ *
1602
+ * @param {function} fn Function to be called
1603
+ * @param {integer} freq Call frequency in mS
1604
+ * @return {function} Wrapped function
1605
+ */
1606
+ throttle: function ( fn, freq ) {
1607
+ var
1608
+ frequency = freq !== undefined ? freq : 200,
1609
+ last,
1610
+ timer;
1611
+
1612
+ return function () {
1613
+ var
1614
+ that = this,
1615
+ now = +new Date(),
1616
+ args = arguments;
1617
+
1618
+ if ( last && now < last + frequency ) {
1619
+ clearTimeout( timer );
1620
+
1621
+ timer = setTimeout( function () {
1622
+ last = undefined;
1623
+ fn.apply( that, args );
1624
+ }, frequency );
1625
+ }
1626
+ else {
1627
+ last = now;
1628
+ fn.apply( that, args );
1629
+ }
1630
+ };
1631
+ },
1632
+
1633
+
1634
+ /**
1635
+ * Escape a string such that it can be used in a regular expression
1636
+ *
1637
+ * @param {string} val string to escape
1638
+ * @returns {string} escaped string
1639
+ */
1640
+ escapeRegex: function ( val ) {
1641
+ return val.replace( _re_escape_regex, '\\$1' );
1642
+ }
1643
+ };
1644
+
1645
+
1646
+
1647
+ /**
1648
+ * Create a mapping object that allows camel case parameters to be looked up
1649
+ * for their Hungarian counterparts. The mapping is stored in a private
1650
+ * parameter called `_hungarianMap` which can be accessed on the source object.
1651
+ * @param {object} o
1652
+ * @memberof DataTable#oApi
1653
+ */
1654
+ function _fnHungarianMap ( o )
1655
+ {
1656
+ var
1657
+ hungarian = 'a aa ai ao as b fn i m o s ',
1658
+ match,
1659
+ newKey,
1660
+ map = {};
1661
+
1662
+ $.each( o, function (key, val) {
1663
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
1664
+
1665
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
1666
+ {
1667
+ newKey = key.replace( match[0], match[2].toLowerCase() );
1668
+ map[ newKey ] = key;
1669
+
1670
+ if ( match[1] === 'o' )
1671
+ {
1672
+ _fnHungarianMap( o[key] );
1673
+ }
1674
+ }
1675
+ } );
1676
+
1677
+ o._hungarianMap = map;
1678
+ }
1679
+
1680
+
1681
+ /**
1682
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
1683
+ * created by _fnHungarianMap.
1684
+ * @param {object} src The model object which holds all parameters that can be
1685
+ * mapped.
1686
+ * @param {object} user The object to convert from camel case to Hungarian.
1687
+ * @param {boolean} force When set to `true`, properties which already have a
1688
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
1689
+ * won't be.
1690
+ * @memberof DataTable#oApi
1691
+ */
1692
+ function _fnCamelToHungarian ( src, user, force )
1693
+ {
1694
+ if ( ! src._hungarianMap ) {
1695
+ _fnHungarianMap( src );
1696
+ }
1697
+
1698
+ var hungarianKey;
1699
+
1700
+ $.each( user, function (key, val) {
1701
+ hungarianKey = src._hungarianMap[ key ];
1702
+
1703
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
1704
+ {
1705
+ // For objects, we need to buzz down into the object to copy parameters
1706
+ if ( hungarianKey.charAt(0) === 'o' )
1707
+ {
1708
+ // Copy the camelCase options over to the hungarian
1709
+ if ( ! user[ hungarianKey ] ) {
1710
+ user[ hungarianKey ] = {};
1711
+ }
1712
+ $.extend( true, user[hungarianKey], user[key] );
1713
+
1714
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
1715
+ }
1716
+ else {
1717
+ user[hungarianKey] = user[ key ];
1718
+ }
1719
+ }
1720
+ } );
1721
+ }
1722
+
1723
+
1724
+ /**
1725
+ * Language compatibility - when certain options are given, and others aren't, we
1726
+ * need to duplicate the values over, in order to provide backwards compatibility
1727
+ * with older language files.
1728
+ * @param {object} oSettings dataTables settings object
1729
+ * @memberof DataTable#oApi
1730
+ */
1731
+ function _fnLanguageCompat( lang )
1732
+ {
1733
+ var defaults = DataTable.defaults.oLanguage;
1734
+ var zeroRecords = lang.sZeroRecords;
1735
+
1736
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
1737
+ * sZeroRecords - assuming that is given.
1738
+ */
1739
+ if ( ! lang.sEmptyTable && zeroRecords &&
1740
+ defaults.sEmptyTable === "No data available in table" )
1741
+ {
1742
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
1743
+ }
1744
+
1745
+ /* Likewise with loading records */
1746
+ if ( ! lang.sLoadingRecords && zeroRecords &&
1747
+ defaults.sLoadingRecords === "Loading..." )
1748
+ {
1749
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
1750
+ }
1751
+
1752
+ // Old parameter name of the thousands separator mapped onto the new
1753
+ if ( lang.sInfoThousands ) {
1754
+ lang.sThousands = lang.sInfoThousands;
1755
+ }
1756
+
1757
+ var decimal = lang.sDecimal;
1758
+ if ( decimal ) {
1759
+ _addNumericSort( decimal );
1760
+ }
1761
+ }
1762
+
1763
+
1764
+ /**
1765
+ * Map one parameter onto another
1766
+ * @param {object} o Object to map
1767
+ * @param {*} knew The new parameter name
1768
+ * @param {*} old The old parameter name
1769
+ */
1770
+ var _fnCompatMap = function ( o, knew, old ) {
1771
+ if ( o[ knew ] !== undefined ) {
1772
+ o[ old ] = o[ knew ];
1773
+ }
1774
+ };
1775
+
1776
+
1777
+ /**
1778
+ * Provide backwards compatibility for the main DT options. Note that the new
1779
+ * options are mapped onto the old parameters, so this is an external interface
1780
+ * change only.
1781
+ * @param {object} init Object to map
1782
+ */
1783
+ function _fnCompatOpts ( init )
1784
+ {
1785
+ _fnCompatMap( init, 'ordering', 'bSort' );
1786
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
1787
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
1788
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
1789
+ _fnCompatMap( init, 'order', 'aaSorting' );
1790
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
1791
+ _fnCompatMap( init, 'paging', 'bPaginate' );
1792
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
1793
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
1794
+ _fnCompatMap( init, 'searching', 'bFilter' );
1795
+
1796
+ // Boolean initialisation of x-scrolling
1797
+ if ( typeof init.sScrollX === 'boolean' ) {
1798
+ init.sScrollX = init.sScrollX ? '100%' : '';
1799
+ }
1800
+ if ( typeof init.scrollX === 'boolean' ) {
1801
+ init.scrollX = init.scrollX ? '100%' : '';
1802
+ }
1803
+
1804
+ // Column search objects are in an array, so it needs to be converted
1805
+ // element by element
1806
+ var searchCols = init.aoSearchCols;
1807
+
1808
+ if ( searchCols ) {
1809
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
1810
+ if ( searchCols[i] ) {
1811
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
1812
+ }
1813
+ }
1814
+ }
1815
+ }
1816
+
1817
+
1818
+ /**
1819
+ * Provide backwards compatibility for column options. Note that the new options
1820
+ * are mapped onto the old parameters, so this is an external interface change
1821
+ * only.
1822
+ * @param {object} init Object to map
1823
+ */
1824
+ function _fnCompatCols ( init )
1825
+ {
1826
+ _fnCompatMap( init, 'orderable', 'bSortable' );
1827
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
1828
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
1829
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
1830
+
1831
+ // orderData can be given as an integer
1832
+ var dataSort = init.aDataSort;
1833
+ if ( typeof dataSort === 'number' && ! $.isArray( dataSort ) ) {
1834
+ init.aDataSort = [ dataSort ];
1835
+ }
1836
+ }
1837
+
1838
+
1839
+ /**
1840
+ * Browser feature detection for capabilities, quirks
1841
+ * @param {object} settings dataTables settings object
1842
+ * @memberof DataTable#oApi
1843
+ */
1844
+ function _fnBrowserDetect( settings )
1845
+ {
1846
+ // We don't need to do this every time DataTables is constructed, the values
1847
+ // calculated are specific to the browser and OS configuration which we
1848
+ // don't expect to change between initialisations
1849
+ if ( ! DataTable.__browser ) {
1850
+ var browser = {};
1851
+ DataTable.__browser = browser;
1852
+
1853
+ // Scrolling feature / quirks detection
1854
+ var n = $('<div/>')
1855
+ .css( {
1856
+ position: 'fixed',
1857
+ top: 0,
1858
+ left: $(window).scrollLeft()*-1, // allow for scrolling
1859
+ height: 1,
1860
+ width: 1,
1861
+ overflow: 'hidden'
1862
+ } )
1863
+ .append(
1864
+ $('<div/>')
1865
+ .css( {
1866
+ position: 'absolute',
1867
+ top: 1,
1868
+ left: 1,
1869
+ width: 100,
1870
+ overflow: 'scroll'
1871
+ } )
1872
+ .append(
1873
+ $('<div/>')
1874
+ .css( {
1875
+ width: '100%',
1876
+ height: 10
1877
+ } )
1878
+ )
1879
+ )
1880
+ .appendTo( 'body' );
1881
+
1882
+ var outer = n.children();
1883
+ var inner = outer.children();
1884
+
1885
+ // Numbers below, in order, are:
1886
+ // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
1887
+ //
1888
+ // IE6 XP: 100 100 100 83
1889
+ // IE7 Vista: 100 100 100 83
1890
+ // IE 8+ Windows: 83 83 100 83
1891
+ // Evergreen Windows: 83 83 100 83
1892
+ // Evergreen Mac with scrollbars: 85 85 100 85
1893
+ // Evergreen Mac without scrollbars: 100 100 100 100
1894
+
1895
+ // Get scrollbar width
1896
+ browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
1897
+
1898
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
1899
+ // include the width of the scrollbar, while other browsers ensure the inner
1900
+ // element is contained without forcing scrolling
1901
+ browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
1902
+
1903
+ // In rtl text layout, some browsers (most, but not all) will place the
1904
+ // scrollbar on the left, rather than the right.
1905
+ browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
1906
+
1907
+ // IE8- don't provide height and width for getBoundingClientRect
1908
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
1909
+
1910
+ n.remove();
1911
+ }
1912
+
1913
+ $.extend( settings.oBrowser, DataTable.__browser );
1914
+ settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
1915
+ }
1916
+
1917
+
1918
+ /**
1919
+ * Array.prototype reduce[Right] method, used for browsers which don't support
1920
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
1921
+ * @param {object} settings dataTables settings object
1922
+ * @memberof DataTable#oApi
1923
+ */
1924
+ function _fnReduce ( that, fn, init, start, end, inc )
1925
+ {
1926
+ var
1927
+ i = start,
1928
+ value,
1929
+ isSet = false;
1930
+
1931
+ if ( init !== undefined ) {
1932
+ value = init;
1933
+ isSet = true;
1934
+ }
1935
+
1936
+ while ( i !== end ) {
1937
+ if ( ! that.hasOwnProperty(i) ) {
1938
+ continue;
1939
+ }
1940
+
1941
+ value = isSet ?
1942
+ fn( value, that[i], i, that ) :
1943
+ that[i];
1944
+
1945
+ isSet = true;
1946
+ i += inc;
1947
+ }
1948
+
1949
+ return value;
1950
+ }
1951
+
1952
+ /**
1953
+ * Add a column to the list used for the table with default values
1954
+ * @param {object} oSettings dataTables settings object
1955
+ * @param {node} nTh The th element for this column
1956
+ * @memberof DataTable#oApi
1957
+ */
1958
+ function _fnAddColumn( oSettings, nTh )
1959
+ {
1960
+ // Add column to aoColumns array
1961
+ var oDefaults = DataTable.defaults.column;
1962
+ var iCol = oSettings.aoColumns.length;
1963
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
1964
+ "nTh": nTh ? nTh : document.createElement('th'),
1965
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
1966
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
1967
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
1968
+ idx: iCol
1969
+ } );
1970
+ oSettings.aoColumns.push( oCol );
1971
+
1972
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
1973
+ // passed into extend can be undefined. This allows the user to give a default
1974
+ // with only some of the parameters defined, and also not give a default
1975
+ var searchCols = oSettings.aoPreSearchCols;
1976
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
1977
+
1978
+ // Use the default column options function to initialise classes etc
1979
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
1980
+ }
1981
+
1982
+
1983
+ /**
1984
+ * Apply options for a column
1985
+ * @param {object} oSettings dataTables settings object
1986
+ * @param {int} iCol column index to consider
1987
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
1988
+ * @memberof DataTable#oApi
1989
+ */
1990
+ function _fnColumnOptions( oSettings, iCol, oOptions )
1991
+ {
1992
+ var oCol = oSettings.aoColumns[ iCol ];
1993
+ var oClasses = oSettings.oClasses;
1994
+ var th = $(oCol.nTh);
1995
+
1996
+ // Try to get width information from the DOM. We can't get it from CSS
1997
+ // as we'd need to parse the CSS stylesheet. `width` option can override
1998
+ if ( ! oCol.sWidthOrig ) {
1999
+ // Width attribute
2000
+ oCol.sWidthOrig = th.attr('width') || null;
2001
+
2002
+ // Style attribute
2003
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
2004
+ if ( t ) {
2005
+ oCol.sWidthOrig = t[1];
2006
+ }
2007
+ }
2008
+
2009
+ /* User specified column options */
2010
+ if ( oOptions !== undefined && oOptions !== null )
2011
+ {
2012
+ // Backwards compatibility
2013
+ _fnCompatCols( oOptions );
2014
+
2015
+ // Map camel case parameters to their Hungarian counterparts
2016
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions );
2017
+
2018
+ /* Backwards compatibility for mDataProp */
2019
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
2020
+ {
2021
+ oOptions.mData = oOptions.mDataProp;
2022
+ }
2023
+
2024
+ if ( oOptions.sType )
2025
+ {
2026
+ oCol._sManualType = oOptions.sType;
2027
+ }
2028
+
2029
+ // `class` is a reserved word in Javascript, so we need to provide
2030
+ // the ability to use a valid name for the camel case input
2031
+ if ( oOptions.className && ! oOptions.sClass )
2032
+ {
2033
+ oOptions.sClass = oOptions.className;
2034
+ }
2035
+ if ( oOptions.sClass ) {
2036
+ th.addClass( oOptions.sClass );
2037
+ }
2038
+
2039
+ $.extend( oCol, oOptions );
2040
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
2041
+
2042
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
2043
+ * priority if defined
2044
+ */
2045
+ if ( oOptions.iDataSort !== undefined )
2046
+ {
2047
+ oCol.aDataSort = [ oOptions.iDataSort ];
2048
+ }
2049
+ _fnMap( oCol, oOptions, "aDataSort" );
2050
+ }
2051
+
2052
+ /* Cache the data get and set functions for speed */
2053
+ var mDataSrc = oCol.mData;
2054
+ var mData = _fnGetObjectDataFn( mDataSrc );
2055
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
2056
+
2057
+ var attrTest = function( src ) {
2058
+ return typeof src === 'string' && src.indexOf('@') !== -1;
2059
+ };
2060
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
2061
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
2062
+ );
2063
+ oCol._setter = null;
2064
+
2065
+ oCol.fnGetData = function (rowData, type, meta) {
2066
+ var innerData = mData( rowData, type, undefined, meta );
2067
+
2068
+ return mRender && type ?
2069
+ mRender( innerData, type, rowData, meta ) :
2070
+ innerData;
2071
+ };
2072
+ oCol.fnSetData = function ( rowData, val, meta ) {
2073
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
2074
+ };
2075
+
2076
+ // Indicate if DataTables should read DOM data as an object or array
2077
+ // Used in _fnGetRowElements
2078
+ if ( typeof mDataSrc !== 'number' ) {
2079
+ oSettings._rowReadObject = true;
2080
+ }
2081
+
2082
+ /* Feature sorting overrides column specific when off */
2083
+ if ( !oSettings.oFeatures.bSort )
2084
+ {
2085
+ oCol.bSortable = false;
2086
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
2087
+ }
2088
+
2089
+ /* Check that the class assignment is correct for sorting */
2090
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
2091
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
2092
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
2093
+ {
2094
+ oCol.sSortingClass = oClasses.sSortableNone;
2095
+ oCol.sSortingClassJUI = "";
2096
+ }
2097
+ else if ( bAsc && !bDesc )
2098
+ {
2099
+ oCol.sSortingClass = oClasses.sSortableAsc;
2100
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
2101
+ }
2102
+ else if ( !bAsc && bDesc )
2103
+ {
2104
+ oCol.sSortingClass = oClasses.sSortableDesc;
2105
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
2106
+ }
2107
+ else
2108
+ {
2109
+ oCol.sSortingClass = oClasses.sSortable;
2110
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
2111
+ }
2112
+ }
2113
+
2114
+
2115
+ /**
2116
+ * Adjust the table column widths for new data. Note: you would probably want to
2117
+ * do a redraw after calling this function!
2118
+ * @param {object} settings dataTables settings object
2119
+ * @memberof DataTable#oApi
2120
+ */
2121
+ function _fnAdjustColumnSizing ( settings )
2122
+ {
2123
+ /* Not interested in doing column width calculation if auto-width is disabled */
2124
+ if ( settings.oFeatures.bAutoWidth !== false )
2125
+ {
2126
+ var columns = settings.aoColumns;
2127
+
2128
+ _fnCalculateColumnWidths( settings );
2129
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
2130
+ {
2131
+ columns[i].nTh.style.width = columns[i].sWidth;
2132
+ }
2133
+ }
2134
+
2135
+ var scroll = settings.oScroll;
2136
+ if ( scroll.sY !== '' || scroll.sX !== '')
2137
+ {
2138
+ _fnScrollDraw( settings );
2139
+ }
2140
+
2141
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
2142
+ }
2143
+
2144
+
2145
+ /**
2146
+ * Covert the index of a visible column to the index in the data array (take account
2147
+ * of hidden columns)
2148
+ * @param {object} oSettings dataTables settings object
2149
+ * @param {int} iMatch Visible column index to lookup
2150
+ * @returns {int} i the data index
2151
+ * @memberof DataTable#oApi
2152
+ */
2153
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
2154
+ {
2155
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2156
+
2157
+ return typeof aiVis[iMatch] === 'number' ?
2158
+ aiVis[iMatch] :
2159
+ null;
2160
+ }
2161
+
2162
+
2163
+ /**
2164
+ * Covert the index of an index in the data array and convert it to the visible
2165
+ * column index (take account of hidden columns)
2166
+ * @param {int} iMatch Column index to lookup
2167
+ * @param {object} oSettings dataTables settings object
2168
+ * @returns {int} i the data index
2169
+ * @memberof DataTable#oApi
2170
+ */
2171
+ function _fnColumnIndexToVisible( oSettings, iMatch )
2172
+ {
2173
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
2174
+ var iPos = $.inArray( iMatch, aiVis );
2175
+
2176
+ return iPos !== -1 ? iPos : null;
2177
+ }
2178
+
2179
+
2180
+ /**
2181
+ * Get the number of visible columns
2182
+ * @param {object} oSettings dataTables settings object
2183
+ * @returns {int} i the number of visible columns
2184
+ * @memberof DataTable#oApi
2185
+ */
2186
+ function _fnVisbleColumns( oSettings )
2187
+ {
2188
+ var vis = 0;
2189
+
2190
+ // No reduce in IE8, use a loop for now
2191
+ $.each( oSettings.aoColumns, function ( i, col ) {
2192
+ if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
2193
+ vis++;
2194
+ }
2195
+ } );
2196
+
2197
+ return vis;
2198
+ }
2199
+
2200
+
2201
+ /**
2202
+ * Get an array of column indexes that match a given property
2203
+ * @param {object} oSettings dataTables settings object
2204
+ * @param {string} sParam Parameter in aoColumns to look for - typically
2205
+ * bVisible or bSearchable
2206
+ * @returns {array} Array of indexes with matched properties
2207
+ * @memberof DataTable#oApi
2208
+ */
2209
+ function _fnGetColumns( oSettings, sParam )
2210
+ {
2211
+ var a = [];
2212
+
2213
+ $.map( oSettings.aoColumns, function(val, i) {
2214
+ if ( val[sParam] ) {
2215
+ a.push( i );
2216
+ }
2217
+ } );
2218
+
2219
+ return a;
2220
+ }
2221
+
2222
+
2223
+ /**
2224
+ * Calculate the 'type' of a column
2225
+ * @param {object} settings dataTables settings object
2226
+ * @memberof DataTable#oApi
2227
+ */
2228
+ function _fnColumnTypes ( settings )
2229
+ {
2230
+ var columns = settings.aoColumns;
2231
+ var data = settings.aoData;
2232
+ var types = DataTable.ext.type.detect;
2233
+ var i, ien, j, jen, k, ken;
2234
+ var col, cell, detectedType, cache;
2235
+
2236
+ // For each column, spin over the
2237
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
2238
+ col = columns[i];
2239
+ cache = [];
2240
+
2241
+ if ( ! col.sType && col._sManualType ) {
2242
+ col.sType = col._sManualType;
2243
+ }
2244
+ else if ( ! col.sType ) {
2245
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
2246
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
2247
+ // Use a cache array so we only need to get the type data
2248
+ // from the formatter once (when using multiple detectors)
2249
+ if ( cache[k] === undefined ) {
2250
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
2251
+ }
2252
+
2253
+ detectedType = types[j]( cache[k], settings );
2254
+
2255
+ // If null, then this type can't apply to this column, so
2256
+ // rather than testing all cells, break out. There is an
2257
+ // exception for the last type which is `html`. We need to
2258
+ // scan all rows since it is possible to mix string and HTML
2259
+ // types
2260
+ if ( ! detectedType && j !== types.length-1 ) {
2261
+ break;
2262
+ }
2263
+
2264
+ // Only a single match is needed for html type since it is
2265
+ // bottom of the pile and very similar to string
2266
+ if ( detectedType === 'html' ) {
2267
+ break;
2268
+ }
2269
+ }
2270
+
2271
+ // Type is valid for all data points in the column - use this
2272
+ // type
2273
+ if ( detectedType ) {
2274
+ col.sType = detectedType;
2275
+ break;
2276
+ }
2277
+ }
2278
+
2279
+ // Fall back - if no type was detected, always use string
2280
+ if ( ! col.sType ) {
2281
+ col.sType = 'string';
2282
+ }
2283
+ }
2284
+ }
2285
+ }
2286
+
2287
+
2288
+ /**
2289
+ * Take the column definitions and static columns arrays and calculate how
2290
+ * they relate to column indexes. The callback function will then apply the
2291
+ * definition found for a column to a suitable configuration object.
2292
+ * @param {object} oSettings dataTables settings object
2293
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
2294
+ * @param {array} aoCols The aoColumns array that defines columns individually
2295
+ * @param {function} fn Callback function - takes two parameters, the calculated
2296
+ * column index and the definition for that column.
2297
+ * @memberof DataTable#oApi
2298
+ */
2299
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
2300
+ {
2301
+ var i, iLen, j, jLen, k, kLen, def;
2302
+ var columns = oSettings.aoColumns;
2303
+
2304
+ // Column definitions with aTargets
2305
+ if ( aoColDefs )
2306
+ {
2307
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
2308
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
2309
+ {
2310
+ def = aoColDefs[i];
2311
+
2312
+ /* Each definition can target multiple columns, as it is an array */
2313
+ var aTargets = def.targets !== undefined ?
2314
+ def.targets :
2315
+ def.aTargets;
2316
+
2317
+ if ( ! $.isArray( aTargets ) )
2318
+ {
2319
+ aTargets = [ aTargets ];
2320
+ }
2321
+
2322
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
2323
+ {
2324
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
2325
+ {
2326
+ /* Add columns that we don't yet know about */
2327
+ while( columns.length <= aTargets[j] )
2328
+ {
2329
+ _fnAddColumn( oSettings );
2330
+ }
2331
+
2332
+ /* Integer, basic index */
2333
+ fn( aTargets[j], def );
2334
+ }
2335
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
2336
+ {
2337
+ /* Negative integer, right to left column counting */
2338
+ fn( columns.length+aTargets[j], def );
2339
+ }
2340
+ else if ( typeof aTargets[j] === 'string' )
2341
+ {
2342
+ /* Class name matching on TH element */
2343
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
2344
+ {
2345
+ if ( aTargets[j] == "_all" ||
2346
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
2347
+ {
2348
+ fn( k, def );
2349
+ }
2350
+ }
2351
+ }
2352
+ }
2353
+ }
2354
+ }
2355
+
2356
+ // Statically defined columns array
2357
+ if ( aoCols )
2358
+ {
2359
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
2360
+ {
2361
+ fn( i, aoCols[i] );
2362
+ }
2363
+ }
2364
+ }
2365
+
2366
+ /**
2367
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
2368
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
2369
+ * DOM source.
2370
+ * @param {object} oSettings dataTables settings object
2371
+ * @param {array} aData data array to be added
2372
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
2373
+ * DataTables will create a row automatically
2374
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
2375
+ * if nTr is.
2376
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
2377
+ * @memberof DataTable#oApi
2378
+ */
2379
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
2380
+ {
2381
+ /* Create the object for storing information about this new row */
2382
+ var iRow = oSettings.aoData.length;
2383
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
2384
+ src: nTr ? 'dom' : 'data',
2385
+ idx: iRow
2386
+ } );
2387
+
2388
+ oData._aData = aDataIn;
2389
+ oSettings.aoData.push( oData );
2390
+
2391
+ /* Create the cells */
2392
+ var nTd, sThisType;
2393
+ var columns = oSettings.aoColumns;
2394
+
2395
+ // Invalidate the column types as the new data needs to be revalidated
2396
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
2397
+ {
2398
+ columns[i].sType = null;
2399
+ }
2400
+
2401
+ /* Add to the display array */
2402
+ oSettings.aiDisplayMaster.push( iRow );
2403
+
2404
+ var id = oSettings.rowIdFn( aDataIn );
2405
+ if ( id !== undefined ) {
2406
+ oSettings.aIds[ id ] = oData;
2407
+ }
2408
+
2409
+ /* Create the DOM information, or register it if already present */
2410
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
2411
+ {
2412
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
2413
+ }
2414
+
2415
+ return iRow;
2416
+ }
2417
+
2418
+
2419
+ /**
2420
+ * Add one or more TR elements to the table. Generally we'd expect to
2421
+ * use this for reading data from a DOM sourced table, but it could be
2422
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
2423
+ * it is not cloned).
2424
+ * @param {object} settings dataTables settings object
2425
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
2426
+ * @returns {array} Array of indexes for the added rows
2427
+ * @memberof DataTable#oApi
2428
+ */
2429
+ function _fnAddTr( settings, trs )
2430
+ {
2431
+ var row;
2432
+
2433
+ // Allow an individual node to be passed in
2434
+ if ( ! (trs instanceof $) ) {
2435
+ trs = $(trs);
2436
+ }
2437
+
2438
+ return trs.map( function (i, el) {
2439
+ row = _fnGetRowElements( settings, el );
2440
+ return _fnAddData( settings, row.data, el, row.cells );
2441
+ } );
2442
+ }
2443
+
2444
+
2445
+ /**
2446
+ * Take a TR element and convert it to an index in aoData
2447
+ * @param {object} oSettings dataTables settings object
2448
+ * @param {node} n the TR element to find
2449
+ * @returns {int} index if the node is found, null if not
2450
+ * @memberof DataTable#oApi
2451
+ */
2452
+ function _fnNodeToDataIndex( oSettings, n )
2453
+ {
2454
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
2455
+ }
2456
+
2457
+
2458
+ /**
2459
+ * Take a TD element and convert it into a column data index (not the visible index)
2460
+ * @param {object} oSettings dataTables settings object
2461
+ * @param {int} iRow The row number the TD/TH can be found in
2462
+ * @param {node} n The TD/TH element to find
2463
+ * @returns {int} index if the node is found, -1 if not
2464
+ * @memberof DataTable#oApi
2465
+ */
2466
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
2467
+ {
2468
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
2469
+ }
2470
+
2471
+
2472
+ /**
2473
+ * Get the data for a given cell from the internal cache, taking into account data mapping
2474
+ * @param {object} settings dataTables settings object
2475
+ * @param {int} rowIdx aoData row id
2476
+ * @param {int} colIdx Column index
2477
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
2478
+ * @returns {*} Cell data
2479
+ * @memberof DataTable#oApi
2480
+ */
2481
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
2482
+ {
2483
+ var draw = settings.iDraw;
2484
+ var col = settings.aoColumns[colIdx];
2485
+ var rowData = settings.aoData[rowIdx]._aData;
2486
+ var defaultContent = col.sDefaultContent;
2487
+ var cellData = col.fnGetData( rowData, type, {
2488
+ settings: settings,
2489
+ row: rowIdx,
2490
+ col: colIdx
2491
+ } );
2492
+
2493
+ if ( cellData === undefined ) {
2494
+ if ( settings.iDrawError != draw && defaultContent === null ) {
2495
+ _fnLog( settings, 0, "Requested unknown parameter "+
2496
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
2497
+ " for row "+rowIdx+", column "+colIdx, 4 );
2498
+ settings.iDrawError = draw;
2499
+ }
2500
+ return defaultContent;
2501
+ }
2502
+
2503
+ // When the data source is null and a specific data type is requested (i.e.
2504
+ // not the original data), we can use default column data
2505
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
2506
+ cellData = defaultContent;
2507
+ }
2508
+ else if ( typeof cellData === 'function' ) {
2509
+ // If the data source is a function, then we run it and use the return,
2510
+ // executing in the scope of the data object (for instances)
2511
+ return cellData.call( rowData );
2512
+ }
2513
+
2514
+ if ( cellData === null && type == 'display' ) {
2515
+ return '';
2516
+ }
2517
+ return cellData;
2518
+ }
2519
+
2520
+
2521
+ /**
2522
+ * Set the value for a specific cell, into the internal data cache
2523
+ * @param {object} settings dataTables settings object
2524
+ * @param {int} rowIdx aoData row id
2525
+ * @param {int} colIdx Column index
2526
+ * @param {*} val Value to set
2527
+ * @memberof DataTable#oApi
2528
+ */
2529
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
2530
+ {
2531
+ var col = settings.aoColumns[colIdx];
2532
+ var rowData = settings.aoData[rowIdx]._aData;
2533
+
2534
+ col.fnSetData( rowData, val, {
2535
+ settings: settings,
2536
+ row: rowIdx,
2537
+ col: colIdx
2538
+ } );
2539
+ }
2540
+
2541
+
2542
+ // Private variable that is used to match action syntax in the data property object
2543
+ var __reArray = /\[.*?\]$/;
2544
+ var __reFn = /\(\)$/;
2545
+
2546
+ /**
2547
+ * Split string on periods, taking into account escaped periods
2548
+ * @param {string} str String to split
2549
+ * @return {array} Split string
2550
+ */
2551
+ function _fnSplitObjNotation( str )
2552
+ {
2553
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
2554
+ return s.replace(/\\\./g, '.');
2555
+ } );
2556
+ }
2557
+
2558
+
2559
+ /**
2560
+ * Return a function that can be used to get data from a source object, taking
2561
+ * into account the ability to use nested objects as a source
2562
+ * @param {string|int|function} mSource The data source for the object
2563
+ * @returns {function} Data get function
2564
+ * @memberof DataTable#oApi
2565
+ */
2566
+ function _fnGetObjectDataFn( mSource )
2567
+ {
2568
+ if ( $.isPlainObject( mSource ) )
2569
+ {
2570
+ /* Build an object of get functions, and wrap them in a single call */
2571
+ var o = {};
2572
+ $.each( mSource, function (key, val) {
2573
+ if ( val ) {
2574
+ o[key] = _fnGetObjectDataFn( val );
2575
+ }
2576
+ } );
2577
+
2578
+ return function (data, type, row, meta) {
2579
+ var t = o[type] || o._;
2580
+ return t !== undefined ?
2581
+ t(data, type, row, meta) :
2582
+ data;
2583
+ };
2584
+ }
2585
+ else if ( mSource === null )
2586
+ {
2587
+ /* Give an empty string for rendering / sorting etc */
2588
+ return function (data) { // type, row and meta also passed, but not used
2589
+ return data;
2590
+ };
2591
+ }
2592
+ else if ( typeof mSource === 'function' )
2593
+ {
2594
+ return function (data, type, row, meta) {
2595
+ return mSource( data, type, row, meta );
2596
+ };
2597
+ }
2598
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2599
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2600
+ {
2601
+ /* If there is a . in the source string then the data source is in a
2602
+ * nested object so we loop over the data for each level to get the next
2603
+ * level down. On each loop we test for undefined, and if found immediately
2604
+ * return. This allows entire objects to be missing and sDefaultContent to
2605
+ * be used if defined, rather than throwing an error
2606
+ */
2607
+ var fetchData = function (data, type, src) {
2608
+ var arrayNotation, funcNotation, out, innerSrc;
2609
+
2610
+ if ( src !== "" )
2611
+ {
2612
+ var a = _fnSplitObjNotation( src );
2613
+
2614
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2615
+ {
2616
+ // Check if we are dealing with special notation
2617
+ arrayNotation = a[i].match(__reArray);
2618
+ funcNotation = a[i].match(__reFn);
2619
+
2620
+ if ( arrayNotation )
2621
+ {
2622
+ // Array notation
2623
+ a[i] = a[i].replace(__reArray, '');
2624
+
2625
+ // Condition allows simply [] to be passed in
2626
+ if ( a[i] !== "" ) {
2627
+ data = data[ a[i] ];
2628
+ }
2629
+ out = [];
2630
+
2631
+ // Get the remainder of the nested object to get
2632
+ a.splice( 0, i+1 );
2633
+ innerSrc = a.join('.');
2634
+
2635
+ // Traverse each entry in the array getting the properties requested
2636
+ if ( $.isArray( data ) ) {
2637
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
2638
+ out.push( fetchData( data[j], type, innerSrc ) );
2639
+ }
2640
+ }
2641
+
2642
+ // If a string is given in between the array notation indicators, that
2643
+ // is used to join the strings together, otherwise an array is returned
2644
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
2645
+ data = (join==="") ? out : out.join(join);
2646
+
2647
+ // The inner call to fetchData has already traversed through the remainder
2648
+ // of the source requested, so we exit from the loop
2649
+ break;
2650
+ }
2651
+ else if ( funcNotation )
2652
+ {
2653
+ // Function call
2654
+ a[i] = a[i].replace(__reFn, '');
2655
+ data = data[ a[i] ]();
2656
+ continue;
2657
+ }
2658
+
2659
+ if ( data === null || data[ a[i] ] === undefined )
2660
+ {
2661
+ return undefined;
2662
+ }
2663
+ data = data[ a[i] ];
2664
+ }
2665
+ }
2666
+
2667
+ return data;
2668
+ };
2669
+
2670
+ return function (data, type) { // row and meta also passed, but not used
2671
+ return fetchData( data, type, mSource );
2672
+ };
2673
+ }
2674
+ else
2675
+ {
2676
+ /* Array or flat object mapping */
2677
+ return function (data, type) { // row and meta also passed, but not used
2678
+ return data[mSource];
2679
+ };
2680
+ }
2681
+ }
2682
+
2683
+
2684
+ /**
2685
+ * Return a function that can be used to set data from a source object, taking
2686
+ * into account the ability to use nested objects as a source
2687
+ * @param {string|int|function} mSource The data source for the object
2688
+ * @returns {function} Data set function
2689
+ * @memberof DataTable#oApi
2690
+ */
2691
+ function _fnSetObjectDataFn( mSource )
2692
+ {
2693
+ if ( $.isPlainObject( mSource ) )
2694
+ {
2695
+ /* Unlike get, only the underscore (global) option is used for for
2696
+ * setting data since we don't know the type here. This is why an object
2697
+ * option is not documented for `mData` (which is read/write), but it is
2698
+ * for `mRender` which is read only.
2699
+ */
2700
+ return _fnSetObjectDataFn( mSource._ );
2701
+ }
2702
+ else if ( mSource === null )
2703
+ {
2704
+ /* Nothing to do when the data source is null */
2705
+ return function () {};
2706
+ }
2707
+ else if ( typeof mSource === 'function' )
2708
+ {
2709
+ return function (data, val, meta) {
2710
+ mSource( data, 'set', val, meta );
2711
+ };
2712
+ }
2713
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
2714
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
2715
+ {
2716
+ /* Like the get, we need to get data from a nested object */
2717
+ var setData = function (data, val, src) {
2718
+ var a = _fnSplitObjNotation( src ), b;
2719
+ var aLast = a[a.length-1];
2720
+ var arrayNotation, funcNotation, o, innerSrc;
2721
+
2722
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
2723
+ {
2724
+ // Check if we are dealing with an array notation request
2725
+ arrayNotation = a[i].match(__reArray);
2726
+ funcNotation = a[i].match(__reFn);
2727
+
2728
+ if ( arrayNotation )
2729
+ {
2730
+ a[i] = a[i].replace(__reArray, '');
2731
+ data[ a[i] ] = [];
2732
+
2733
+ // Get the remainder of the nested object to set so we can recurse
2734
+ b = a.slice();
2735
+ b.splice( 0, i+1 );
2736
+ innerSrc = b.join('.');
2737
+
2738
+ // Traverse each entry in the array setting the properties requested
2739
+ if ( $.isArray( val ) )
2740
+ {
2741
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
2742
+ {
2743
+ o = {};
2744
+ setData( o, val[j], innerSrc );
2745
+ data[ a[i] ].push( o );
2746
+ }
2747
+ }
2748
+ else
2749
+ {
2750
+ // We've been asked to save data to an array, but it
2751
+ // isn't array data to be saved. Best that can be done
2752
+ // is to just save the value.
2753
+ data[ a[i] ] = val;
2754
+ }
2755
+
2756
+ // The inner call to setData has already traversed through the remainder
2757
+ // of the source and has set the data, thus we can exit here
2758
+ return;
2759
+ }
2760
+ else if ( funcNotation )
2761
+ {
2762
+ // Function call
2763
+ a[i] = a[i].replace(__reFn, '');
2764
+ data = data[ a[i] ]( val );
2765
+ }
2766
+
2767
+ // If the nested object doesn't currently exist - since we are
2768
+ // trying to set the value - create it
2769
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
2770
+ {
2771
+ data[ a[i] ] = {};
2772
+ }
2773
+ data = data[ a[i] ];
2774
+ }
2775
+
2776
+ // Last item in the input - i.e, the actual set
2777
+ if ( aLast.match(__reFn ) )
2778
+ {
2779
+ // Function call
2780
+ data = data[ aLast.replace(__reFn, '') ]( val );
2781
+ }
2782
+ else
2783
+ {
2784
+ // If array notation is used, we just want to strip it and use the property name
2785
+ // and assign the value. If it isn't used, then we get the result we want anyway
2786
+ data[ aLast.replace(__reArray, '') ] = val;
2787
+ }
2788
+ };
2789
+
2790
+ return function (data, val) { // meta is also passed in, but not used
2791
+ return setData( data, val, mSource );
2792
+ };
2793
+ }
2794
+ else
2795
+ {
2796
+ /* Array or flat object mapping */
2797
+ return function (data, val) { // meta is also passed in, but not used
2798
+ data[mSource] = val;
2799
+ };
2800
+ }
2801
+ }
2802
+
2803
+
2804
+ /**
2805
+ * Return an array with the full table data
2806
+ * @param {object} oSettings dataTables settings object
2807
+ * @returns array {array} aData Master data array
2808
+ * @memberof DataTable#oApi
2809
+ */
2810
+ function _fnGetDataMaster ( settings )
2811
+ {
2812
+ return _pluck( settings.aoData, '_aData' );
2813
+ }
2814
+
2815
+
2816
+ /**
2817
+ * Nuke the table
2818
+ * @param {object} oSettings dataTables settings object
2819
+ * @memberof DataTable#oApi
2820
+ */
2821
+ function _fnClearTable( settings )
2822
+ {
2823
+ settings.aoData.length = 0;
2824
+ settings.aiDisplayMaster.length = 0;
2825
+ settings.aiDisplay.length = 0;
2826
+ settings.aIds = {};
2827
+ }
2828
+
2829
+
2830
+ /**
2831
+ * Take an array of integers (index array) and remove a target integer (value - not
2832
+ * the key!)
2833
+ * @param {array} a Index array to target
2834
+ * @param {int} iTarget value to find
2835
+ * @memberof DataTable#oApi
2836
+ */
2837
+ function _fnDeleteIndex( a, iTarget, splice )
2838
+ {
2839
+ var iTargetIndex = -1;
2840
+
2841
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2842
+ {
2843
+ if ( a[i] == iTarget )
2844
+ {
2845
+ iTargetIndex = i;
2846
+ }
2847
+ else if ( a[i] > iTarget )
2848
+ {
2849
+ a[i]--;
2850
+ }
2851
+ }
2852
+
2853
+ if ( iTargetIndex != -1 && splice === undefined )
2854
+ {
2855
+ a.splice( iTargetIndex, 1 );
2856
+ }
2857
+ }
2858
+
2859
+
2860
+ /**
2861
+ * Mark cached data as invalid such that a re-read of the data will occur when
2862
+ * the cached data is next requested. Also update from the data source object.
2863
+ *
2864
+ * @param {object} settings DataTables settings object
2865
+ * @param {int} rowIdx Row index to invalidate
2866
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
2867
+ * or 'data'
2868
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
2869
+ * row will be invalidated
2870
+ * @memberof DataTable#oApi
2871
+ *
2872
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
2873
+ * the sort and filter methods can subscribe to it. That will required
2874
+ * initialisation options for sorting, which is why it is not already baked in
2875
+ */
2876
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
2877
+ {
2878
+ var row = settings.aoData[ rowIdx ];
2879
+ var i, ien;
2880
+ var cellWrite = function ( cell, col ) {
2881
+ // This is very frustrating, but in IE if you just write directly
2882
+ // to innerHTML, and elements that are overwritten are GC'ed,
2883
+ // even if there is a reference to them elsewhere
2884
+ while ( cell.childNodes.length ) {
2885
+ cell.removeChild( cell.firstChild );
2886
+ }
2887
+
2888
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
2889
+ };
2890
+
2891
+ // Are we reading last data from DOM or the data object?
2892
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
2893
+ // Read the data from the DOM
2894
+ row._aData = _fnGetRowElements(
2895
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
2896
+ )
2897
+ .data;
2898
+ }
2899
+ else {
2900
+ // Reading from data object, update the DOM
2901
+ var cells = row.anCells;
2902
+
2903
+ if ( cells ) {
2904
+ if ( colIdx !== undefined ) {
2905
+ cellWrite( cells[colIdx], colIdx );
2906
+ }
2907
+ else {
2908
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
2909
+ cellWrite( cells[i], i );
2910
+ }
2911
+ }
2912
+ }
2913
+ }
2914
+
2915
+ // For both row and cell invalidation, the cached data for sorting and
2916
+ // filtering is nulled out
2917
+ row._aSortData = null;
2918
+ row._aFilterData = null;
2919
+
2920
+ // Invalidate the type for a specific column (if given) or all columns since
2921
+ // the data might have changed
2922
+ var cols = settings.aoColumns;
2923
+ if ( colIdx !== undefined ) {
2924
+ cols[ colIdx ].sType = null;
2925
+ }
2926
+ else {
2927
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
2928
+ cols[i].sType = null;
2929
+ }
2930
+
2931
+ // Update DataTables special `DT_*` attributes for the row
2932
+ _fnRowAttributes( settings, row );
2933
+ }
2934
+ }
2935
+
2936
+
2937
+ /**
2938
+ * Build a data source object from an HTML row, reading the contents of the
2939
+ * cells that are in the row.
2940
+ *
2941
+ * @param {object} settings DataTables settings object
2942
+ * @param {node|object} TR element from which to read data or existing row
2943
+ * object from which to re-read the data from the cells
2944
+ * @param {int} [colIdx] Optional column index
2945
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
2946
+ * parameter should also be given and will be used to write the data into.
2947
+ * Only the column in question will be written
2948
+ * @returns {object} Object with two parameters: `data` the data read, in
2949
+ * document order, and `cells` and array of nodes (they can be useful to the
2950
+ * caller, so rather than needing a second traversal to get them, just return
2951
+ * them from here).
2952
+ * @memberof DataTable#oApi
2953
+ */
2954
+ function _fnGetRowElements( settings, row, colIdx, d )
2955
+ {
2956
+ var
2957
+ tds = [],
2958
+ td = row.firstChild,
2959
+ name, col, o, i=0, contents,
2960
+ columns = settings.aoColumns,
2961
+ objectRead = settings._rowReadObject;
2962
+
2963
+ // Allow the data object to be passed in, or construct
2964
+ d = d !== undefined ?
2965
+ d :
2966
+ objectRead ?
2967
+ {} :
2968
+ [];
2969
+
2970
+ var attr = function ( str, td ) {
2971
+ if ( typeof str === 'string' ) {
2972
+ var idx = str.indexOf('@');
2973
+
2974
+ if ( idx !== -1 ) {
2975
+ var attr = str.substring( idx+1 );
2976
+ var setter = _fnSetObjectDataFn( str );
2977
+ setter( d, td.getAttribute( attr ) );
2978
+ }
2979
+ }
2980
+ };
2981
+
2982
+ // Read data from a cell and store into the data object
2983
+ var cellProcess = function ( cell ) {
2984
+ if ( colIdx === undefined || colIdx === i ) {
2985
+ col = columns[i];
2986
+ contents = $.trim(cell.innerHTML);
2987
+
2988
+ if ( col && col._bAttrSrc ) {
2989
+ var setter = _fnSetObjectDataFn( col.mData._ );
2990
+ setter( d, contents );
2991
+
2992
+ attr( col.mData.sort, cell );
2993
+ attr( col.mData.type, cell );
2994
+ attr( col.mData.filter, cell );
2995
+ }
2996
+ else {
2997
+ // Depending on the `data` option for the columns the data can
2998
+ // be read to either an object or an array.
2999
+ if ( objectRead ) {
3000
+ if ( ! col._setter ) {
3001
+ // Cache the setter function
3002
+ col._setter = _fnSetObjectDataFn( col.mData );
3003
+ }
3004
+ col._setter( d, contents );
3005
+ }
3006
+ else {
3007
+ d[i] = contents;
3008
+ }
3009
+ }
3010
+ }
3011
+
3012
+ i++;
3013
+ };
3014
+
3015
+ if ( td ) {
3016
+ // `tr` element was passed in
3017
+ while ( td ) {
3018
+ name = td.nodeName.toUpperCase();
3019
+
3020
+ if ( name == "TD" || name == "TH" ) {
3021
+ cellProcess( td );
3022
+ tds.push( td );
3023
+ }
3024
+
3025
+ td = td.nextSibling;
3026
+ }
3027
+ }
3028
+ else {
3029
+ // Existing row object passed in
3030
+ tds = row.anCells;
3031
+
3032
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
3033
+ cellProcess( tds[j] );
3034
+ }
3035
+ }
3036
+
3037
+ // Read the ID from the DOM if present
3038
+ var rowNode = row.firstChild ? row : row.nTr;
3039
+
3040
+ if ( rowNode ) {
3041
+ var id = rowNode.getAttribute( 'id' );
3042
+
3043
+ if ( id ) {
3044
+ _fnSetObjectDataFn( settings.rowId )( d, id );
3045
+ }
3046
+ }
3047
+
3048
+ return {
3049
+ data: d,
3050
+ cells: tds
3051
+ };
3052
+ }
3053
+ /**
3054
+ * Create a new TR element (and it's TD children) for a row
3055
+ * @param {object} oSettings dataTables settings object
3056
+ * @param {int} iRow Row to consider
3057
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
3058
+ * DataTables will create a row automatically
3059
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
3060
+ * if nTr is.
3061
+ * @memberof DataTable#oApi
3062
+ */
3063
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
3064
+ {
3065
+ var
3066
+ row = oSettings.aoData[iRow],
3067
+ rowData = row._aData,
3068
+ cells = [],
3069
+ nTr, nTd, oCol,
3070
+ i, iLen;
3071
+
3072
+ if ( row.nTr === null )
3073
+ {
3074
+ nTr = nTrIn || document.createElement('tr');
3075
+
3076
+ row.nTr = nTr;
3077
+ row.anCells = cells;
3078
+
3079
+ /* Use a private property on the node to allow reserve mapping from the node
3080
+ * to the aoData array for fast look up
3081
+ */
3082
+ nTr._DT_RowIndex = iRow;
3083
+
3084
+ /* Special parameters can be given by the data source to be used on the row */
3085
+ _fnRowAttributes( oSettings, row );
3086
+
3087
+ /* Process each column */
3088
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3089
+ {
3090
+ oCol = oSettings.aoColumns[i];
3091
+
3092
+ nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
3093
+ nTd._DT_CellIndex = {
3094
+ row: iRow,
3095
+ column: i
3096
+ };
3097
+
3098
+ cells.push( nTd );
3099
+
3100
+ // Need to create the HTML if new, or if a rendering function is defined
3101
+ if ( (!nTrIn || oCol.mRender || oCol.mData !== i) &&
3102
+ (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
3103
+ ) {
3104
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
3105
+ }
3106
+
3107
+ /* Add user defined class */
3108
+ if ( oCol.sClass )
3109
+ {
3110
+ nTd.className += ' '+oCol.sClass;
3111
+ }
3112
+
3113
+ // Visibility - add or remove as required
3114
+ if ( oCol.bVisible && ! nTrIn )
3115
+ {
3116
+ nTr.appendChild( nTd );
3117
+ }
3118
+ else if ( ! oCol.bVisible && nTrIn )
3119
+ {
3120
+ nTd.parentNode.removeChild( nTd );
3121
+ }
3122
+
3123
+ if ( oCol.fnCreatedCell )
3124
+ {
3125
+ oCol.fnCreatedCell.call( oSettings.oInstance,
3126
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
3127
+ );
3128
+ }
3129
+ }
3130
+
3131
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
3132
+ }
3133
+
3134
+ // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
3135
+ // and deployed
3136
+ row.nTr.setAttribute( 'role', 'row' );
3137
+ }
3138
+
3139
+
3140
+ /**
3141
+ * Add attributes to a row based on the special `DT_*` parameters in a data
3142
+ * source object.
3143
+ * @param {object} settings DataTables settings object
3144
+ * @param {object} DataTables row object for the row to be modified
3145
+ * @memberof DataTable#oApi
3146
+ */
3147
+ function _fnRowAttributes( settings, row )
3148
+ {
3149
+ var tr = row.nTr;
3150
+ var data = row._aData;
3151
+
3152
+ if ( tr ) {
3153
+ var id = settings.rowIdFn( data );
3154
+
3155
+ if ( id ) {
3156
+ tr.id = id;
3157
+ }
3158
+
3159
+ if ( data.DT_RowClass ) {
3160
+ // Remove any classes added by DT_RowClass before
3161
+ var a = data.DT_RowClass.split(' ');
3162
+ row.__rowc = row.__rowc ?
3163
+ _unique( row.__rowc.concat( a ) ) :
3164
+ a;
3165
+
3166
+ $(tr)
3167
+ .removeClass( row.__rowc.join(' ') )
3168
+ .addClass( data.DT_RowClass );
3169
+ }
3170
+
3171
+ if ( data.DT_RowAttr ) {
3172
+ $(tr).attr( data.DT_RowAttr );
3173
+ }
3174
+
3175
+ if ( data.DT_RowData ) {
3176
+ $(tr).data( data.DT_RowData );
3177
+ }
3178
+ }
3179
+ }
3180
+
3181
+
3182
+ /**
3183
+ * Create the HTML header for the table
3184
+ * @param {object} oSettings dataTables settings object
3185
+ * @memberof DataTable#oApi
3186
+ */
3187
+ function _fnBuildHead( oSettings )
3188
+ {
3189
+ var i, ien, cell, row, column;
3190
+ var thead = oSettings.nTHead;
3191
+ var tfoot = oSettings.nTFoot;
3192
+ var createHeader = $('th, td', thead).length === 0;
3193
+ var classes = oSettings.oClasses;
3194
+ var columns = oSettings.aoColumns;
3195
+
3196
+ if ( createHeader ) {
3197
+ row = $('<tr/>').appendTo( thead );
3198
+ }
3199
+
3200
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
3201
+ column = columns[i];
3202
+ cell = $( column.nTh ).addClass( column.sClass );
3203
+
3204
+ if ( createHeader ) {
3205
+ cell.appendTo( row );
3206
+ }
3207
+
3208
+ // 1.11 move into sorting
3209
+ if ( oSettings.oFeatures.bSort ) {
3210
+ cell.addClass( column.sSortingClass );
3211
+
3212
+ if ( column.bSortable !== false ) {
3213
+ cell
3214
+ .attr( 'tabindex', oSettings.iTabIndex )
3215
+ .attr( 'aria-controls', oSettings.sTableId );
3216
+
3217
+ _fnSortAttachListener( oSettings, column.nTh, i );
3218
+ }
3219
+ }
3220
+
3221
+ if ( column.sTitle != cell[0].innerHTML ) {
3222
+ cell.html( column.sTitle );
3223
+ }
3224
+
3225
+ _fnRenderer( oSettings, 'header' )(
3226
+ oSettings, cell, column, classes
3227
+ );
3228
+ }
3229
+
3230
+ if ( createHeader ) {
3231
+ _fnDetectHeader( oSettings.aoHeader, thead );
3232
+ }
3233
+
3234
+ /* ARIA role for the rows */
3235
+ $(thead).find('>tr').attr('role', 'row');
3236
+
3237
+ /* Deal with the footer - add classes if required */
3238
+ $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
3239
+ $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
3240
+
3241
+ // Cache the footer cells. Note that we only take the cells from the first
3242
+ // row in the footer. If there is more than one row the user wants to
3243
+ // interact with, they need to use the table().foot() method. Note also this
3244
+ // allows cells to be used for multiple columns using colspan
3245
+ if ( tfoot !== null ) {
3246
+ var cells = oSettings.aoFooter[0];
3247
+
3248
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
3249
+ column = columns[i];
3250
+ column.nTf = cells[i].cell;
3251
+
3252
+ if ( column.sClass ) {
3253
+ $(column.nTf).addClass( column.sClass );
3254
+ }
3255
+ }
3256
+ }
3257
+ }
3258
+
3259
+
3260
+ /**
3261
+ * Draw the header (or footer) element based on the column visibility states. The
3262
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
3263
+ * the instantaneous column visibility, to construct the new layout. The grid is
3264
+ * traversed over cell at a time in a rows x columns grid fashion, although each
3265
+ * cell insert can cover multiple elements in the grid - which is tracks using the
3266
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
3267
+ * already a cell in that position.
3268
+ * @param {object} oSettings dataTables settings object
3269
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
3270
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
3271
+ * @memberof DataTable#oApi
3272
+ */
3273
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
3274
+ {
3275
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
3276
+ var aoLocal = [];
3277
+ var aApplied = [];
3278
+ var iColumns = oSettings.aoColumns.length;
3279
+ var iRowspan, iColspan;
3280
+
3281
+ if ( ! aoSource )
3282
+ {
3283
+ return;
3284
+ }
3285
+
3286
+ if ( bIncludeHidden === undefined )
3287
+ {
3288
+ bIncludeHidden = false;
3289
+ }
3290
+
3291
+ /* Make a copy of the master layout array, but without the visible columns in it */
3292
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
3293
+ {
3294
+ aoLocal[i] = aoSource[i].slice();
3295
+ aoLocal[i].nTr = aoSource[i].nTr;
3296
+
3297
+ /* Remove any columns which are currently hidden */
3298
+ for ( j=iColumns-1 ; j>=0 ; j-- )
3299
+ {
3300
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
3301
+ {
3302
+ aoLocal[i].splice( j, 1 );
3303
+ }
3304
+ }
3305
+
3306
+ /* Prep the applied array - it needs an element for each row */
3307
+ aApplied.push( [] );
3308
+ }
3309
+
3310
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
3311
+ {
3312
+ nLocalTr = aoLocal[i].nTr;
3313
+
3314
+ /* All cells are going to be replaced, so empty out the row */
3315
+ if ( nLocalTr )
3316
+ {
3317
+ while( (n = nLocalTr.firstChild) )
3318
+ {
3319
+ nLocalTr.removeChild( n );
3320
+ }
3321
+ }
3322
+
3323
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
3324
+ {
3325
+ iRowspan = 1;
3326
+ iColspan = 1;
3327
+
3328
+ /* Check to see if there is already a cell (row/colspan) covering our target
3329
+ * insert point. If there is, then there is nothing to do.
3330
+ */
3331
+ if ( aApplied[i][j] === undefined )
3332
+ {
3333
+ nLocalTr.appendChild( aoLocal[i][j].cell );
3334
+ aApplied[i][j] = 1;
3335
+
3336
+ /* Expand the cell to cover as many rows as needed */
3337
+ while ( aoLocal[i+iRowspan] !== undefined &&
3338
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
3339
+ {
3340
+ aApplied[i+iRowspan][j] = 1;
3341
+ iRowspan++;
3342
+ }
3343
+
3344
+ /* Expand the cell to cover as many columns as needed */
3345
+ while ( aoLocal[i][j+iColspan] !== undefined &&
3346
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
3347
+ {
3348
+ /* Must update the applied array over the rows for the columns */
3349
+ for ( k=0 ; k<iRowspan ; k++ )
3350
+ {
3351
+ aApplied[i+k][j+iColspan] = 1;
3352
+ }
3353
+ iColspan++;
3354
+ }
3355
+
3356
+ /* Do the actual expansion in the DOM */
3357
+ $(aoLocal[i][j].cell)
3358
+ .attr('rowspan', iRowspan)
3359
+ .attr('colspan', iColspan);
3360
+ }
3361
+ }
3362
+ }
3363
+ }
3364
+
3365
+
3366
+ /**
3367
+ * Insert the required TR nodes into the table for display
3368
+ * @param {object} oSettings dataTables settings object
3369
+ * @memberof DataTable#oApi
3370
+ */
3371
+ function _fnDraw( oSettings )
3372
+ {
3373
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
3374
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
3375
+ if ( $.inArray( false, aPreDraw ) !== -1 )
3376
+ {
3377
+ _fnProcessingDisplay( oSettings, false );
3378
+ return;
3379
+ }
3380
+
3381
+ var i, iLen, n;
3382
+ var anRows = [];
3383
+ var iRowCount = 0;
3384
+ var asStripeClasses = oSettings.asStripeClasses;
3385
+ var iStripes = asStripeClasses.length;
3386
+ var iOpenRows = oSettings.aoOpenRows.length;
3387
+ var oLang = oSettings.oLanguage;
3388
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
3389
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
3390
+ var aiDisplay = oSettings.aiDisplay;
3391
+
3392
+ oSettings.bDrawing = true;
3393
+
3394
+ /* Check and see if we have an initial draw position from state saving */
3395
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
3396
+ {
3397
+ oSettings._iDisplayStart = bServerSide ?
3398
+ iInitDisplayStart :
3399
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
3400
+ 0 :
3401
+ iInitDisplayStart;
3402
+
3403
+ oSettings.iInitDisplayStart = -1;
3404
+ }
3405
+
3406
+ var iDisplayStart = oSettings._iDisplayStart;
3407
+ var iDisplayEnd = oSettings.fnDisplayEnd();
3408
+
3409
+ /* Server-side processing draw intercept */
3410
+ if ( oSettings.bDeferLoading )
3411
+ {
3412
+ oSettings.bDeferLoading = false;
3413
+ oSettings.iDraw++;
3414
+ _fnProcessingDisplay( oSettings, false );
3415
+ }
3416
+ else if ( !bServerSide )
3417
+ {
3418
+ oSettings.iDraw++;
3419
+ }
3420
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
3421
+ {
3422
+ return;
3423
+ }
3424
+
3425
+ if ( aiDisplay.length !== 0 )
3426
+ {
3427
+ var iStart = bServerSide ? 0 : iDisplayStart;
3428
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
3429
+
3430
+ for ( var j=iStart ; j<iEnd ; j++ )
3431
+ {
3432
+ var iDataIndex = aiDisplay[j];
3433
+ var aoData = oSettings.aoData[ iDataIndex ];
3434
+ if ( aoData.nTr === null )
3435
+ {
3436
+ _fnCreateTr( oSettings, iDataIndex );
3437
+ }
3438
+
3439
+ var nRow = aoData.nTr;
3440
+
3441
+ /* Remove the old striping classes and then add the new one */
3442
+ if ( iStripes !== 0 )
3443
+ {
3444
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
3445
+ if ( aoData._sRowStripe != sStripe )
3446
+ {
3447
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
3448
+ aoData._sRowStripe = sStripe;
3449
+ }
3450
+ }
3451
+
3452
+ // Row callback functions - might want to manipulate the row
3453
+ // iRowCount and j are not currently documented. Are they at all
3454
+ // useful?
3455
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
3456
+ [nRow, aoData._aData, iRowCount, j] );
3457
+
3458
+ anRows.push( nRow );
3459
+ iRowCount++;
3460
+ }
3461
+ }
3462
+ else
3463
+ {
3464
+ /* Table is empty - create a row with an empty message in it */
3465
+ var sZero = oLang.sZeroRecords;
3466
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
3467
+ {
3468
+ sZero = oLang.sLoadingRecords;
3469
+ }
3470
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3471
+ {
3472
+ sZero = oLang.sEmptyTable;
3473
+ }
3474
+
3475
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
3476
+ .append( $('<td />', {
3477
+ 'valign': 'top',
3478
+ 'colSpan': _fnVisbleColumns( oSettings ),
3479
+ 'class': oSettings.oClasses.sRowEmpty
3480
+ } ).html( sZero ) )[0];
3481
+ }
3482
+
3483
+ /* Header and footer callbacks */
3484
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
3485
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3486
+
3487
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
3488
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
3489
+
3490
+ var body = $(oSettings.nTBody);
3491
+
3492
+ body.children().detach();
3493
+ body.append( $(anRows) );
3494
+
3495
+ /* Call all required callback functions for the end of a draw */
3496
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3497
+
3498
+ /* Draw is complete, sorting and filtering must be as well */
3499
+ oSettings.bSorted = false;
3500
+ oSettings.bFiltered = false;
3501
+ oSettings.bDrawing = false;
3502
+ }
3503
+
3504
+
3505
+ /**
3506
+ * Redraw the table - taking account of the various features which are enabled
3507
+ * @param {object} oSettings dataTables settings object
3508
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
3509
+ * the paging is reset to the first page
3510
+ * @memberof DataTable#oApi
3511
+ */
3512
+ function _fnReDraw( settings, holdPosition )
3513
+ {
3514
+ var
3515
+ features = settings.oFeatures,
3516
+ sort = features.bSort,
3517
+ filter = features.bFilter;
3518
+
3519
+ if ( sort ) {
3520
+ _fnSort( settings );
3521
+ }
3522
+
3523
+ if ( filter ) {
3524
+ _fnFilterComplete( settings, settings.oPreviousSearch );
3525
+ }
3526
+ else {
3527
+ // No filtering, so we want to just use the display master
3528
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
3529
+ }
3530
+
3531
+ if ( holdPosition !== true ) {
3532
+ settings._iDisplayStart = 0;
3533
+ }
3534
+
3535
+ // Let any modules know about the draw hold position state (used by
3536
+ // scrolling internally)
3537
+ settings._drawHold = holdPosition;
3538
+
3539
+ _fnDraw( settings );
3540
+
3541
+ settings._drawHold = false;
3542
+ }
3543
+
3544
+
3545
+ /**
3546
+ * Add the options to the page HTML for the table
3547
+ * @param {object} oSettings dataTables settings object
3548
+ * @memberof DataTable#oApi
3549
+ */
3550
+ function _fnAddOptionsHtml ( oSettings )
3551
+ {
3552
+ var classes = oSettings.oClasses;
3553
+ var table = $(oSettings.nTable);
3554
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
3555
+ var features = oSettings.oFeatures;
3556
+
3557
+ // All DataTables are wrapped in a div
3558
+ var insert = $('<div/>', {
3559
+ id: oSettings.sTableId+'_wrapper',
3560
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
3561
+ } );
3562
+
3563
+ oSettings.nHolding = holding[0];
3564
+ oSettings.nTableWrapper = insert[0];
3565
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3566
+
3567
+ /* Loop over the user set positioning and place the elements as needed */
3568
+ var aDom = oSettings.sDom.split('');
3569
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
3570
+ for ( var i=0 ; i<aDom.length ; i++ )
3571
+ {
3572
+ featureNode = null;
3573
+ cOption = aDom[i];
3574
+
3575
+ if ( cOption == '<' )
3576
+ {
3577
+ /* New container div */
3578
+ nNewNode = $('<div/>')[0];
3579
+
3580
+ /* Check to see if we should append an id and/or a class name to the container */
3581
+ cNext = aDom[i+1];
3582
+ if ( cNext == "'" || cNext == '"' )
3583
+ {
3584
+ sAttr = "";
3585
+ j = 2;
3586
+ while ( aDom[i+j] != cNext )
3587
+ {
3588
+ sAttr += aDom[i+j];
3589
+ j++;
3590
+ }
3591
+
3592
+ /* Replace jQuery UI constants @todo depreciated */
3593
+ if ( sAttr == "H" )
3594
+ {
3595
+ sAttr = classes.sJUIHeader;
3596
+ }
3597
+ else if ( sAttr == "F" )
3598
+ {
3599
+ sAttr = classes.sJUIFooter;
3600
+ }
3601
+
3602
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3603
+ * breaks the string into parts and applies them as needed
3604
+ */
3605
+ if ( sAttr.indexOf('.') != -1 )
3606
+ {
3607
+ var aSplit = sAttr.split('.');
3608
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3609
+ nNewNode.className = aSplit[1];
3610
+ }
3611
+ else if ( sAttr.charAt(0) == "#" )
3612
+ {
3613
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
3614
+ }
3615
+ else
3616
+ {
3617
+ nNewNode.className = sAttr;
3618
+ }
3619
+
3620
+ i += j; /* Move along the position array */
3621
+ }
3622
+
3623
+ insert.append( nNewNode );
3624
+ insert = $(nNewNode);
3625
+ }
3626
+ else if ( cOption == '>' )
3627
+ {
3628
+ /* End container div */
3629
+ insert = insert.parent();
3630
+ }
3631
+ // @todo Move options into their own plugins?
3632
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
3633
+ {
3634
+ /* Length */
3635
+ featureNode = _fnFeatureHtmlLength( oSettings );
3636
+ }
3637
+ else if ( cOption == 'f' && features.bFilter )
3638
+ {
3639
+ /* Filter */
3640
+ featureNode = _fnFeatureHtmlFilter( oSettings );
3641
+ }
3642
+ else if ( cOption == 'r' && features.bProcessing )
3643
+ {
3644
+ /* pRocessing */
3645
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
3646
+ }
3647
+ else if ( cOption == 't' )
3648
+ {
3649
+ /* Table */
3650
+ featureNode = _fnFeatureHtmlTable( oSettings );
3651
+ }
3652
+ else if ( cOption == 'i' && features.bInfo )
3653
+ {
3654
+ /* Info */
3655
+ featureNode = _fnFeatureHtmlInfo( oSettings );
3656
+ }
3657
+ else if ( cOption == 'p' && features.bPaginate )
3658
+ {
3659
+ /* Pagination */
3660
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
3661
+ }
3662
+ else if ( DataTable.ext.feature.length !== 0 )
3663
+ {
3664
+ /* Plug-in features */
3665
+ var aoFeatures = DataTable.ext.feature;
3666
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3667
+ {
3668
+ if ( cOption == aoFeatures[k].cFeature )
3669
+ {
3670
+ featureNode = aoFeatures[k].fnInit( oSettings );
3671
+ break;
3672
+ }
3673
+ }
3674
+ }
3675
+
3676
+ /* Add to the 2D features array */
3677
+ if ( featureNode )
3678
+ {
3679
+ var aanFeatures = oSettings.aanFeatures;
3680
+
3681
+ if ( ! aanFeatures[cOption] )
3682
+ {
3683
+ aanFeatures[cOption] = [];
3684
+ }
3685
+
3686
+ aanFeatures[cOption].push( featureNode );
3687
+ insert.append( featureNode );
3688
+ }
3689
+ }
3690
+
3691
+ /* Built our DOM structure - replace the holding div with what we want */
3692
+ holding.replaceWith( insert );
3693
+ oSettings.nHolding = null;
3694
+ }
3695
+
3696
+
3697
+ /**
3698
+ * Use the DOM source to create up an array of header cells. The idea here is to
3699
+ * create a layout grid (array) of rows x columns, which contains a reference
3700
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
3701
+ * any column / row could be removed and the new grid constructed
3702
+ * @param array {object} aLayout Array to store the calculated layout in
3703
+ * @param {node} nThead The header/footer element for the table
3704
+ * @memberof DataTable#oApi
3705
+ */
3706
+ function _fnDetectHeader ( aLayout, nThead )
3707
+ {
3708
+ var nTrs = $(nThead).children('tr');
3709
+ var nTr, nCell;
3710
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3711
+ var bUnique;
3712
+ var fnShiftCol = function ( a, i, j ) {
3713
+ var k = a[i];
3714
+ while ( k[j] ) {
3715
+ j++;
3716
+ }
3717
+ return j;
3718
+ };
3719
+
3720
+ aLayout.splice( 0, aLayout.length );
3721
+
3722
+ /* We know how many rows there are in the layout - so prep it */
3723
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3724
+ {
3725
+ aLayout.push( [] );
3726
+ }
3727
+
3728
+ /* Calculate a layout array */
3729
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3730
+ {
3731
+ nTr = nTrs[i];
3732
+ iColumn = 0;
3733
+
3734
+ /* For every cell in the row... */
3735
+ nCell = nTr.firstChild;
3736
+ while ( nCell ) {
3737
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
3738
+ nCell.nodeName.toUpperCase() == "TH" )
3739
+ {
3740
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
3741
+ iColspan = nCell.getAttribute('colspan') * 1;
3742
+ iRowspan = nCell.getAttribute('rowspan') * 1;
3743
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3744
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3745
+
3746
+ /* There might be colspan cells already in this row, so shift our target
3747
+ * accordingly
3748
+ */
3749
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
3750
+
3751
+ /* Cache calculation for unique columns */
3752
+ bUnique = iColspan === 1 ? true : false;
3753
+
3754
+ /* If there is col / rowspan, copy the information into the layout grid */
3755
+ for ( l=0 ; l<iColspan ; l++ )
3756
+ {
3757
+ for ( k=0 ; k<iRowspan ; k++ )
3758
+ {
3759
+ aLayout[i+k][iColShifted+l] = {
3760
+ "cell": nCell,
3761
+ "unique": bUnique
3762
+ };
3763
+ aLayout[i+k].nTr = nTr;
3764
+ }
3765
+ }
3766
+ }
3767
+ nCell = nCell.nextSibling;
3768
+ }
3769
+ }
3770
+ }
3771
+
3772
+
3773
+ /**
3774
+ * Get an array of unique th elements, one for each column
3775
+ * @param {object} oSettings dataTables settings object
3776
+ * @param {node} nHeader automatically detect the layout from this node - optional
3777
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3778
+ * @returns array {node} aReturn list of unique th's
3779
+ * @memberof DataTable#oApi
3780
+ */
3781
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3782
+ {
3783
+ var aReturn = [];
3784
+ if ( !aLayout )
3785
+ {
3786
+ aLayout = oSettings.aoHeader;
3787
+ if ( nHeader )
3788
+ {
3789
+ aLayout = [];
3790
+ _fnDetectHeader( aLayout, nHeader );
3791
+ }
3792
+ }
3793
+
3794
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3795
+ {
3796
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3797
+ {
3798
+ if ( aLayout[i][j].unique &&
3799
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
3800
+ {
3801
+ aReturn[j] = aLayout[i][j].cell;
3802
+ }
3803
+ }
3804
+ }
3805
+
3806
+ return aReturn;
3807
+ }
3808
+
3809
+ /**
3810
+ * Create an Ajax call based on the table's settings, taking into account that
3811
+ * parameters can have multiple forms, and backwards compatibility.
3812
+ *
3813
+ * @param {object} oSettings dataTables settings object
3814
+ * @param {array} data Data to send to the server, required by
3815
+ * DataTables - may be augmented by developer callbacks
3816
+ * @param {function} fn Callback function to run when data is obtained
3817
+ */
3818
+ function _fnBuildAjax( oSettings, data, fn )
3819
+ {
3820
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
3821
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
3822
+
3823
+ // Convert to object based for 1.10+ if using the old array scheme which can
3824
+ // come from server-side processing or serverParams
3825
+ if ( data && $.isArray(data) ) {
3826
+ var tmp = {};
3827
+ var rbracket = /(.*?)\[\]$/;
3828
+
3829
+ $.each( data, function (key, val) {
3830
+ var match = val.name.match(rbracket);
3831
+
3832
+ if ( match ) {
3833
+ // Support for arrays
3834
+ var name = match[0];
3835
+
3836
+ if ( ! tmp[ name ] ) {
3837
+ tmp[ name ] = [];
3838
+ }
3839
+ tmp[ name ].push( val.value );
3840
+ }
3841
+ else {
3842
+ tmp[val.name] = val.value;
3843
+ }
3844
+ } );
3845
+ data = tmp;
3846
+ }
3847
+
3848
+ var ajaxData;
3849
+ var ajax = oSettings.ajax;
3850
+ var instance = oSettings.oInstance;
3851
+ var callback = function ( json ) {
3852
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
3853
+ fn( json );
3854
+ };
3855
+
3856
+ if ( $.isPlainObject( ajax ) && ajax.data )
3857
+ {
3858
+ ajaxData = ajax.data;
3859
+
3860
+ var newData = $.isFunction( ajaxData ) ?
3861
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
3862
+ ajaxData; // an object object or array to merge
3863
+
3864
+ // If the function returned something, use that alone
3865
+ data = $.isFunction( ajaxData ) && newData ?
3866
+ newData :
3867
+ $.extend( true, data, newData );
3868
+
3869
+ // Remove the data property as we've resolved it already and don't want
3870
+ // jQuery to do it again (it is restored at the end of the function)
3871
+ delete ajax.data;
3872
+ }
3873
+
3874
+ var baseAjax = {
3875
+ "data": data,
3876
+ "success": function (json) {
3877
+ var error = json.error || json.sError;
3878
+ if ( error ) {
3879
+ _fnLog( oSettings, 0, error );
3880
+ }
3881
+
3882
+ oSettings.json = json;
3883
+ callback( json );
3884
+ },
3885
+ "dataType": "json",
3886
+ "cache": false,
3887
+ "type": oSettings.sServerMethod,
3888
+ "error": function (xhr, error, thrown) {
3889
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
3890
+
3891
+ if ( $.inArray( true, ret ) === -1 ) {
3892
+ if ( error == "parsererror" ) {
3893
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
3894
+ }
3895
+ else if ( xhr.readyState === 4 ) {
3896
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
3897
+ }
3898
+ }
3899
+
3900
+ _fnProcessingDisplay( oSettings, false );
3901
+ }
3902
+ };
3903
+
3904
+ // Store the data submitted for the API
3905
+ oSettings.oAjaxData = data;
3906
+
3907
+ // Allow plug-ins and external processes to modify the data
3908
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
3909
+
3910
+ if ( oSettings.fnServerData )
3911
+ {
3912
+ // DataTables 1.9- compatibility
3913
+ oSettings.fnServerData.call( instance,
3914
+ oSettings.sAjaxSource,
3915
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
3916
+ return { name: key, value: val };
3917
+ } ),
3918
+ callback,
3919
+ oSettings
3920
+ );
3921
+ }
3922
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
3923
+ {
3924
+ // DataTables 1.9- compatibility
3925
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
3926
+ url: ajax || oSettings.sAjaxSource
3927
+ } ) );
3928
+ }
3929
+ else if ( $.isFunction( ajax ) )
3930
+ {
3931
+ // Is a function - let the caller define what needs to be done
3932
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
3933
+ }
3934
+ else
3935
+ {
3936
+ // Object to extend the base settings
3937
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
3938
+
3939
+ // Restore for next time around
3940
+ ajax.data = ajaxData;
3941
+ }
3942
+ }
3943
+
3944
+
3945
+ /**
3946
+ * Update the table using an Ajax call
3947
+ * @param {object} settings dataTables settings object
3948
+ * @returns {boolean} Block the table drawing or not
3949
+ * @memberof DataTable#oApi
3950
+ */
3951
+ function _fnAjaxUpdate( settings )
3952
+ {
3953
+ if ( settings.bAjaxDataGet ) {
3954
+ settings.iDraw++;
3955
+ _fnProcessingDisplay( settings, true );
3956
+
3957
+ _fnBuildAjax(
3958
+ settings,
3959
+ _fnAjaxParameters( settings ),
3960
+ function(json) {
3961
+ _fnAjaxUpdateDraw( settings, json );
3962
+ }
3963
+ );
3964
+
3965
+ return false;
3966
+ }
3967
+ return true;
3968
+ }
3969
+
3970
+
3971
+ /**
3972
+ * Build up the parameters in an object needed for a server-side processing
3973
+ * request. Note that this is basically done twice, is different ways - a modern
3974
+ * method which is used by default in DataTables 1.10 which uses objects and
3975
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
3976
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
3977
+ * option is set.
3978
+ * @param {object} oSettings dataTables settings object
3979
+ * @returns {bool} block the table drawing or not
3980
+ * @memberof DataTable#oApi
3981
+ */
3982
+ function _fnAjaxParameters( settings )
3983
+ {
3984
+ var
3985
+ columns = settings.aoColumns,
3986
+ columnCount = columns.length,
3987
+ features = settings.oFeatures,
3988
+ preSearch = settings.oPreviousSearch,
3989
+ preColSearch = settings.aoPreSearchCols,
3990
+ i, data = [], dataProp, column, columnSearch,
3991
+ sort = _fnSortFlatten( settings ),
3992
+ displayStart = settings._iDisplayStart,
3993
+ displayLength = features.bPaginate !== false ?
3994
+ settings._iDisplayLength :
3995
+ -1;
3996
+
3997
+ var param = function ( name, value ) {
3998
+ data.push( { 'name': name, 'value': value } );
3999
+ };
4000
+
4001
+ // DataTables 1.9- compatible method
4002
+ param( 'sEcho', settings.iDraw );
4003
+ param( 'iColumns', columnCount );
4004
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
4005
+ param( 'iDisplayStart', displayStart );
4006
+ param( 'iDisplayLength', displayLength );
4007
+
4008
+ // DataTables 1.10+ method
4009
+ var d = {
4010
+ draw: settings.iDraw,
4011
+ columns: [],
4012
+ order: [],
4013
+ start: displayStart,
4014
+ length: displayLength,
4015
+ search: {
4016
+ value: preSearch.sSearch,
4017
+ regex: preSearch.bRegex
4018
+ }
4019
+ };
4020
+
4021
+ for ( i=0 ; i<columnCount ; i++ ) {
4022
+ column = columns[i];
4023
+ columnSearch = preColSearch[i];
4024
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
4025
+
4026
+ d.columns.push( {
4027
+ data: dataProp,
4028
+ name: column.sName,
4029
+ searchable: column.bSearchable,
4030
+ orderable: column.bSortable,
4031
+ search: {
4032
+ value: columnSearch.sSearch,
4033
+ regex: columnSearch.bRegex
4034
+ }
4035
+ } );
4036
+
4037
+ param( "mDataProp_"+i, dataProp );
4038
+
4039
+ if ( features.bFilter ) {
4040
+ param( 'sSearch_'+i, columnSearch.sSearch );
4041
+ param( 'bRegex_'+i, columnSearch.bRegex );
4042
+ param( 'bSearchable_'+i, column.bSearchable );
4043
+ }
4044
+
4045
+ if ( features.bSort ) {
4046
+ param( 'bSortable_'+i, column.bSortable );
4047
+ }
4048
+ }
4049
+
4050
+ if ( features.bFilter ) {
4051
+ param( 'sSearch', preSearch.sSearch );
4052
+ param( 'bRegex', preSearch.bRegex );
4053
+ }
4054
+
4055
+ if ( features.bSort ) {
4056
+ $.each( sort, function ( i, val ) {
4057
+ d.order.push( { column: val.col, dir: val.dir } );
4058
+
4059
+ param( 'iSortCol_'+i, val.col );
4060
+ param( 'sSortDir_'+i, val.dir );
4061
+ } );
4062
+
4063
+ param( 'iSortingCols', sort.length );
4064
+ }
4065
+
4066
+ // If the legacy.ajax parameter is null, then we automatically decide which
4067
+ // form to use, based on sAjaxSource
4068
+ var legacy = DataTable.ext.legacy.ajax;
4069
+ if ( legacy === null ) {
4070
+ return settings.sAjaxSource ? data : d;
4071
+ }
4072
+
4073
+ // Otherwise, if legacy has been specified then we use that to decide on the
4074
+ // form
4075
+ return legacy ? data : d;
4076
+ }
4077
+
4078
+
4079
+ /**
4080
+ * Data the data from the server (nuking the old) and redraw the table
4081
+ * @param {object} oSettings dataTables settings object
4082
+ * @param {object} json json data return from the server.
4083
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
4084
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
4085
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
4086
+ * @param {array} json.aaData The data to display on this page
4087
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
4088
+ * @memberof DataTable#oApi
4089
+ */
4090
+ function _fnAjaxUpdateDraw ( settings, json )
4091
+ {
4092
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
4093
+ // Support both
4094
+ var compat = function ( old, modern ) {
4095
+ return json[old] !== undefined ? json[old] : json[modern];
4096
+ };
4097
+
4098
+ var data = _fnAjaxDataSrc( settings, json );
4099
+ var draw = compat( 'sEcho', 'draw' );
4100
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
4101
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
4102
+
4103
+ if ( draw ) {
4104
+ // Protect against out of sequence returns
4105
+ if ( draw*1 < settings.iDraw ) {
4106
+ return;
4107
+ }
4108
+ settings.iDraw = draw * 1;
4109
+ }
4110
+
4111
+ _fnClearTable( settings );
4112
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
4113
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
4114
+
4115
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
4116
+ _fnAddData( settings, data[i] );
4117
+ }
4118
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
4119
+
4120
+ settings.bAjaxDataGet = false;
4121
+ _fnDraw( settings );
4122
+
4123
+ if ( ! settings._bInitComplete ) {
4124
+ _fnInitComplete( settings, json );
4125
+ }
4126
+
4127
+ settings.bAjaxDataGet = true;
4128
+ _fnProcessingDisplay( settings, false );
4129
+ }
4130
+
4131
+
4132
+ /**
4133
+ * Get the data from the JSON data source to use for drawing a table. Using
4134
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
4135
+ * source object, or from a processing function.
4136
+ * @param {object} oSettings dataTables settings object
4137
+ * @param {object} json Data source object / array from the server
4138
+ * @return {array} Array of data to use
4139
+ */
4140
+ function _fnAjaxDataSrc ( oSettings, json )
4141
+ {
4142
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
4143
+ oSettings.ajax.dataSrc :
4144
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
4145
+
4146
+ // Compatibility with 1.9-. In order to read from aaData, check if the
4147
+ // default has been changed, if not, check for aaData
4148
+ if ( dataSrc === 'data' ) {
4149
+ return json.aaData || json[dataSrc];
4150
+ }
4151
+
4152
+ return dataSrc !== "" ?
4153
+ _fnGetObjectDataFn( dataSrc )( json ) :
4154
+ json;
4155
+ }
4156
+
4157
+ /**
4158
+ * Generate the node required for filtering text
4159
+ * @returns {node} Filter control element
4160
+ * @param {object} oSettings dataTables settings object
4161
+ * @memberof DataTable#oApi
4162
+ */
4163
+ function _fnFeatureHtmlFilter ( settings )
4164
+ {
4165
+ var classes = settings.oClasses;
4166
+ var tableId = settings.sTableId;
4167
+ var language = settings.oLanguage;
4168
+ var previousSearch = settings.oPreviousSearch;
4169
+ var features = settings.aanFeatures;
4170
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
4171
+
4172
+ var str = language.sSearch;
4173
+ str = str.match(/_INPUT_/) ?
4174
+ str.replace('_INPUT_', input) :
4175
+ str+input;
4176
+
4177
+ var filter = $('<div/>', {
4178
+ 'id': ! features.f ? tableId+'_filter' : null,
4179
+ 'class': classes.sFilter
4180
+ } )
4181
+ .append( $('<label/>' ).append( str ) );
4182
+
4183
+ var searchFn = function() {
4184
+ /* Update all other filter input elements for the new display */
4185
+ var n = features.f;
4186
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
4187
+
4188
+ /* Now do the filter */
4189
+ if ( val != previousSearch.sSearch ) {
4190
+ _fnFilterComplete( settings, {
4191
+ "sSearch": val,
4192
+ "bRegex": previousSearch.bRegex,
4193
+ "bSmart": previousSearch.bSmart ,
4194
+ "bCaseInsensitive": previousSearch.bCaseInsensitive
4195
+ } );
4196
+
4197
+ // Need to redraw, without resorting
4198
+ settings._iDisplayStart = 0;
4199
+ _fnDraw( settings );
4200
+ }
4201
+ };
4202
+
4203
+ var searchDelay = settings.searchDelay !== null ?
4204
+ settings.searchDelay :
4205
+ _fnDataSource( settings ) === 'ssp' ?
4206
+ 400 :
4207
+ 0;
4208
+
4209
+ var jqFilter = $('input', filter)
4210
+ .val( previousSearch.sSearch )
4211
+ .attr( 'placeholder', language.sSearchPlaceholder )
4212
+ .on(
4213
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
4214
+ searchDelay ?
4215
+ _fnThrottle( searchFn, searchDelay ) :
4216
+ searchFn
4217
+ )
4218
+ .on( 'keypress.DT', function(e) {
4219
+ /* Prevent form submission */
4220
+ if ( e.keyCode == 13 ) {
4221
+ return false;
4222
+ }
4223
+ } )
4224
+ .attr('aria-controls', tableId);
4225
+
4226
+ // Update the input elements whenever the table is filtered
4227
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
4228
+ if ( settings === s ) {
4229
+ // IE9 throws an 'unknown error' if document.activeElement is used
4230
+ // inside an iframe or frame...
4231
+ try {
4232
+ if ( jqFilter[0] !== document.activeElement ) {
4233
+ jqFilter.val( previousSearch.sSearch );
4234
+ }
4235
+ }
4236
+ catch ( e ) {}
4237
+ }
4238
+ } );
4239
+
4240
+ return filter[0];
4241
+ }
4242
+
4243
+
4244
+ /**
4245
+ * Filter the table using both the global filter and column based filtering
4246
+ * @param {object} oSettings dataTables settings object
4247
+ * @param {object} oSearch search information
4248
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4249
+ * @memberof DataTable#oApi
4250
+ */
4251
+ function _fnFilterComplete ( oSettings, oInput, iForce )
4252
+ {
4253
+ var oPrevSearch = oSettings.oPreviousSearch;
4254
+ var aoPrevSearch = oSettings.aoPreSearchCols;
4255
+ var fnSaveFilter = function ( oFilter ) {
4256
+ /* Save the filtering values */
4257
+ oPrevSearch.sSearch = oFilter.sSearch;
4258
+ oPrevSearch.bRegex = oFilter.bRegex;
4259
+ oPrevSearch.bSmart = oFilter.bSmart;
4260
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4261
+ };
4262
+ var fnRegex = function ( o ) {
4263
+ // Backwards compatibility with the bEscapeRegex option
4264
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
4265
+ };
4266
+
4267
+ // Resolve any column types that are unknown due to addition or invalidation
4268
+ // @todo As per sort - can this be moved into an event handler?
4269
+ _fnColumnTypes( oSettings );
4270
+
4271
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
4272
+ if ( _fnDataSource( oSettings ) != 'ssp' )
4273
+ {
4274
+ /* Global filter */
4275
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
4276
+ fnSaveFilter( oInput );
4277
+
4278
+ /* Now do the individual column filter */
4279
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
4280
+ {
4281
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
4282
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4283
+ }
4284
+
4285
+ /* Custom filtering */
4286
+ _fnFilterCustom( oSettings );
4287
+ }
4288
+ else
4289
+ {
4290
+ fnSaveFilter( oInput );
4291
+ }
4292
+
4293
+ /* Tell the draw function we have been filtering */
4294
+ oSettings.bFiltered = true;
4295
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
4296
+ }
4297
+
4298
+
4299
+ /**
4300
+ * Apply custom filtering functions
4301
+ * @param {object} oSettings dataTables settings object
4302
+ * @memberof DataTable#oApi
4303
+ */
4304
+ function _fnFilterCustom( settings )
4305
+ {
4306
+ var filters = DataTable.ext.search;
4307
+ var displayRows = settings.aiDisplay;
4308
+ var row, rowIdx;
4309
+
4310
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
4311
+ var rows = [];
4312
+
4313
+ // Loop over each row and see if it should be included
4314
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
4315
+ rowIdx = displayRows[ j ];
4316
+ row = settings.aoData[ rowIdx ];
4317
+
4318
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
4319
+ rows.push( rowIdx );
4320
+ }
4321
+ }
4322
+
4323
+ // So the array reference doesn't break set the results into the
4324
+ // existing array
4325
+ displayRows.length = 0;
4326
+ $.merge( displayRows, rows );
4327
+ }
4328
+ }
4329
+
4330
+
4331
+ /**
4332
+ * Filter the table on a per-column basis
4333
+ * @param {object} oSettings dataTables settings object
4334
+ * @param {string} sInput string to filter on
4335
+ * @param {int} iColumn column to filter
4336
+ * @param {bool} bRegex treat search string as a regular expression or not
4337
+ * @param {bool} bSmart use smart filtering or not
4338
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
4339
+ * @memberof DataTable#oApi
4340
+ */
4341
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
4342
+ {
4343
+ if ( searchStr === '' ) {
4344
+ return;
4345
+ }
4346
+
4347
+ var data;
4348
+ var out = [];
4349
+ var display = settings.aiDisplay;
4350
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
4351
+
4352
+ for ( var i=0 ; i<display.length ; i++ ) {
4353
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
4354
+
4355
+ if ( rpSearch.test( data ) ) {
4356
+ out.push( display[i] );
4357
+ }
4358
+ }
4359
+
4360
+ settings.aiDisplay = out;
4361
+ }
4362
+
4363
+
4364
+ /**
4365
+ * Filter the data table based on user input and draw the table
4366
+ * @param {object} settings dataTables settings object
4367
+ * @param {string} input string to filter on
4368
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
4369
+ * @param {bool} regex treat as a regular expression or not
4370
+ * @param {bool} smart perform smart filtering or not
4371
+ * @param {bool} caseInsensitive Do case insenstive matching or not
4372
+ * @memberof DataTable#oApi
4373
+ */
4374
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
4375
+ {
4376
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
4377
+ var prevSearch = settings.oPreviousSearch.sSearch;
4378
+ var displayMaster = settings.aiDisplayMaster;
4379
+ var display, invalidated, i;
4380
+ var filtered = [];
4381
+
4382
+ // Need to take account of custom filtering functions - always filter
4383
+ if ( DataTable.ext.search.length !== 0 ) {
4384
+ force = true;
4385
+ }
4386
+
4387
+ // Check if any of the rows were invalidated
4388
+ invalidated = _fnFilterData( settings );
4389
+
4390
+ // If the input is blank - we just want the full data set
4391
+ if ( input.length <= 0 ) {
4392
+ settings.aiDisplay = displayMaster.slice();
4393
+ }
4394
+ else {
4395
+ // New search - start from the master array
4396
+ if ( invalidated ||
4397
+ force ||
4398
+ prevSearch.length > input.length ||
4399
+ input.indexOf(prevSearch) !== 0 ||
4400
+ settings.bSorted // On resort, the display master needs to be
4401
+ // re-filtered since indexes will have changed
4402
+ ) {
4403
+ settings.aiDisplay = displayMaster.slice();
4404
+ }
4405
+
4406
+ // Search the display array
4407
+ display = settings.aiDisplay;
4408
+
4409
+ for ( i=0 ; i<display.length ; i++ ) {
4410
+ if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
4411
+ filtered.push( display[i] );
4412
+ }
4413
+ }
4414
+
4415
+ settings.aiDisplay = filtered;
4416
+ }
4417
+ }
4418
+
4419
+
4420
+ /**
4421
+ * Build a regular expression object suitable for searching a table
4422
+ * @param {string} sSearch string to search for
4423
+ * @param {bool} bRegex treat as a regular expression or not
4424
+ * @param {bool} bSmart perform smart filtering or not
4425
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
4426
+ * @returns {RegExp} constructed object
4427
+ * @memberof DataTable#oApi
4428
+ */
4429
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
4430
+ {
4431
+ search = regex ?
4432
+ search :
4433
+ _fnEscapeRegex( search );
4434
+
4435
+ if ( smart ) {
4436
+ /* For smart filtering we want to allow the search to work regardless of
4437
+ * word order. We also want double quoted text to be preserved, so word
4438
+ * order is important - a la google. So this is what we want to
4439
+ * generate:
4440
+ *
4441
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
4442
+ */
4443
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
4444
+ if ( word.charAt(0) === '"' ) {
4445
+ var m = word.match( /^"(.*)"$/ );
4446
+ word = m ? m[1] : word;
4447
+ }
4448
+
4449
+ return word.replace('"', '');
4450
+ } );
4451
+
4452
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
4453
+ }
4454
+
4455
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
4456
+ }
4457
+
4458
+
4459
+ /**
4460
+ * Escape a string such that it can be used in a regular expression
4461
+ * @param {string} sVal string to escape
4462
+ * @returns {string} escaped string
4463
+ * @memberof DataTable#oApi
4464
+ */
4465
+ var _fnEscapeRegex = DataTable.util.escapeRegex;
4466
+
4467
+ var __filter_div = $('<div>')[0];
4468
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
4469
+
4470
+ // Update the filtering data for each row if needed (by invalidation or first run)
4471
+ function _fnFilterData ( settings )
4472
+ {
4473
+ var columns = settings.aoColumns;
4474
+ var column;
4475
+ var i, j, ien, jen, filterData, cellData, row;
4476
+ var fomatters = DataTable.ext.type.search;
4477
+ var wasInvalidated = false;
4478
+
4479
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4480
+ row = settings.aoData[i];
4481
+
4482
+ if ( ! row._aFilterData ) {
4483
+ filterData = [];
4484
+
4485
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
4486
+ column = columns[j];
4487
+
4488
+ if ( column.bSearchable ) {
4489
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
4490
+
4491
+ if ( fomatters[ column.sType ] ) {
4492
+ cellData = fomatters[ column.sType ]( cellData );
4493
+ }
4494
+
4495
+ // Search in DataTables 1.10 is string based. In 1.11 this
4496
+ // should be altered to also allow strict type checking.
4497
+ if ( cellData === null ) {
4498
+ cellData = '';
4499
+ }
4500
+
4501
+ if ( typeof cellData !== 'string' && cellData.toString ) {
4502
+ cellData = cellData.toString();
4503
+ }
4504
+ }
4505
+ else {
4506
+ cellData = '';
4507
+ }
4508
+
4509
+ // If it looks like there is an HTML entity in the string,
4510
+ // attempt to decode it so sorting works as expected. Note that
4511
+ // we could use a single line of jQuery to do this, but the DOM
4512
+ // method used here is much faster http://jsperf.com/html-decode
4513
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
4514
+ __filter_div.innerHTML = cellData;
4515
+ cellData = __filter_div_textContent ?
4516
+ __filter_div.textContent :
4517
+ __filter_div.innerText;
4518
+ }
4519
+
4520
+ if ( cellData.replace ) {
4521
+ cellData = cellData.replace(/[\r\n]/g, '');
4522
+ }
4523
+
4524
+ filterData.push( cellData );
4525
+ }
4526
+
4527
+ row._aFilterData = filterData;
4528
+ row._sFilterRow = filterData.join(' ');
4529
+ wasInvalidated = true;
4530
+ }
4531
+ }
4532
+
4533
+ return wasInvalidated;
4534
+ }
4535
+
4536
+
4537
+ /**
4538
+ * Convert from the internal Hungarian notation to camelCase for external
4539
+ * interaction
4540
+ * @param {object} obj Object to convert
4541
+ * @returns {object} Inverted object
4542
+ * @memberof DataTable#oApi
4543
+ */
4544
+ function _fnSearchToCamel ( obj )
4545
+ {
4546
+ return {
4547
+ search: obj.sSearch,
4548
+ smart: obj.bSmart,
4549
+ regex: obj.bRegex,
4550
+ caseInsensitive: obj.bCaseInsensitive
4551
+ };
4552
+ }
4553
+
4554
+
4555
+
4556
+ /**
4557
+ * Convert from camelCase notation to the internal Hungarian. We could use the
4558
+ * Hungarian convert function here, but this is cleaner
4559
+ * @param {object} obj Object to convert
4560
+ * @returns {object} Inverted object
4561
+ * @memberof DataTable#oApi
4562
+ */
4563
+ function _fnSearchToHung ( obj )
4564
+ {
4565
+ return {
4566
+ sSearch: obj.search,
4567
+ bSmart: obj.smart,
4568
+ bRegex: obj.regex,
4569
+ bCaseInsensitive: obj.caseInsensitive
4570
+ };
4571
+ }
4572
+
4573
+ /**
4574
+ * Generate the node required for the info display
4575
+ * @param {object} oSettings dataTables settings object
4576
+ * @returns {node} Information element
4577
+ * @memberof DataTable#oApi
4578
+ */
4579
+ function _fnFeatureHtmlInfo ( settings )
4580
+ {
4581
+ var
4582
+ tid = settings.sTableId,
4583
+ nodes = settings.aanFeatures.i,
4584
+ n = $('<div/>', {
4585
+ 'class': settings.oClasses.sInfo,
4586
+ 'id': ! nodes ? tid+'_info' : null
4587
+ } );
4588
+
4589
+ if ( ! nodes ) {
4590
+ // Update display on each draw
4591
+ settings.aoDrawCallback.push( {
4592
+ "fn": _fnUpdateInfo,
4593
+ "sName": "information"
4594
+ } );
4595
+
4596
+ n
4597
+ .attr( 'role', 'status' )
4598
+ .attr( 'aria-live', 'polite' );
4599
+
4600
+ // Table is described by our info div
4601
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
4602
+ }
4603
+
4604
+ return n[0];
4605
+ }
4606
+
4607
+
4608
+ /**
4609
+ * Update the information elements in the display
4610
+ * @param {object} settings dataTables settings object
4611
+ * @memberof DataTable#oApi
4612
+ */
4613
+ function _fnUpdateInfo ( settings )
4614
+ {
4615
+ /* Show information about the table */
4616
+ var nodes = settings.aanFeatures.i;
4617
+ if ( nodes.length === 0 ) {
4618
+ return;
4619
+ }
4620
+
4621
+ var
4622
+ lang = settings.oLanguage,
4623
+ start = settings._iDisplayStart+1,
4624
+ end = settings.fnDisplayEnd(),
4625
+ max = settings.fnRecordsTotal(),
4626
+ total = settings.fnRecordsDisplay(),
4627
+ out = total ?
4628
+ lang.sInfo :
4629
+ lang.sInfoEmpty;
4630
+
4631
+ if ( total !== max ) {
4632
+ /* Record set after filtering */
4633
+ out += ' ' + lang.sInfoFiltered;
4634
+ }
4635
+
4636
+ // Convert the macros
4637
+ out += lang.sInfoPostFix;
4638
+ out = _fnInfoMacros( settings, out );
4639
+
4640
+ var callback = lang.fnInfoCallback;
4641
+ if ( callback !== null ) {
4642
+ out = callback.call( settings.oInstance,
4643
+ settings, start, end, max, total, out
4644
+ );
4645
+ }
4646
+
4647
+ $(nodes).html( out );
4648
+ }
4649
+
4650
+
4651
+ function _fnInfoMacros ( settings, str )
4652
+ {
4653
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
4654
+ // internally
4655
+ var
4656
+ formatter = settings.fnFormatNumber,
4657
+ start = settings._iDisplayStart+1,
4658
+ len = settings._iDisplayLength,
4659
+ vis = settings.fnRecordsDisplay(),
4660
+ all = len === -1;
4661
+
4662
+ return str.
4663
+ replace(/_START_/g, formatter.call( settings, start ) ).
4664
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
4665
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
4666
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
4667
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
4668
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
4669
+ }
4670
+
4671
+
4672
+
4673
+ /**
4674
+ * Draw the table for the first time, adding all required features
4675
+ * @param {object} settings dataTables settings object
4676
+ * @memberof DataTable#oApi
4677
+ */
4678
+ function _fnInitialise ( settings )
4679
+ {
4680
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
4681
+ var columns = settings.aoColumns, column;
4682
+ var features = settings.oFeatures;
4683
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
4684
+
4685
+ /* Ensure that the table data is fully initialised */
4686
+ if ( ! settings.bInitialised ) {
4687
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
4688
+ return;
4689
+ }
4690
+
4691
+ /* Show the display HTML options */
4692
+ _fnAddOptionsHtml( settings );
4693
+
4694
+ /* Build and draw the header / footer for the table */
4695
+ _fnBuildHead( settings );
4696
+ _fnDrawHead( settings, settings.aoHeader );
4697
+ _fnDrawHead( settings, settings.aoFooter );
4698
+
4699
+ /* Okay to show that something is going on now */
4700
+ _fnProcessingDisplay( settings, true );
4701
+
4702
+ /* Calculate sizes for columns */
4703
+ if ( features.bAutoWidth ) {
4704
+ _fnCalculateColumnWidths( settings );
4705
+ }
4706
+
4707
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
4708
+ column = columns[i];
4709
+
4710
+ if ( column.sWidth ) {
4711
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
4712
+ }
4713
+ }
4714
+
4715
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
4716
+
4717
+ // If there is default sorting required - let's do it. The sort function
4718
+ // will do the drawing for us. Otherwise we draw the table regardless of the
4719
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
4720
+ // data (show 'loading' message possibly)
4721
+ _fnReDraw( settings );
4722
+
4723
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
4724
+ var dataSrc = _fnDataSource( settings );
4725
+ if ( dataSrc != 'ssp' || deferLoading ) {
4726
+ // if there is an ajax source load the data
4727
+ if ( dataSrc == 'ajax' ) {
4728
+ _fnBuildAjax( settings, [], function(json) {
4729
+ var aData = _fnAjaxDataSrc( settings, json );
4730
+
4731
+ // Got the data - add it to the table
4732
+ for ( i=0 ; i<aData.length ; i++ ) {
4733
+ _fnAddData( settings, aData[i] );
4734
+ }
4735
+
4736
+ // Reset the init display for cookie saving. We've already done
4737
+ // a filter, and therefore cleared it before. So we need to make
4738
+ // it appear 'fresh'
4739
+ settings.iInitDisplayStart = iAjaxStart;
4740
+
4741
+ _fnReDraw( settings );
4742
+
4743
+ _fnProcessingDisplay( settings, false );
4744
+ _fnInitComplete( settings, json );
4745
+ }, settings );
4746
+ }
4747
+ else {
4748
+ _fnProcessingDisplay( settings, false );
4749
+ _fnInitComplete( settings );
4750
+ }
4751
+ }
4752
+ }
4753
+
4754
+
4755
+ /**
4756
+ * Draw the table for the first time, adding all required features
4757
+ * @param {object} oSettings dataTables settings object
4758
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
4759
+ * with client-side processing (optional)
4760
+ * @memberof DataTable#oApi
4761
+ */
4762
+ function _fnInitComplete ( settings, json )
4763
+ {
4764
+ settings._bInitComplete = true;
4765
+
4766
+ // When data was added after the initialisation (data or Ajax) we need to
4767
+ // calculate the column sizing
4768
+ if ( json || settings.oInit.aaData ) {
4769
+ _fnAdjustColumnSizing( settings );
4770
+ }
4771
+
4772
+ _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
4773
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
4774
+ }
4775
+
4776
+
4777
+ function _fnLengthChange ( settings, val )
4778
+ {
4779
+ var len = parseInt( val, 10 );
4780
+ settings._iDisplayLength = len;
4781
+
4782
+ _fnLengthOverflow( settings );
4783
+
4784
+ // Fire length change event
4785
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
4786
+ }
4787
+
4788
+
4789
+ /**
4790
+ * Generate the node required for user display length changing
4791
+ * @param {object} settings dataTables settings object
4792
+ * @returns {node} Display length feature node
4793
+ * @memberof DataTable#oApi
4794
+ */
4795
+ function _fnFeatureHtmlLength ( settings )
4796
+ {
4797
+ var
4798
+ classes = settings.oClasses,
4799
+ tableId = settings.sTableId,
4800
+ menu = settings.aLengthMenu,
4801
+ d2 = $.isArray( menu[0] ),
4802
+ lengths = d2 ? menu[0] : menu,
4803
+ language = d2 ? menu[1] : menu;
4804
+
4805
+ var select = $('<select/>', {
4806
+ 'name': tableId+'_length',
4807
+ 'aria-controls': tableId,
4808
+ 'class': classes.sLengthSelect
4809
+ } );
4810
+
4811
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
4812
+ select[0][ i ] = new Option(
4813
+ typeof language[i] === 'number' ?
4814
+ settings.fnFormatNumber( language[i] ) :
4815
+ language[i],
4816
+ lengths[i]
4817
+ );
4818
+ }
4819
+
4820
+ var div = $('<div><label/></div>').addClass( classes.sLength );
4821
+ if ( ! settings.aanFeatures.l ) {
4822
+ div[0].id = tableId+'_length';
4823
+ }
4824
+
4825
+ div.children().append(
4826
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
4827
+ );
4828
+
4829
+ // Can't use `select` variable as user might provide their own and the
4830
+ // reference is broken by the use of outerHTML
4831
+ $('select', div)
4832
+ .val( settings._iDisplayLength )
4833
+ .on( 'change.DT', function(e) {
4834
+ _fnLengthChange( settings, $(this).val() );
4835
+ _fnDraw( settings );
4836
+ } );
4837
+
4838
+ // Update node value whenever anything changes the table's length
4839
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
4840
+ if ( settings === s ) {
4841
+ $('select', div).val( len );
4842
+ }
4843
+ } );
4844
+
4845
+ return div[0];
4846
+ }
4847
+
4848
+
4849
+
4850
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4851
+ * Note that most of the paging logic is done in
4852
+ * DataTable.ext.pager
4853
+ */
4854
+
4855
+ /**
4856
+ * Generate the node required for default pagination
4857
+ * @param {object} oSettings dataTables settings object
4858
+ * @returns {node} Pagination feature node
4859
+ * @memberof DataTable#oApi
4860
+ */
4861
+ function _fnFeatureHtmlPaginate ( settings )
4862
+ {
4863
+ var
4864
+ type = settings.sPaginationType,
4865
+ plugin = DataTable.ext.pager[ type ],
4866
+ modern = typeof plugin === 'function',
4867
+ redraw = function( settings ) {
4868
+ _fnDraw( settings );
4869
+ },
4870
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
4871
+ features = settings.aanFeatures;
4872
+
4873
+ if ( ! modern ) {
4874
+ plugin.fnInit( settings, node, redraw );
4875
+ }
4876
+
4877
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
4878
+ if ( ! features.p )
4879
+ {
4880
+ node.id = settings.sTableId+'_paginate';
4881
+
4882
+ settings.aoDrawCallback.push( {
4883
+ "fn": function( settings ) {
4884
+ if ( modern ) {
4885
+ var
4886
+ start = settings._iDisplayStart,
4887
+ len = settings._iDisplayLength,
4888
+ visRecords = settings.fnRecordsDisplay(),
4889
+ all = len === -1,
4890
+ page = all ? 0 : Math.ceil( start / len ),
4891
+ pages = all ? 1 : Math.ceil( visRecords / len ),
4892
+ buttons = plugin(page, pages),
4893
+ i, ien;
4894
+
4895
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
4896
+ _fnRenderer( settings, 'pageButton' )(
4897
+ settings, features.p[i], i, buttons, page, pages
4898
+ );
4899
+ }
4900
+ }
4901
+ else {
4902
+ plugin.fnUpdate( settings, redraw );
4903
+ }
4904
+ },
4905
+ "sName": "pagination"
4906
+ } );
4907
+ }
4908
+
4909
+ return node;
4910
+ }
4911
+
4912
+
4913
+ /**
4914
+ * Alter the display settings to change the page
4915
+ * @param {object} settings DataTables settings object
4916
+ * @param {string|int} action Paging action to take: "first", "previous",
4917
+ * "next" or "last" or page number to jump to (integer)
4918
+ * @param [bool] redraw Automatically draw the update or not
4919
+ * @returns {bool} true page has changed, false - no change
4920
+ * @memberof DataTable#oApi
4921
+ */
4922
+ function _fnPageChange ( settings, action, redraw )
4923
+ {
4924
+ var
4925
+ start = settings._iDisplayStart,
4926
+ len = settings._iDisplayLength,
4927
+ records = settings.fnRecordsDisplay();
4928
+
4929
+ if ( records === 0 || len === -1 )
4930
+ {
4931
+ start = 0;
4932
+ }
4933
+ else if ( typeof action === "number" )
4934
+ {
4935
+ start = action * len;
4936
+
4937
+ if ( start > records )
4938
+ {
4939
+ start = 0;
4940
+ }
4941
+ }
4942
+ else if ( action == "first" )
4943
+ {
4944
+ start = 0;
4945
+ }
4946
+ else if ( action == "previous" )
4947
+ {
4948
+ start = len >= 0 ?
4949
+ start - len :
4950
+ 0;
4951
+
4952
+ if ( start < 0 )
4953
+ {
4954
+ start = 0;
4955
+ }
4956
+ }
4957
+ else if ( action == "next" )
4958
+ {
4959
+ if ( start + len < records )
4960
+ {
4961
+ start += len;
4962
+ }
4963
+ }
4964
+ else if ( action == "last" )
4965
+ {
4966
+ start = Math.floor( (records-1) / len) * len;
4967
+ }
4968
+ else
4969
+ {
4970
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
4971
+ }
4972
+
4973
+ var changed = settings._iDisplayStart !== start;
4974
+ settings._iDisplayStart = start;
4975
+
4976
+ if ( changed ) {
4977
+ _f