WP-Optimize - Version 2.2.8

Version Description

  • 03/Jan/2019 =

  • FIX: Change a newly-introduced fragment that was not compatible with PHP 5.2

Download this release

Release Info

Developer DavidAnderson
Plugin Icon 128x128 WP-Optimize
Version 2.2.8
Comparing to
See all releases

Code changes from version 2.2.6 to 2.2.8

css/admin.css CHANGED
@@ -31,6 +31,12 @@
31
  margin-bottom: 16px;
32
  }
33
 
 
 
 
 
 
 
34
  /* COLUMN SETUP */
35
  .wpo_col {
36
  display: block;
@@ -122,12 +128,25 @@
122
 
123
  }
124
 
125
- #select_all_optimizations {
126
- margin-left: -5px;
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
128
 
129
- .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label {
130
- color: #9B0000;
131
  }
132
 
133
  td.wp-optimize-settings-optimization-checkbox {
@@ -147,12 +166,11 @@ td.wp-optimize-settings-optimization-checkbox {
147
 
148
  .wp-optimize-settings-optimization-info {
149
  font-size: 80%;
150
- padding-left: 32px;
151
  font-style: italic;
152
  }
153
 
154
  .wp-optimize-settings input[type="checkbox"] {
155
- width: 18px;
156
  }
157
 
158
  /* Added for the Image on Addons tab*/
@@ -160,7 +178,10 @@ img.addons {
160
  display: block;
161
  margin-left: auto;
162
  margin-right: auto;
163
- height: 44px;
 
 
 
164
  }
165
 
166
  .wpo_spinner {
@@ -195,7 +216,7 @@ img.addons {
195
 
196
  #save_done, .save-done {
197
  color: #D94F00;
198
- font-size: 250%;
199
  }
200
 
201
  .wp-optimize-settings-optimization-info a {
@@ -207,30 +228,41 @@ img.addons {
207
  top: 2px;
208
  }
209
 
210
- #wpoptimize_table_list .tablesorter-filter-row {
211
- display: none !important;
212
- }
 
 
 
213
 
214
- #wp_optimize_table_list_refresh {
215
- float: right;
216
  }
217
 
218
- #wp_optimize_table_list_refresh:hover {
219
- cursor: pointer;
220
  }
221
 
222
  #wpoptimize_table_list .optimization_spinner {
223
  position: relative;
224
- top: 5px;
225
  left: 5px;
226
  }
227
 
 
 
 
 
228
  #wpoptimize_table_list_filter {
229
  width: 100%;
 
230
  }
231
 
232
  #wpoptimize_table_list_tables_not_found {
233
  display: none;
 
 
 
 
 
234
  }
235
 
236
  #optimize_form .select2-container,
@@ -242,12 +274,10 @@ img.addons {
242
  }
243
 
244
  #wpoptimize_table_list .optimization_done_icon {
245
- color: #D94F00;
246
  font-size: 200%;
247
  display: inline-block;
248
  position: relative;
249
- top: 5px;
250
- left: -20px;
251
  }
252
 
253
  #wpo_sitelist_show_moreoptions_cron {
@@ -256,42 +286,31 @@ img.addons {
256
  letter-spacing: 1px;
257
  }
258
 
259
- .wpo_unused_image, .wpo_smush_image {
260
- position: relative;
261
- float: left;
262
- margin: .5%;
263
- width: 32%;
264
- text-align: center;
265
- background: rgba(220, 220, 220, 0.5);
266
- height: 20vh;
267
- min-height: 200px;
268
  }
269
 
270
- .wpo_unused_image img, .wpo_smush_image img {
271
- max-height: 80%;
272
- max-width: 90%;
273
- margin: 10px 5px;
274
  }
275
 
276
- .wpo_unused_image_checkbox_conatiner {
277
- text-align: center;
278
- position: absolute;
279
- width: 100%;
280
- bottom: 7px;
281
  }
282
 
283
- #wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {
284
- display: inline-block;
285
- }
286
 
287
- #wpo_remove_unused_images_btn {
288
- margin-top: 10px;
289
- margin-right: 10px;
290
- float: right;
291
- }
 
 
 
 
292
 
293
- #wpo_remove_selected_sizes_btn {
294
- margin-top: 20px;
295
  }
296
 
297
  #wp-optimize-nav-tab-contents-tables a {
@@ -360,6 +379,7 @@ img.addons {
360
  .wpo_logging_status_row,
361
  .wpo_logging_actions_row {
362
  display: inline-block;
 
363
  }
364
 
365
  .wpo_logging_logger_title,
@@ -390,13 +410,6 @@ img.addons {
390
  word-wrap: break-word;
391
  }
392
 
393
- #wpo_add_logger_link {
394
- clear: both;
395
- display: block;
396
- cursor: pointer;
397
- font-weight: bold;
398
- }
399
-
400
  .wpo_logging_actions_row .dashicons-no-alt,
401
  .wpo_add_logger_form .dashicons-no-alt {
402
  background-color: #F06666;
@@ -441,96 +454,63 @@ img.addons {
441
  .save_settings_reminder {
442
  display: none;
443
  color: #333;
444
- padding: 5px 10px;
445
- border: 1px solid #F00;
446
  background-color: #F0A5A4;
447
- border-radius: 5px;
448
  margin: 15px 0;
449
  }
450
 
451
- /* Added for WPO Premium Features tab */
452
- .wpo_feature_cont {
453
- width: 54.5%;
454
- }
455
-
456
- .wpo_plugin_family_cont {
457
- width: 44.5%;
458
- }
459
-
460
- .wpo_feat_table, .wpo_feat_th, .wpo_feat_table td {
461
- border: 1px solid black;
462
- border-collapse: collapse;
463
- font-size: 120%;
464
- background-color: white;
465
- text-align: center;
466
  }
467
 
468
- .wpo_feat_table p {
469
- padding: 0px 10px;
470
- margin: 5px 0px;
471
- font-size: 16px;
472
  }
473
 
474
- .wpo_feat_table h4 {
475
- margin: 5px 0px;
476
  }
477
 
478
- .wpo_feat_table .dashicons {
479
- width: 25px;
480
- height: 25px;
481
- font-size: 25px;
482
- line-height: 1;
483
  }
484
 
485
- .wpo_feat_table .dashicons-yes, .wpo_feat_table .updraft-yes {
486
- color: green;
487
  }
488
 
489
- .wpo_feat_table .dashicons-no-alt, .wpo_feat_table .updraft-no {
490
- color: red;
491
  }
492
 
493
- .wpo-premium-image {
494
- display: none;
495
  }
496
 
497
- @media screen and (min-width: 720px) {
498
-
499
- #wpoptimize_table_list_filter {
500
- width: 40%;
501
- }
502
-
503
- .wpo-premium-image {
504
- display: block;
505
- float: left;
506
- padding: 14px 8px;
507
- width: 50px;
508
- height: 50px;
509
- }
510
-
511
  }
512
 
513
- .other-plugin-title {
514
- text-decoration: none;
 
 
515
  }
516
 
517
- #wpo_remove_selected_sizes {
518
- margin-top: 20px;
 
519
  }
520
 
521
- .wpo_unused_images_buttons_wrap {
522
  display: none;
523
  }
524
 
525
- .wpo_unused_images_container h3 {
526
- min-width: 150px;
527
- }
528
-
529
- #wpo_unused_images, #wpo_smush_images_grid {
530
- max-height: 500px;
531
- overflow-y: auto;
532
- }
533
-
534
- #wpo_unused_images a {
535
- outline: none;
536
  }
31
  margin-bottom: 16px;
32
  }
33
 
34
+ .wp-optimize-settings td > label {
35
+ font-weight: bold;
36
+ display: block;
37
+ margin-bottom: 8px;
38
+ }
39
+
40
  /* COLUMN SETUP */
41
  .wpo_col {
42
  display: block;
128
 
129
  }
130
 
131
+ /* .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label */
132
+
133
+ .wp-optimize-setting-is-sensitive td > label::before {
134
+ content: "\f534";
135
+ font-family: 'dashicons';
136
+ display: inline-block;
137
+ margin-right: 6px;
138
+ font-style: normal;
139
+ line-height: 1;
140
+ vertical-align: middle;
141
+ width: 20px;
142
+ font-size: 18px;
143
+ height: 20px;
144
+ text-align: center;
145
+ color: #72777C;
146
  }
147
 
148
+ .wpo-run-optimizations__container {
149
+ margin-bottom: 15px;
150
  }
151
 
152
  td.wp-optimize-settings-optimization-checkbox {
166
 
167
  .wp-optimize-settings-optimization-info {
168
  font-size: 80%;
 
169
  font-style: italic;
170
  }
171
 
172
  .wp-optimize-settings input[type="checkbox"] {
173
+ /* width: 18px; */
174
  }
175
 
176
  /* Added for the Image on Addons tab*/
178
  display: block;
179
  margin-left: auto;
180
  margin-right: auto;
181
+ margin-bottom: 20px;
182
+ max-height: 44px;
183
+ height: auto;
184
+ max-width: 100%;
185
  }
186
 
187
  .wpo_spinner {
216
 
217
  #save_done, .save-done {
218
  color: #D94F00;
219
+ font-size: 250% !important;
220
  }
221
 
222
  .wp-optimize-settings-optimization-info a {
228
  top: 2px;
229
  }
230
 
231
+ @media screen and (min-width: 782px) {
232
+
233
+ td.wp-optimize-settings-optimization-run {
234
+ width: 180px;
235
+ padding-top: 16px;
236
+ }
237
 
 
 
238
  }
239
 
240
+ #wpoptimize_table_list .tablesorter-filter-row {
241
+ display: none !important;
242
  }
243
 
244
  #wpoptimize_table_list .optimization_spinner {
245
  position: relative;
246
+ top: 2px;
247
  left: 5px;
248
  }
249
 
250
+ #wpoptimize_table_list .optimization_spinner.visibility-hidden {
251
+ display: none;
252
+ }
253
+
254
  #wpoptimize_table_list_filter {
255
  width: 100%;
256
+ margin-bottom: 15px;
257
  }
258
 
259
  #wpoptimize_table_list_tables_not_found {
260
  display: none;
261
+ margin: 20px 0;
262
+ }
263
+
264
+ div#wpoptimize_table_list_tables_not_found + h3 {
265
+ margin-top: 30px;
266
  }
267
 
268
  #optimize_form .select2-container,
274
  }
275
 
276
  #wpoptimize_table_list .optimization_done_icon {
277
+ color: #009B24;
278
  font-size: 200%;
279
  display: inline-block;
280
  position: relative;
 
 
281
  }
282
 
283
  #wpo_sitelist_show_moreoptions_cron {
286
  letter-spacing: 1px;
287
  }
288
 
289
+ #wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {
290
+ display: inline-block;
 
 
 
 
 
 
 
291
  }
292
 
293
+ .wpo_remove_selected_sizes_btn__container {
294
+ margin-top: 20px;
 
 
295
  }
296
 
297
+ .unused-image-sizes__label {
298
+ display: block;
299
+ line-height: 1.6;
 
 
300
  }
301
 
302
+ @media (max-width: 782px) {
 
 
303
 
304
+ .unused-image-sizes__label {
305
+ margin-left: 30px;
306
+ margin-bottom: 15px;
307
+ line-height: 1;
308
+ }
309
+
310
+ .unused-image-sizes__label input[type=checkbox] {
311
+ margin-left: -30px;
312
+ }
313
 
 
 
314
  }
315
 
316
  #wp-optimize-nav-tab-contents-tables a {
379
  .wpo_logging_status_row,
380
  .wpo_logging_actions_row {
381
  display: inline-block;
382
+ vertical-align: middle;
383
  }
384
 
385
  .wpo_logging_logger_title,
410
  word-wrap: break-word;
411
  }
412
 
 
 
 
 
 
 
 
413
  .wpo_logging_actions_row .dashicons-no-alt,
414
  .wpo_add_logger_form .dashicons-no-alt {
415
  background-color: #F06666;
454
  .save_settings_reminder {
455
  display: none;
456
  color: #333;
457
+ padding: 15px 20px;
 
458
  background-color: #F0A5A4;
459
+ border-radius: 3px;
460
  margin: 15px 0;
461
  }
462
 
463
+ #wpo_remove_selected_sizes {
464
+ margin-top: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
465
  }
466
 
467
+ .wpo_unused_images_buttons_wrap {
468
+ display: none;
 
 
469
  }
470
 
471
+ .wpo_unused_images_container h3 {
472
+ min-width: 150px;
473
  }
474
 
475
+ #wpo_unused_images, #wpo_smush_images_grid {
476
+ max-height: 500px;
477
+ overflow-y: auto;
 
 
478
  }
479
 
480
+ #wpo_unused_images a {
481
+ outline: none;
482
  }
483
 
484
+ #wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup {
485
+ margin-left: 1%;
486
  }
487
 
488
+ .run-single-table-delete {
489
+ margin-top: 3px;
490
  }
491
 
492
+ #wpo_browser_cache_output,
493
+ #wpo_gzip_compression_output {
494
+ background: #F0F0F0;
495
+ padding: 10px;
496
+ border: 1px solid #CCC;
 
 
 
 
 
 
 
 
 
497
  }
498
 
499
+ #wpo_browser_cache_error_message,
500
+ #wpo_gzip_compression_error_message,
501
+ .wpo-error {
502
+ color: #9B0000;
503
  }
504
 
505
+ #wpo_browser_cache_expire_days,
506
+ #wpo_browser_cache_expire_hours {
507
+ width: 50px;
508
  }
509
 
510
+ .wpo-enabled .wpo-disabled {
511
  display: none;
512
  }
513
 
514
+ .wpo-disabled .wpo-enabled {
515
+ display: none;
 
 
 
 
 
 
 
 
 
516
  }
css/admin.min.css CHANGED
@@ -1,2 +1,2 @@
1
- .wpo_hidden{display:none}.wpo_info{background:#FFF;color:#444;font-family:-apple-system,"BlinkMacSystemFont","Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif;margin:2em auto;padding:1em 2em;max-width:700px;box-shadow:0 1px 3px rgba(0,0,0,0.13)}.wpo_primary_big{padding:4px 6px !important;font-size:22px !important;min-height:34px;min-width:200px}.wpo_section{clear:both;padding:0;margin:0}.wp-optimize-settings{margin-bottom:16px}.wpo_col{display:block;float:left;margin:1% 0 1% 1%}.wpo_col:first-child{margin-left:0}.wpo_group:before,.wpo_group:after{content:"";display:table}.wpo_group:after{clear:both}.wpo_half_width{width:48%}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:65.3%}.wpo_span_1_of_3{width:32.1%}.nav-tab-wrapper{margin:14px 0}@media screen and (min-width:549px){.show_on_default_sizes{display:block !important}.show_on_mobile_sizes{display:none !important}}@media screen and (max-width:548px){.show_on_default_sizes{display:none !important}.show_on_mobile_sizes{display:block !important}}@media screen and (max-width:768px){.wpo_col{margin:1% 0}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:100%}.wpo_span_1_of_3{width:100%}.wpo_half_width{width:100%}}#select_all_optimizations{margin-left:-5px}.wp-optimize-settings-clean-transient label,.wp-optimize-settings-clean-pingbacks label,.wp-optimize-settings-clean-trackbacks label,.wp-optimize-settings-clean-postmeta label,.wp-optimize-settings-clean-orphandata label,.wp-optimize-settings-clean-commentmeta label{color:#9b0000}td.wp-optimize-settings-optimization-checkbox{width:18px;padding-left:4px;padding-right:0}.wp-optimize-settings-optimization-checkbox input{margin:0;padding:0}#retention-period{width:60px}.wp-optimize-settings-optimization-info{font-size:80%;padding-left:32px;font-style:italic}.wp-optimize-settings input[type="checkbox"]{width:18px}img.addons{display:block;margin-left:auto;margin-right:auto;height:44px}.wpo_spinner{width:18px;height:18px;padding-left:10px;display:none;position:relative;top:4px}.optimization_spinner{width:20px;height:20px}#wp-optimize-auto-options{margin:20px 0 0 28px}.display-none{display:none}.visibility-hidden{visibility:hidden}.margin-one-percent{margin:1%}#save_done,.save-done{color:#d94f00;font-size:250%}.wp-optimize-settings-optimization-info a{text-decoration:underline}.wp-optimize-settings-optimization-run-spinner{position:relative;top:2px}#wpoptimize_table_list .tablesorter-filter-row{display:none !important}#wp_optimize_table_list_refresh{float:right}#wp_optimize_table_list_refresh:hover{cursor:pointer}#wpoptimize_table_list .optimization_spinner{position:relative;top:5px;left:5px}#wpoptimize_table_list_filter{width:100%}#wpoptimize_table_list_tables_not_found{display:none}#optimize_form .select2-container,#wp-optimize-auto-options .select2-container{width:50% !important;top:-5px;height:40px;margin-left:10px}#wpoptimize_table_list .optimization_done_icon{color:#d94f00;font-size:200%;display:inline-block;position:relative;top:5px;left:-20px}#wpo_sitelist_show_moreoptions_cron{font-size:13px;line-height:1.5;letter-spacing:1px}.wpo_unused_image,.wpo_smush_image{position:relative;float:left;margin:.5%;width:32%;text-align:center;background:rgba(220,220,220,0.5);height:20vh;min-height:200px}.wpo_unused_image img,.wpo_smush_image img{max-height:80%;max-width:90%;margin:10px 5px}.wpo_unused_image_checkbox_conatiner{text-align:center;position:absolute;width:100%;bottom:7px}#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3{display:inline-block}#wpo_remove_unused_images_btn{margin-top:10px;margin-right:10px;float:right}#wpo_remove_selected_sizes_btn{margin-top:20px}#wp-optimize-nav-tab-contents-tables a{vertical-align:middle}#wpo_sitelist_moreoptions,#wpo_sitelist_moreoptions_cron{margin:4px 16px 6px 0;border:1px dotted;padding:6px 10px;max-height:300px;overflow-y:scroll;overflow-x:hidden}#wpo_sitelist_moreoptions{max-height:150px;margin-right:0}#wpo_settings_sites_list li,#wpo_settings_sites_list li a{font-size:13px;line-height:1.5}#wpo_sitelist_moreoptions_cron li{padding-left:20px}#wpo_import_error_message{display:none;color:#9b0000}#wpo_import_success_message{display:none;color:#46b450}#wp-optimize-logging-options{margin-top:10px}.wpo_logging_header{font-weight:bold;border-top:1px solid #333;border-bottom:1px solid #333;padding:5px 0;margin:0}.wpo_logging_row{border-bottom:1px solid #a1a2a3;padding:5px 0}.wpo_logging_logger_title,.wpo_logging_options_title,.wpo_logging_status_title,.wpo_logging_actions_title,.wpo_logging_logger_row,.wpo_logging_options_row,.wpo_logging_status_row,.wpo_logging_actions_row{display:inline-block}.wpo_logging_logger_title,.wpo_logging_logger_row{width:38%}.wpo_logging_options_title,.wpo_logging_options_row{width:44%}.wpo_logging_status_title,.wpo_logging_status_row{width:8%}.wpo_logging_actions_title,.wpo_logging_actions_row{width:7%}.wpo_logging_actions_row{text-align:right}.wpo_logging_options_row{word-wrap:break-word}#wpo_add_logger_link{clear:both;display:block;cursor:pointer;font-weight:bold}.wpo_logging_actions_row .dashicons-no-alt,.wpo_add_logger_form .dashicons-no-alt{background-color:#f06666;color:#FFF;width:20px;height:20px;border-radius:20px;display:inline-block;cursor:pointer;margin-left:5px}.wpo_add_logger_form .dashicons-no-alt{margin-top:12px;margin-right:10px;float:right}.wpo_logger_type{width:90%;margin-top:10px}.wpo_logger_addition_option{width:100%;margin-top:5px}.wpo_alert_notice{background-color:#f06666;color:#FFF;padding:5px;display:block;margin-bottom:5px;border-radius:5px}.wpo_error_field{border-color:#f06666 !important}.save_settings_reminder{display:none;color:#333;padding:5px 10px;border:1px solid #F00;background-color:#f0a5a4;border-radius:5px;margin:15px 0}.wpo_feature_cont{width:54.5%}.wpo_plugin_family_cont{width:44.5%}.wpo_feat_table,.wpo_feat_th,.wpo_feat_table td{border:1px solid black;border-collapse:collapse;font-size:120%;background-color:white;text-align:center}.wpo_feat_table p{padding:0 10px;margin:5px 0;font-size:16px}.wpo_feat_table h4{margin:5px 0}.wpo_feat_table .dashicons{width:25px;height:25px;font-size:25px;line-height:1}.wpo_feat_table .dashicons-yes,.wpo_feat_table .updraft-yes{color:green}.wpo_feat_table .dashicons-no-alt,.wpo_feat_table .updraft-no{color:red}.wpo-premium-image{display:none}@media screen and (min-width:720px){#wpoptimize_table_list_filter{width:40%}.wpo-premium-image{display:block;float:left;padding:14px 8px;width:50px;height:50px}}.other-plugin-title{text-decoration:none}#wpo_remove_selected_sizes{margin-top:20px}.wpo_unused_images_buttons_wrap{display:none}.wpo_unused_images_container h3{min-width:150px}#wpo_unused_images,#wpo_smush_images_grid{max-height:500px;overflow-y:auto}#wpo_unused_images a{outline:0}
2
  /*# sourceMappingURL=admin.min.css.map */
1
+ .wpo_hidden{display:none}.wpo_info{background:#FFF;color:#444;font-family:-apple-system,"BlinkMacSystemFont","Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif;margin:2em auto;padding:1em 2em;max-width:700px;box-shadow:0 1px 3px rgba(0,0,0,0.13)}.wpo_primary_big{padding:4px 6px !important;font-size:22px !important;min-height:34px;min-width:200px}.wpo_section{clear:both;padding:0;margin:0}.wp-optimize-settings{margin-bottom:16px}.wp-optimize-settings td>label{font-weight:bold;display:block;margin-bottom:8px}.wpo_col{display:block;float:left;margin:1% 0 1% 1%}.wpo_col:first-child{margin-left:0}.wpo_group:before,.wpo_group:after{content:"";display:table}.wpo_group:after{clear:both}.wpo_half_width{width:48%}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:65.3%}.wpo_span_1_of_3{width:32.1%}.nav-tab-wrapper{margin:14px 0}@media screen and (min-width:549px){.show_on_default_sizes{display:block !important}.show_on_mobile_sizes{display:none !important}}@media screen and (max-width:548px){.show_on_default_sizes{display:none !important}.show_on_mobile_sizes{display:block !important}}@media screen and (max-width:768px){.wpo_col{margin:1% 0}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:100%}.wpo_span_1_of_3{width:100%}.wpo_half_width{width:100%}}.wp-optimize-setting-is-sensitive td>label::before{content:"\f534";font-family:'dashicons';display:inline-block;margin-right:6px;font-style:normal;line-height:1;vertical-align:middle;width:20px;font-size:18px;height:20px;text-align:center;color:#72777c}.wpo-run-optimizations__container{margin-bottom:15px}td.wp-optimize-settings-optimization-checkbox{width:18px;padding-left:4px;padding-right:0}.wp-optimize-settings-optimization-checkbox input{margin:0;padding:0}#retention-period{width:60px}.wp-optimize-settings-optimization-info{font-size:80%;font-style:italic}img.addons{display:block;margin-left:auto;margin-right:auto;margin-bottom:20px;max-height:44px;height:auto;max-width:100%}.wpo_spinner{width:18px;height:18px;padding-left:10px;display:none;position:relative;top:4px}.optimization_spinner{width:20px;height:20px}#wp-optimize-auto-options{margin:20px 0 0 28px}.display-none{display:none}.visibility-hidden{visibility:hidden}.margin-one-percent{margin:1%}#save_done,.save-done{color:#d94f00;font-size:250% !important}.wp-optimize-settings-optimization-info a{text-decoration:underline}.wp-optimize-settings-optimization-run-spinner{position:relative;top:2px}@media screen and (min-width:782px){td.wp-optimize-settings-optimization-run{width:180px;padding-top:16px}}#wpoptimize_table_list .tablesorter-filter-row{display:none !important}#wpoptimize_table_list .optimization_spinner{position:relative;top:2px;left:5px}#wpoptimize_table_list .optimization_spinner.visibility-hidden{display:none}#wpoptimize_table_list_filter{width:100%;margin-bottom:15px}#wpoptimize_table_list_tables_not_found{display:none;margin:20px 0}div#wpoptimize_table_list_tables_not_found+h3{margin-top:30px}#optimize_form .select2-container,#wp-optimize-auto-options .select2-container{width:50% !important;top:-5px;height:40px;margin-left:10px}#wpoptimize_table_list .optimization_done_icon{color:#009b24;font-size:200%;display:inline-block;position:relative}#wpo_sitelist_show_moreoptions_cron{font-size:13px;line-height:1.5;letter-spacing:1px}#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3{display:inline-block}.wpo_remove_selected_sizes_btn__container{margin-top:20px}.unused-image-sizes__label{display:block;line-height:1.6}@media(max-width:782px){.unused-image-sizes__label{margin-left:30px;margin-bottom:15px;line-height:1}.unused-image-sizes__label input[type=checkbox]{margin-left:-30px}}#wp-optimize-nav-tab-contents-tables a{vertical-align:middle}#wpo_sitelist_moreoptions,#wpo_sitelist_moreoptions_cron{margin:4px 16px 6px 0;border:1px dotted;padding:6px 10px;max-height:300px;overflow-y:scroll;overflow-x:hidden}#wpo_sitelist_moreoptions{max-height:150px;margin-right:0}#wpo_settings_sites_list li,#wpo_settings_sites_list li a{font-size:13px;line-height:1.5}#wpo_sitelist_moreoptions_cron li{padding-left:20px}#wpo_import_error_message{display:none;color:#9b0000}#wpo_import_success_message{display:none;color:#46b450}#wp-optimize-logging-options{margin-top:10px}.wpo_logging_header{font-weight:bold;border-top:1px solid #333;border-bottom:1px solid #333;padding:5px 0;margin:0}.wpo_logging_row{border-bottom:1px solid #a1a2a3;padding:5px 0}.wpo_logging_logger_title,.wpo_logging_options_title,.wpo_logging_status_title,.wpo_logging_actions_title,.wpo_logging_logger_row,.wpo_logging_options_row,.wpo_logging_status_row,.wpo_logging_actions_row{display:inline-block;vertical-align:middle}.wpo_logging_logger_title,.wpo_logging_logger_row{width:38%}.wpo_logging_options_title,.wpo_logging_options_row{width:44%}.wpo_logging_status_title,.wpo_logging_status_row{width:8%}.wpo_logging_actions_title,.wpo_logging_actions_row{width:7%}.wpo_logging_actions_row{text-align:right}.wpo_logging_options_row{word-wrap:break-word}.wpo_logging_actions_row .dashicons-no-alt,.wpo_add_logger_form .dashicons-no-alt{background-color:#f06666;color:#FFF;width:20px;height:20px;border-radius:20px;display:inline-block;cursor:pointer;margin-left:5px}.wpo_add_logger_form .dashicons-no-alt{margin-top:12px;margin-right:10px;float:right}.wpo_logger_type{width:90%;margin-top:10px}.wpo_logger_addition_option{width:100%;margin-top:5px}.wpo_alert_notice{background-color:#f06666;color:#FFF;padding:5px;display:block;margin-bottom:5px;border-radius:5px}.wpo_error_field{border-color:#f06666 !important}.save_settings_reminder{display:none;color:#333;padding:15px 20px;background-color:#f0a5a4;border-radius:3px;margin:15px 0}#wpo_remove_selected_sizes{margin-top:20px}.wpo_unused_images_buttons_wrap{display:none}.wpo_unused_images_container h3{min-width:150px}#wpo_unused_images,#wpo_smush_images_grid{max-height:500px;overflow-y:auto}#wpo_unused_images a{outline:0}#wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup{margin-left:1%}.run-single-table-delete{margin-top:3px}#wpo_browser_cache_output,#wpo_gzip_compression_output{background:#f0f0f0;padding:10px;border:1px solid #CCC}#wpo_browser_cache_error_message,#wpo_gzip_compression_error_message,.wpo-error{color:#9b0000}#wpo_browser_cache_expire_days,#wpo_browser_cache_expire_hours{width:50px}.wpo-enabled .wpo-disabled{display:none}.wpo-disabled .wpo-enabled{display:none}
2
  /*# sourceMappingURL=admin.min.css.map */
css/admin.min.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["css/admin.css"],"names":[],"mappings":"AAAA;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB,YAAY;CACZ,2IAA2I;CAC3I,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,uCAAuC;CACvC;;AAED,gBAAgB;AAChB;CACC,4BAA4B;CAC5B,2BAA2B;CAC3B,iBAAiB;CACjB,iBAAiB;CACjB;;AAED,gBAAgB;AAChB;CACC,YAAY;CACZ,WAAW;CACX,UAAU;CACV;;AAED;CACC,oBAAoB;CACpB;;AAED,oBAAoB;AACpB;CACC,eAAe;CACf,YAAY;CACZ,mBAAmB;CACnB;;AAED;CACC,eAAe;CACf;;AAED,gBAAgB;AAChB;;CAEC,YAAY;CACZ,eAAe;CACf;;AAED;CACC,YAAY;CACZ;;AAED;CACC,WAAW;CACX;;AAED,qBAAqB;AACrB;CACC,YAAY;CACZ;;AAED;CACC,aAAa;CACb;;AAED;CACC,aAAa;CACb;;AAED;CACC,iBAAiB;CACjB;;AAED;;CAEC;EACC,0BAA0B;EAC1B;;CAED;EACC,yBAAyB;EACzB;;CAED;;AAED;;CAEC;EACC,yBAAyB;EACzB;;CAED;EACC,0BAA0B;EAC1B;;CAED;;AAED;;CAEC;EACC,aAAa;EACb;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,eAAe;CACf;;AAED;CACC,YAAY;CACZ,kBAAkB;CAClB,mBAAmB;CACnB;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,YAAY;CACZ;;AAED;CACC,eAAe;CACf,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,YAAY;CACZ;;AAED,sCAAsC;AACtC;CACC,eAAe;CACf,kBAAkB;CAClB,mBAAmB;CACnB,aAAa;CACb;;AAED;CACC,YAAY;CACZ,aAAa;CACb,mBAAmB;CACnB,cAAc;CACd,mBAAmB;CACnB,SAAS;CACT;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,cAAc;CACd;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,WAAW;CACX;;AAED;CACC,eAAe;CACf,gBAAgB;CAChB;;AAED;CACC,2BAA2B;CAC3B;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT;;AAED;CACC,yBAAyB;CACzB;;AAED;CACC,aAAa;CACb;;AAED;CACC,gBAAgB;CAChB;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT,UAAU;CACV;;AAED;CACC,YAAY;CACZ;;AAED;CACC,cAAc;CACd;;AAED;;CAEC,sBAAsB;CACtB,UAAU;CACV,aAAa;CACb,kBAAkB;CAClB;;AAED;CACC,eAAe;CACf,gBAAgB;CAChB,sBAAsB;CACtB,mBAAmB;CACnB,SAAS;CACT,YAAY;CACZ;;AAED;CACC,gBAAgB;CAChB,iBAAiB;CACjB,oBAAoB;CACpB;;AAED;CACC,mBAAmB;CACnB,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,mBAAmB;CACnB,qCAAqC;CACrC,aAAa;CACb,kBAAkB;CAClB;;AAED;CACC,gBAAgB;CAChB,eAAe;CACf,iBAAiB;CACjB;;AAED;CACC,mBAAmB;CACnB,mBAAmB;CACnB,YAAY;CACZ,YAAY;CACZ;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,iBAAiB;CACjB,mBAAmB;CACnB,aAAa;CACb;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,uBAAuB;CACvB;;AAED;;CAEC,uBAAuB;CACvB,mBAAmB;CACnB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB,gBAAgB;CAChB;;AAED;;CAEC,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED,oBAAoB;AACpB;CACC,kBAAkB;CAClB,2BAA2B;CAC3B,8BAA8B;CAC9B,eAAe;CACf,UAAU;CACV;;AAED;CACC,iCAAiC;CACjC,eAAe;CACf;;AAED;;;;;;;;CAQC,sBAAsB;CACtB;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,UAAU;CACV;;AAED;;CAEC,UAAU;CACV;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,YAAY;CACZ,eAAe;CACf,gBAAgB;CAChB,kBAAkB;CAClB;;AAED;;CAEC,0BAA0B;CAC1B,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,oBAAoB;CACpB,sBAAsB;CACtB,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,iBAAiB;CACjB,mBAAmB;CACnB,aAAa;CACb;;AAED;CACC,WAAW;CACX,iBAAiB;CACjB;;AAED;CACC,YAAY;CACZ,gBAAgB;CAChB;;AAED;CACC,0BAA0B;CAC1B,YAAY;CACZ,aAAa;CACb,eAAe;CACf,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,iCAAiC;CACjC;;AAED;CACC,cAAc;CACd,YAAY;CACZ,kBAAkB;CAClB,uBAAuB;CACvB,0BAA0B;CAC1B,mBAAmB;CACnB,eAAe;CACf;;AAED,wCAAwC;AACxC;CACC,aAAa;CACb;;AAED;CACC,aAAa;CACb;;AAED;CACC,wBAAwB;CACxB,0BAA0B;CAC1B,gBAAgB;CAChB,wBAAwB;CACxB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB,gBAAgB;CAChB,gBAAgB;CAChB;;AAED;CACC,gBAAgB;CAChB;;AAED;CACC,YAAY;CACZ,aAAa;CACb,gBAAgB;CAChB,eAAe;CACf;;AAED;CACC,aAAa;CACb;;AAED;CACC,WAAW;CACX;;AAED;CACC,cAAc;CACd;;AAED;;CAEC;EACC,WAAW;EACX;;CAED;EACC,eAAe;EACf,YAAY;EACZ,kBAAkB;EAClB,YAAY;EACZ,aAAa;EACb;;CAED;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,kBAAkB;CAClB,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd","file":"admin.min.css","sourcesContent":[".wpo_hidden {\n\tdisplay: none;\n}\n\n.wpo_info {\n\tbackground: #FFF;\n\tcolor: #444;\n\tfont-family: -apple-system, \"BlinkMacSystemFont\", \"Segoe UI\", \"Roboto\", \"Oxygen-Sans\", \"Ubuntu\", \"Cantarell\", \"Helvetica Neue\", sans-serif;\n\tmargin: 2em auto;\n\tpadding: 1em 2em;\n\tmax-width: 700px;\n\t-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.13);\n}\n\n/* big button */\n.wpo_primary_big {\n\tpadding: 4px 6px !important;\n\tfont-size: 22px !important;\n\tmin-height: 34px;\n\tmin-width: 200px;\n}\n\n/* SECTIONS */\n.wpo_section {\n\tclear: both;\n\tpadding: 0;\n\tmargin: 0;\n}\n\n.wp-optimize-settings {\n\tmargin-bottom: 16px;\n}\n\n/* COLUMN SETUP */\n.wpo_col {\n\tdisplay: block;\n\tfloat: left;\n\tmargin: 1% 0 1% 1%;\n}\n\n.wpo_col:first-child {\n\tmargin-left: 0;\n}\n\n/* GROUPING */\n.wpo_group:before,\n.wpo_group:after {\n\tcontent: \"\";\n\tdisplay: table;\n}\n\n.wpo_group:after {\n\tclear: both;\n}\n\n.wpo_half_width {\n\twidth: 48%;\n}\n\n/* GRID OF THREE */\n.wpo_span_3_of_3 {\n\twidth: 100%;\n}\n\n.wpo_span_2_of_3 {\n\twidth: 65.3%;\n}\n\n.wpo_span_1_of_3 {\n\twidth: 32.1%;\n}\n\n.nav-tab-wrapper {\n\tmargin: 14px 0px;\n}\n\n@media screen and (min-width: 549px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: block !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: none !important;\n\t}\n\n}\n\n@media screen and (max-width: 548px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: none !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: block !important;\n\t}\n\n}\n\n@media screen and (max-width: 768px) {\n\n\t.wpo_col {\n\t\tmargin: 1% 0;\n\t}\n\n\t.wpo_span_3_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_2_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_1_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_half_width {\n\t\twidth: 100%;\n\t}\n\n}\n\n#select_all_optimizations {\n\tmargin-left: -5px;\n}\n\n.wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label {\n\tcolor: #9B0000;\n}\n\ntd.wp-optimize-settings-optimization-checkbox {\n\twidth: 18px;\n\tpadding-left: 4px;\n\tpadding-right: 0px;\n}\n\n.wp-optimize-settings-optimization-checkbox input {\n\tmargin: 0px;\n\tpadding: 0px;\n}\n\n#retention-period {\n\twidth: 60px;\n}\n\n.wp-optimize-settings-optimization-info {\n\tfont-size: 80%;\n\tpadding-left: 32px;\n\tfont-style: italic;\n}\n\n.wp-optimize-settings input[type=\"checkbox\"] {\n\twidth: 18px;\n}\n\n/* Added for the Image on Addons tab*/\nimg.addons {\n\tdisplay: block;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\theight: 44px;\n}\n\n.wpo_spinner {\n\twidth: 18px;\n\theight: 18px;\n\tpadding-left: 10px;\n\tdisplay: none;\n\tposition: relative;\n\ttop: 4px;\n}\n\n.optimization_spinner {\n\twidth: 20px;\n\theight: 20px;\n}\n\n#wp-optimize-auto-options {\n\tmargin: 20px 0 0 28px;\n}\n\n.display-none {\n\tdisplay: none;\n}\n\n.visibility-hidden {\n\tvisibility: hidden;\n}\n\n.margin-one-percent {\n\tmargin: 1%;\n}\n\n#save_done, .save-done {\n\tcolor: #D94F00;\n\tfont-size: 250%;\n}\n\n.wp-optimize-settings-optimization-info a {\n\ttext-decoration: underline;\n}\n\n.wp-optimize-settings-optimization-run-spinner {\n\tposition: relative;\n\ttop: 2px;\n}\n\n#wpoptimize_table_list .tablesorter-filter-row {\n\tdisplay: none !important;\n}\n\n#wp_optimize_table_list_refresh {\n\tfloat: right;\n}\n\n#wp_optimize_table_list_refresh:hover {\n\tcursor: pointer;\n}\n\n#wpoptimize_table_list .optimization_spinner {\n\tposition: relative;\n\ttop: 5px;\n\tleft: 5px;\n}\n\n#wpoptimize_table_list_filter {\n\twidth: 100%;\n}\n\n#wpoptimize_table_list_tables_not_found {\n\tdisplay: none;\n}\n\n#optimize_form .select2-container,\n#wp-optimize-auto-options .select2-container {\n\twidth: 50% !important;\n\ttop: -5px;\n\theight: 40px;\n\tmargin-left: 10px;\n}\n\n#wpoptimize_table_list .optimization_done_icon {\n\tcolor: #D94F00;\n\tfont-size: 200%;\n\tdisplay: inline-block;\n\tposition: relative;\n\ttop: 5px;\n\tleft: -20px;\n}\n\n#wpo_sitelist_show_moreoptions_cron {\n\tfont-size: 13px;\n\tline-height: 1.5;\n\tletter-spacing: 1px;\n}\n\n.wpo_unused_image, .wpo_smush_image {\n\tposition: relative;\n\tfloat: left;\n\tmargin: .5%;\n\twidth: 32%;\n\ttext-align: center;\n\tbackground: rgba(220, 220, 220, 0.5);\n\theight: 20vh;\n\tmin-height: 200px;\n}\n\n.wpo_unused_image img, .wpo_smush_image img {\n\tmax-height: 80%;\n\tmax-width: 90%;\n\tmargin: 10px 5px;\n}\n\n.wpo_unused_image_checkbox_conatiner {\n\ttext-align: center;\n\tposition: absolute;\n\twidth: 100%;\n\tbottom: 7px;\n}\n\n#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {\n\tdisplay: inline-block;\n}\n\n#wpo_remove_unused_images_btn {\n\tmargin-top: 10px;\n\tmargin-right: 10px;\n\tfloat: right;\n}\n\n#wpo_remove_selected_sizes_btn {\n\tmargin-top: 20px;\n}\n\n#wp-optimize-nav-tab-contents-tables a {\n\tvertical-align: middle;\n}\n\n#wpo_sitelist_moreoptions,\n#wpo_sitelist_moreoptions_cron {\n\tmargin: 4px 16px 6px 0;\n\tborder: 1px dotted;\n\tpadding: 6px 10px;\n\tmax-height: 300px;\n\toverflow-y: scroll;\n\toverflow-x: hidden;\n}\n\n#wpo_sitelist_moreoptions {\n\tmax-height: 150px;\n\tmargin-right: 0;\n}\n\n#wpo_settings_sites_list li,\n#wpo_settings_sites_list li a {\n\tfont-size: 13px;\n\tline-height: 1.5;\n}\n\n#wpo_sitelist_moreoptions_cron li {\n\tpadding-left: 20px;\n}\n\n#wpo_import_error_message {\n\tdisplay: none;\n\tcolor: #9B0000;\n}\n\n#wpo_import_success_message {\n\tdisplay: none;\n\tcolor: #46B450;\n}\n\n#wp-optimize-logging-options {\n\tmargin-top: 10px;\n}\n\n/* Logger settings*/\n.wpo_logging_header {\n\tfont-weight: bold;\n\tborder-top: 1px solid #333;\n\tborder-bottom: 1px solid #333;\n\tpadding: 5px 0;\n\tmargin: 0;\n}\n\n.wpo_logging_row {\n\tborder-bottom: 1px solid #A1A2A3;\n\tpadding: 5px 0;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_options_title,\n.wpo_logging_status_title,\n.wpo_logging_actions_title,\n.wpo_logging_logger_row,\n.wpo_logging_options_row,\n.wpo_logging_status_row,\n.wpo_logging_actions_row {\n\tdisplay: inline-block;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_logger_row {\n\twidth: 38%;\n}\n\n.wpo_logging_options_title,\n.wpo_logging_options_row {\n\twidth: 44%;\n}\n\n.wpo_logging_status_title,\n.wpo_logging_status_row {\n\twidth: 8%;\n}\n\n.wpo_logging_actions_title,\n.wpo_logging_actions_row {\n\twidth: 7%;\n}\n\n.wpo_logging_actions_row {\n\ttext-align: right;\n}\n\n.wpo_logging_options_row {\n\tword-wrap: break-word;\n}\n\n#wpo_add_logger_link {\n\tclear: both;\n\tdisplay: block;\n\tcursor: pointer;\n\tfont-weight: bold;\n}\n\n.wpo_logging_actions_row .dashicons-no-alt,\n.wpo_add_logger_form .dashicons-no-alt {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\twidth: 20px;\n\theight: 20px;\n\tborder-radius: 20px;\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tmargin-left: 5px;\n}\n\n.wpo_add_logger_form .dashicons-no-alt {\n\tmargin-top: 12px;\n\tmargin-right: 10px;\n\tfloat: right;\n}\n\n.wpo_logger_type {\n\twidth: 90%;\n\tmargin-top: 10px;\n}\n\n.wpo_logger_addition_option {\n\twidth: 100%;\n\tmargin-top: 5px;\n}\n\n.wpo_alert_notice {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\tpadding: 5px;\n\tdisplay: block;\n\tmargin-bottom: 5px;\n\tborder-radius: 5px;\n}\n\n.wpo_error_field {\n\tborder-color: #F06666 !important;\n}\n\n.save_settings_reminder {\n\tdisplay: none;\n\tcolor: #333;\n\tpadding: 5px 10px;\n\tborder: 1px solid #F00;\n\tbackground-color: #F0A5A4;\n\tborder-radius: 5px;\n\tmargin: 15px 0;\n}\n\n/* Added for WPO Premium Features tab */\n.wpo_feature_cont {\n\twidth: 54.5%;\n}\n\n.wpo_plugin_family_cont {\n\twidth: 44.5%;\n}\n\n.wpo_feat_table, .wpo_feat_th, .wpo_feat_table td {\n\tborder: 1px solid black;\n\tborder-collapse: collapse;\n\tfont-size: 120%;\n\tbackground-color: white;\n\ttext-align: center;\n}\n\n.wpo_feat_table p {\n\tpadding: 0px 10px;\n\tmargin: 5px 0px;\n\tfont-size: 16px;\n}\n\n.wpo_feat_table h4 {\n\tmargin: 5px 0px;\n}\n\n.wpo_feat_table .dashicons {\n\twidth: 25px;\n\theight: 25px;\n\tfont-size: 25px;\n\tline-height: 1;\n}\n\n.wpo_feat_table .dashicons-yes, .wpo_feat_table .updraft-yes {\n\tcolor: green;\n}\n\n.wpo_feat_table .dashicons-no-alt, .wpo_feat_table .updraft-no {\n\tcolor: red;\n}\n\n.wpo-premium-image {\n\tdisplay: none;\n}\n\n@media screen and (min-width: 720px) {\n\n\t#wpoptimize_table_list_filter {\n\t\twidth: 40%;\n\t}\n\n\t.wpo-premium-image {\n\t\tdisplay: block;\n\t\tfloat: left;\n\t\tpadding: 14px 8px;\n\t\twidth: 50px;\n\t\theight: 50px;\n\t}\n\n}\n\n.other-plugin-title {\n\ttext-decoration: none;\n}\n\n#wpo_remove_selected_sizes {\n\tmargin-top: 20px;\n}\n\n.wpo_unused_images_buttons_wrap {\n\tdisplay: none;\n}\n\n.wpo_unused_images_container h3 {\n\tmin-width: 150px;\n}\n\n#wpo_unused_images, #wpo_smush_images_grid {\n\tmax-height: 500px;\n\toverflow-y: auto;\n}\n\n#wpo_unused_images a {\n\toutline: none;\n}"]}
1
+ {"version":3,"sources":["css/admin.css"],"names":[],"mappings":"AAAA;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB,YAAY;CACZ,2IAA2I;CAC3I,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,uCAAuC;CACvC;;AAED,gBAAgB;AAChB;CACC,4BAA4B;CAC5B,2BAA2B;CAC3B,iBAAiB;CACjB,iBAAiB;CACjB;;AAED,gBAAgB;AAChB;CACC,YAAY;CACZ,WAAW;CACX,UAAU;CACV;;AAED;CACC,oBAAoB;CACpB;;AAED;CACC,kBAAkB;CAClB,eAAe;CACf,mBAAmB;CACnB;;AAED,oBAAoB;AACpB;CACC,eAAe;CACf,YAAY;CACZ,mBAAmB;CACnB;;AAED;CACC,eAAe;CACf;;AAED,gBAAgB;AAChB;;CAEC,YAAY;CACZ,eAAe;CACf;;AAED;CACC,YAAY;CACZ;;AAED;CACC,WAAW;CACX;;AAED,qBAAqB;AACrB;CACC,YAAY;CACZ;;AAED;CACC,aAAa;CACb;;AAED;CACC,aAAa;CACb;;AAED;CACC,iBAAiB;CACjB;;AAED;;CAEC;EACC,0BAA0B;EAC1B;;CAED;EACC,yBAAyB;EACzB;;CAED;;AAED;;CAEC;EACC,yBAAyB;EACzB;;CAED;EACC,0BAA0B;EAC1B;;CAED;;AAED;;CAEC;EACC,aAAa;EACb;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;;AAED,qRAAqR;;AAErR;CACC,iBAAiB;CACjB,yBAAyB;CACzB,sBAAsB;CACtB,kBAAkB;CAClB,mBAAmB;CACnB,eAAe;CACf,uBAAuB;CACvB,YAAY;CACZ,gBAAgB;CAChB,aAAa;CACb,mBAAmB;CACnB,eAAe;CACf;;AAED;CACC,oBAAoB;CACpB;;AAED;CACC,YAAY;CACZ,kBAAkB;CAClB,mBAAmB;CACnB;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,YAAY;CACZ;;AAED;CACC,eAAe;CACf,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB;;AAED,sCAAsC;AACtC;CACC,eAAe;CACf,kBAAkB;CAClB,mBAAmB;CACnB,oBAAoB;CACpB,iBAAiB;CACjB,aAAa;CACb,gBAAgB;CAChB;;AAED;CACC,YAAY;CACZ,aAAa;CACb,mBAAmB;CACnB,cAAc;CACd,mBAAmB;CACnB,SAAS;CACT;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,cAAc;CACd;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,WAAW;CACX;;AAED;CACC,eAAe;CACf,2BAA2B;CAC3B;;AAED;CACC,2BAA2B;CAC3B;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT;;AAED;;CAEC;EACC,aAAa;EACb,kBAAkB;EAClB;;CAED;;AAED;CACC,yBAAyB;CACzB;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT,UAAU;CACV;;AAED;CACC,cAAc;CACd;;AAED;CACC,YAAY;CACZ,oBAAoB;CACpB;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED;;CAEC,sBAAsB;CACtB,UAAU;CACV,aAAa;CACb,kBAAkB;CAClB;;AAED;CACC,eAAe;CACf,gBAAgB;CAChB,sBAAsB;CACtB,mBAAmB;CACnB;;AAED;CACC,gBAAgB;CAChB,iBAAiB;CACjB,oBAAoB;CACpB;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,eAAe;CACf,iBAAiB;CACjB;;AAED;;CAEC;EACC,kBAAkB;EAClB,oBAAoB;EACpB,eAAe;EACf;;CAED;EACC,mBAAmB;EACnB;;CAED;;AAED;CACC,uBAAuB;CACvB;;AAED;;CAEC,uBAAuB;CACvB,mBAAmB;CACnB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB,gBAAgB;CAChB;;AAED;;CAEC,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED,oBAAoB;AACpB;CACC,kBAAkB;CAClB,2BAA2B;CAC3B,8BAA8B;CAC9B,eAAe;CACf,UAAU;CACV;;AAED;CACC,iCAAiC;CACjC,eAAe;CACf;;AAED;;;;;;;;CAQC,sBAAsB;CACtB,uBAAuB;CACvB;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,UAAU;CACV;;AAED;;CAEC,UAAU;CACV;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,sBAAsB;CACtB;;AAED;;CAEC,0BAA0B;CAC1B,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,oBAAoB;CACpB,sBAAsB;CACtB,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,iBAAiB;CACjB,mBAAmB;CACnB,aAAa;CACb;;AAED;CACC,WAAW;CACX,iBAAiB;CACjB;;AAED;CACC,YAAY;CACZ,gBAAgB;CAChB;;AAED;CACC,0BAA0B;CAC1B,YAAY;CACZ,aAAa;CACb,eAAe;CACf,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,iCAAiC;CACjC;;AAED;CACC,cAAc;CACd,YAAY;CACZ,mBAAmB;CACnB,0BAA0B;CAC1B,mBAAmB;CACnB,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,kBAAkB;CAClB,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd;;AAED;CACC,gBAAgB;CAChB;;AAED;CACC,gBAAgB;CAChB;;AAED;;CAEC,oBAAoB;CACpB,cAAc;CACd,uBAAuB;CACvB;;AAED;;;CAGC,eAAe;CACf;;AAED;;CAEC,YAAY;CACZ;;AAED;CACC,cAAc;CACd;;AAED;CACC,cAAc;CACd","file":"admin.min.css","sourcesContent":[".wpo_hidden {\n\tdisplay: none;\n}\n\n.wpo_info {\n\tbackground: #FFF;\n\tcolor: #444;\n\tfont-family: -apple-system, \"BlinkMacSystemFont\", \"Segoe UI\", \"Roboto\", \"Oxygen-Sans\", \"Ubuntu\", \"Cantarell\", \"Helvetica Neue\", sans-serif;\n\tmargin: 2em auto;\n\tpadding: 1em 2em;\n\tmax-width: 700px;\n\t-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.13);\n}\n\n/* big button */\n.wpo_primary_big {\n\tpadding: 4px 6px !important;\n\tfont-size: 22px !important;\n\tmin-height: 34px;\n\tmin-width: 200px;\n}\n\n/* SECTIONS */\n.wpo_section {\n\tclear: both;\n\tpadding: 0;\n\tmargin: 0;\n}\n\n.wp-optimize-settings {\n\tmargin-bottom: 16px;\n}\n\n.wp-optimize-settings td > label {\n\tfont-weight: bold;\n\tdisplay: block;\n\tmargin-bottom: 8px;\n}\n\n/* COLUMN SETUP */\n.wpo_col {\n\tdisplay: block;\n\tfloat: left;\n\tmargin: 1% 0 1% 1%;\n}\n\n.wpo_col:first-child {\n\tmargin-left: 0;\n}\n\n/* GROUPING */\n.wpo_group:before,\n.wpo_group:after {\n\tcontent: \"\";\n\tdisplay: table;\n}\n\n.wpo_group:after {\n\tclear: both;\n}\n\n.wpo_half_width {\n\twidth: 48%;\n}\n\n/* GRID OF THREE */\n.wpo_span_3_of_3 {\n\twidth: 100%;\n}\n\n.wpo_span_2_of_3 {\n\twidth: 65.3%;\n}\n\n.wpo_span_1_of_3 {\n\twidth: 32.1%;\n}\n\n.nav-tab-wrapper {\n\tmargin: 14px 0px;\n}\n\n@media screen and (min-width: 549px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: block !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: none !important;\n\t}\n\n}\n\n@media screen and (max-width: 548px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: none !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: block !important;\n\t}\n\n}\n\n@media screen and (max-width: 768px) {\n\n\t.wpo_col {\n\t\tmargin: 1% 0;\n\t}\n\n\t.wpo_span_3_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_2_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_1_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_half_width {\n\t\twidth: 100%;\n\t}\n\n}\n\n/* .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label */\n\n.wp-optimize-setting-is-sensitive td > label::before {\n\tcontent: \"\\f534\";\n\tfont-family: 'dashicons';\n\tdisplay: inline-block;\n\tmargin-right: 6px;\n\tfont-style: normal;\n\tline-height: 1;\n\tvertical-align: middle;\n\twidth: 20px;\n\tfont-size: 18px;\n\theight: 20px;\n\ttext-align: center;\n\tcolor: #72777C;\n}\n\n.wpo-run-optimizations__container {\n\tmargin-bottom: 15px;\n}\n\ntd.wp-optimize-settings-optimization-checkbox {\n\twidth: 18px;\n\tpadding-left: 4px;\n\tpadding-right: 0px;\n}\n\n.wp-optimize-settings-optimization-checkbox input {\n\tmargin: 0px;\n\tpadding: 0px;\n}\n\n#retention-period {\n\twidth: 60px;\n}\n\n.wp-optimize-settings-optimization-info {\n\tfont-size: 80%;\n\tfont-style: italic;\n}\n\n.wp-optimize-settings input[type=\"checkbox\"] {\n\t/* width: 18px; */\n}\n\n/* Added for the Image on Addons tab*/\nimg.addons {\n\tdisplay: block;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tmargin-bottom: 20px;\n\tmax-height: 44px;\n\theight: auto;\n\tmax-width: 100%;\n}\n\n.wpo_spinner {\n\twidth: 18px;\n\theight: 18px;\n\tpadding-left: 10px;\n\tdisplay: none;\n\tposition: relative;\n\ttop: 4px;\n}\n\n.optimization_spinner {\n\twidth: 20px;\n\theight: 20px;\n}\n\n#wp-optimize-auto-options {\n\tmargin: 20px 0 0 28px;\n}\n\n.display-none {\n\tdisplay: none;\n}\n\n.visibility-hidden {\n\tvisibility: hidden;\n}\n\n.margin-one-percent {\n\tmargin: 1%;\n}\n\n#save_done, .save-done {\n\tcolor: #D94F00;\n\tfont-size: 250% !important;\n}\n\n.wp-optimize-settings-optimization-info a {\n\ttext-decoration: underline;\n}\n\n.wp-optimize-settings-optimization-run-spinner {\n\tposition: relative;\n\ttop: 2px;\n}\n\n@media screen and (min-width: 782px) {\n\n\ttd.wp-optimize-settings-optimization-run {\n\t\twidth: 180px;\n\t\tpadding-top: 16px;\n\t}\n\n}\n\n#wpoptimize_table_list .tablesorter-filter-row {\n\tdisplay: none !important;\n}\n\n#wpoptimize_table_list .optimization_spinner {\n\tposition: relative;\n\ttop: 2px;\n\tleft: 5px;\n}\n\n#wpoptimize_table_list .optimization_spinner.visibility-hidden {\n\tdisplay: none;\n}\n\n#wpoptimize_table_list_filter {\n\twidth: 100%;\n\tmargin-bottom: 15px;\n}\n\n#wpoptimize_table_list_tables_not_found {\n\tdisplay: none;\n\tmargin: 20px 0;\n}\n\ndiv#wpoptimize_table_list_tables_not_found + h3 {\n\tmargin-top: 30px;\n}\n\n#optimize_form .select2-container,\n#wp-optimize-auto-options .select2-container {\n\twidth: 50% !important;\n\ttop: -5px;\n\theight: 40px;\n\tmargin-left: 10px;\n}\n\n#wpoptimize_table_list .optimization_done_icon {\n\tcolor: #009B24;\n\tfont-size: 200%;\n\tdisplay: inline-block;\n\tposition: relative;\n}\n\n#wpo_sitelist_show_moreoptions_cron {\n\tfont-size: 13px;\n\tline-height: 1.5;\n\tletter-spacing: 1px;\n}\n\n#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {\n\tdisplay: inline-block;\n}\n\n.wpo_remove_selected_sizes_btn__container {\n\tmargin-top: 20px;\n}\n\n.unused-image-sizes__label {\n\tdisplay: block;\n\tline-height: 1.6;\n}\n\n@media (max-width: 782px) {\n\n\t.unused-image-sizes__label {\n\t\tmargin-left: 30px;\n\t\tmargin-bottom: 15px;\n\t\tline-height: 1;\n\t}\n\n\t.unused-image-sizes__label input[type=checkbox] {\n\t\tmargin-left: -30px;\n\t}\n\n}\n\n#wp-optimize-nav-tab-contents-tables a {\n\tvertical-align: middle;\n}\n\n#wpo_sitelist_moreoptions,\n#wpo_sitelist_moreoptions_cron {\n\tmargin: 4px 16px 6px 0;\n\tborder: 1px dotted;\n\tpadding: 6px 10px;\n\tmax-height: 300px;\n\toverflow-y: scroll;\n\toverflow-x: hidden;\n}\n\n#wpo_sitelist_moreoptions {\n\tmax-height: 150px;\n\tmargin-right: 0;\n}\n\n#wpo_settings_sites_list li,\n#wpo_settings_sites_list li a {\n\tfont-size: 13px;\n\tline-height: 1.5;\n}\n\n#wpo_sitelist_moreoptions_cron li {\n\tpadding-left: 20px;\n}\n\n#wpo_import_error_message {\n\tdisplay: none;\n\tcolor: #9B0000;\n}\n\n#wpo_import_success_message {\n\tdisplay: none;\n\tcolor: #46B450;\n}\n\n#wp-optimize-logging-options {\n\tmargin-top: 10px;\n}\n\n/* Logger settings*/\n.wpo_logging_header {\n\tfont-weight: bold;\n\tborder-top: 1px solid #333;\n\tborder-bottom: 1px solid #333;\n\tpadding: 5px 0;\n\tmargin: 0;\n}\n\n.wpo_logging_row {\n\tborder-bottom: 1px solid #A1A2A3;\n\tpadding: 5px 0;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_options_title,\n.wpo_logging_status_title,\n.wpo_logging_actions_title,\n.wpo_logging_logger_row,\n.wpo_logging_options_row,\n.wpo_logging_status_row,\n.wpo_logging_actions_row {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_logger_row {\n\twidth: 38%;\n}\n\n.wpo_logging_options_title,\n.wpo_logging_options_row {\n\twidth: 44%;\n}\n\n.wpo_logging_status_title,\n.wpo_logging_status_row {\n\twidth: 8%;\n}\n\n.wpo_logging_actions_title,\n.wpo_logging_actions_row {\n\twidth: 7%;\n}\n\n.wpo_logging_actions_row {\n\ttext-align: right;\n}\n\n.wpo_logging_options_row {\n\tword-wrap: break-word;\n}\n\n.wpo_logging_actions_row .dashicons-no-alt,\n.wpo_add_logger_form .dashicons-no-alt {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\twidth: 20px;\n\theight: 20px;\n\tborder-radius: 20px;\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tmargin-left: 5px;\n}\n\n.wpo_add_logger_form .dashicons-no-alt {\n\tmargin-top: 12px;\n\tmargin-right: 10px;\n\tfloat: right;\n}\n\n.wpo_logger_type {\n\twidth: 90%;\n\tmargin-top: 10px;\n}\n\n.wpo_logger_addition_option {\n\twidth: 100%;\n\tmargin-top: 5px;\n}\n\n.wpo_alert_notice {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\tpadding: 5px;\n\tdisplay: block;\n\tmargin-bottom: 5px;\n\tborder-radius: 5px;\n}\n\n.wpo_error_field {\n\tborder-color: #F06666 !important;\n}\n\n.save_settings_reminder {\n\tdisplay: none;\n\tcolor: #333;\n\tpadding: 15px 20px;\n\tbackground-color: #F0A5A4;\n\tborder-radius: 3px;\n\tmargin: 15px 0;\n}\n\n#wpo_remove_selected_sizes {\n\tmargin-top: 20px;\n}\n\n.wpo_unused_images_buttons_wrap {\n\tdisplay: none;\n}\n\n.wpo_unused_images_container h3 {\n\tmin-width: 150px;\n}\n\n#wpo_unused_images, #wpo_smush_images_grid {\n\tmax-height: 500px;\n\toverflow-y: auto;\n}\n\n#wpo_unused_images a {\n\toutline: none;\n}\n\n#wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup {\n\tmargin-left: 1%;\n}\n\n.run-single-table-delete {\n\tmargin-top: 3px;\n}\n\n#wpo_browser_cache_output,\n#wpo_gzip_compression_output {\n\tbackground: #F0F0F0;\n\tpadding: 10px;\n\tborder: 1px solid #CCC;\n}\n\n#wpo_browser_cache_error_message,\n#wpo_gzip_compression_error_message,\n.wpo-error {\n\tcolor: #9B0000;\n}\n\n#wpo_browser_cache_expire_days,\n#wpo_browser_cache_expire_hours {\n\twidth: 50px;\n}\n\n.wpo-enabled .wpo-disabled {\n\tdisplay: none;\n}\n\n.wpo-disabled .wpo-enabled {\n\tdisplay: none;\n}"]}
css/wp-optimize-admin.css ADDED
@@ -0,0 +1,1674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* COLORS */
2
+
3
+ /* OTHER VARS */
4
+
5
+ .wpo_hidden {
6
+ display: none;
7
+ }
8
+
9
+ .wpo_info {
10
+ background: #FFF;
11
+ color: #444;
12
+ font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif;
13
+ margin: 2em auto;
14
+ padding: 1em 2em;
15
+ max-width: 700px;
16
+ box-shadow: 0 1px 3px rgba(0,0,0,0.13);
17
+ }
18
+
19
+ /* big button */
20
+
21
+ .wpo_primary_big {
22
+ padding: 4px 6px !important;
23
+ font-size: 22px !important;
24
+ min-height: 34px;
25
+ min-width: 200px;
26
+ }
27
+
28
+ /* SECTIONS */
29
+
30
+ .wpo_section {
31
+ clear: both;
32
+ padding: 0;
33
+ margin: 0;
34
+ }
35
+
36
+ .wp-optimize-settings {
37
+ margin-bottom: 16px;
38
+ }
39
+
40
+ .wp-optimize-settings td > label {
41
+ font-weight: bold;
42
+ display: block;
43
+ margin-bottom: 8px;
44
+ }
45
+
46
+ /* COLUMN SETUP */
47
+
48
+ .wpo_col {
49
+ display: block;
50
+ float: left;
51
+ margin: 1% 0 1% 1%;
52
+ }
53
+
54
+ .wpo_col:first-child {
55
+ margin-left: 0;
56
+ }
57
+
58
+ /* GROUPING */
59
+
60
+ .wpo_group:before,
61
+ .wpo_group:after {
62
+ content: "";
63
+ display: table;
64
+ }
65
+
66
+ .wpo_group:after {
67
+ clear: both;
68
+ }
69
+
70
+ .wpo_half_width {
71
+ width: 48%;
72
+ }
73
+
74
+ /* GRID OF THREE */
75
+
76
+ .wpo_span_3_of_3 {
77
+ width: 100%;
78
+ }
79
+
80
+ .wpo_span_2_of_3 {
81
+ width: 65.3%;
82
+ }
83
+
84
+ .wpo_span_1_of_3 {
85
+ width: 32.1%;
86
+ }
87
+
88
+ .nav-tab-wrapper {
89
+ margin: 14px 0px;
90
+ }
91
+
92
+ @media screen and (min-width: 549px) {
93
+
94
+ .show_on_default_sizes {
95
+ display: block !important;
96
+ }
97
+
98
+ .show_on_mobile_sizes {
99
+ display: none !important;
100
+ }
101
+
102
+ }
103
+
104
+ @media screen and (max-width: 548px) {
105
+
106
+ .show_on_default_sizes {
107
+ display: none !important;
108
+ }
109
+
110
+ .show_on_mobile_sizes {
111
+ display: block !important;
112
+ }
113
+
114
+ }
115
+
116
+ @media screen and (max-width: 768px) {
117
+
118
+ .wpo_col {
119
+ margin: 1% 0;
120
+ }
121
+
122
+ .wpo_span_3_of_3 {
123
+ width: 100%;
124
+ }
125
+
126
+ .wpo_span_2_of_3 {
127
+ width: 100%;
128
+ }
129
+
130
+ .wpo_span_1_of_3 {
131
+ width: 100%;
132
+ }
133
+
134
+ .wpo_half_width {
135
+ width: 100%;
136
+ }
137
+
138
+ }
139
+
140
+ /* .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label */
141
+
142
+ .wp-optimize-setting-is-sensitive td > label::before {
143
+ content: "\f534";
144
+ font-family: 'dashicons';
145
+ display: inline-block;
146
+ margin-right: 6px;
147
+ font-style: normal;
148
+ line-height: 1;
149
+ vertical-align: middle;
150
+ width: 20px;
151
+ font-size: 18px;
152
+ height: 20px;
153
+ text-align: center;
154
+ color: #72777C;
155
+ }
156
+
157
+ .wpo-run-optimizations__container {
158
+ margin-bottom: 15px;
159
+ }
160
+
161
+ td.wp-optimize-settings-optimization-checkbox {
162
+ width: 18px;
163
+ padding-left: 4px;
164
+ padding-right: 0px;
165
+ }
166
+
167
+ .wp-optimize-settings-optimization-checkbox input {
168
+ margin: 0px;
169
+ padding: 0px;
170
+ }
171
+
172
+ #retention-period {
173
+ width: 60px;
174
+ }
175
+
176
+ .wp-optimize-settings-optimization-info {
177
+ font-size: 80%;
178
+ font-style: italic;
179
+ }
180
+
181
+ .wp-optimize-settings input[type="checkbox"] {
182
+ /* width: 18px; */
183
+ }
184
+
185
+ /* Added for the Image on Addons tab*/
186
+
187
+ img.addons {
188
+ display: block;
189
+ margin-left: auto;
190
+ margin-right: auto;
191
+ margin-bottom: 20px;
192
+ max-height: 44px;
193
+ height: auto;
194
+ max-width: 100%;
195
+ }
196
+
197
+ .wpo_spinner {
198
+ width: 18px;
199
+ height: 18px;
200
+ padding-left: 10px;
201
+ display: none;
202
+ position: relative;
203
+ top: 4px;
204
+ }
205
+
206
+ .optimization_spinner {
207
+ width: 20px;
208
+ height: 20px;
209
+ }
210
+
211
+ #wp-optimize-auto-options {
212
+ margin: 20px 0 0 28px;
213
+ }
214
+
215
+ .display-none {
216
+ display: none;
217
+ }
218
+
219
+ .visibility-hidden {
220
+ visibility: hidden;
221
+ }
222
+
223
+ .margin-one-percent {
224
+ margin: 1%;
225
+ }
226
+
227
+ #save_done, .save-done {
228
+ color: #D94F00;
229
+ font-size: 250% !important;
230
+ }
231
+
232
+ .wp-optimize-settings-optimization-info a {
233
+ text-decoration: underline;
234
+ }
235
+
236
+ .wp-optimize-settings-optimization-run-spinner {
237
+ position: relative;
238
+ top: 2px;
239
+ }
240
+
241
+ @media screen and (min-width: 782px) {
242
+
243
+ td.wp-optimize-settings-optimization-run {
244
+ width: 180px;
245
+ padding-top: 16px;
246
+ }
247
+
248
+ }
249
+
250
+ #wpoptimize_table_list .tablesorter-filter-row {
251
+ display: none !important;
252
+ }
253
+
254
+ #wpoptimize_table_list .optimization_spinner {
255
+ position: relative;
256
+ top: 2px;
257
+ left: 5px;
258
+ }
259
+
260
+ #wpoptimize_table_list .optimization_spinner.visibility-hidden {
261
+ display: none;
262
+ }
263
+
264
+ #wpoptimize_table_list_filter {
265
+ width: 100%;
266
+ margin-bottom: 15px;
267
+ }
268
+
269
+ #wpoptimize_table_list_tables_not_found {
270
+ display: none;
271
+ margin: 20px 0;
272
+ }
273
+
274
+ div#wpoptimize_table_list_tables_not_found + h3 {
275
+ margin-top: 30px;
276
+ }
277
+
278
+ #optimize_form .select2-container,
279
+ #wp-optimize-auto-options .select2-container {
280
+ width: 50% !important;
281
+ top: -5px;
282
+ height: 40px;
283
+ margin-left: 10px;
284
+ }
285
+
286
+ #wpoptimize_table_list .optimization_done_icon {
287
+ color: #009B24;
288
+ font-size: 200%;
289
+ display: inline-block;
290
+ position: relative;
291
+ }
292
+
293
+ #wpo_sitelist_show_moreoptions_cron {
294
+ font-size: 13px;
295
+ line-height: 1.5;
296
+ letter-spacing: 1px;
297
+ }
298
+
299
+ #wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {
300
+ display: inline-block;
301
+ }
302
+
303
+ .wpo_remove_selected_sizes_btn__container {
304
+ margin-top: 20px;
305
+ }
306
+
307
+ .unused-image-sizes__label {
308
+ display: block;
309
+ line-height: 1.6;
310
+ }
311
+
312
+ @media (max-width: 782px) {
313
+
314
+ .unused-image-sizes__label {
315
+ margin-left: 30px;
316
+ margin-bottom: 15px;
317
+ line-height: 1;
318
+ }
319
+
320
+ .unused-image-sizes__label input[type=checkbox] {
321
+ margin-left: -30px;
322
+ }
323
+
324
+ }
325
+
326
+ #wp-optimize-nav-tab-contents-tables a {
327
+ vertical-align: middle;
328
+ }
329
+
330
+ #wpo_sitelist_moreoptions,
331
+ #wpo_sitelist_moreoptions_cron {
332
+ margin: 4px 16px 6px 0;
333
+ border: 1px dotted;
334
+ padding: 6px 10px;
335
+ max-height: 300px;
336
+ overflow-y: scroll;
337
+ overflow-x: hidden;
338
+ }
339
+
340
+ #wpo_sitelist_moreoptions {
341
+ max-height: 150px;
342
+ margin-right: 0;
343
+ }
344
+
345
+ #wpo_settings_sites_list li,
346
+ #wpo_settings_sites_list li a {
347
+ font-size: 13px;
348
+ line-height: 1.5;
349
+ }
350
+
351
+ #wpo_sitelist_moreoptions_cron li {
352
+ padding-left: 20px;
353
+ }
354
+
355
+ #wpo_import_error_message {
356
+ display: none;
357
+ color: #9B0000;
358
+ }
359
+
360
+ #wpo_import_success_message {
361
+ display: none;
362
+ color: #46B450;
363
+ }
364
+
365
+ #wp-optimize-logging-options {
366
+ margin-top: 10px;
367
+ }
368
+
369
+ /* Logger settings*/
370
+
371
+ .wpo_logging_header {
372
+ font-weight: bold;
373
+ border-top: 1px solid #333;
374
+ border-bottom: 1px solid #333;
375
+ padding: 5px 0;
376
+ margin: 0;
377
+ }
378
+
379
+ .wpo_logging_row {
380
+ border-bottom: 1px solid #A1A2A3;
381
+ padding: 5px 0;
382
+ }
383
+
384
+ .wpo_logging_logger_title,
385
+ .wpo_logging_options_title,
386
+ .wpo_logging_status_title,
387
+ .wpo_logging_actions_title,
388
+ .wpo_logging_logger_row,
389
+ .wpo_logging_options_row,
390
+ .wpo_logging_status_row,
391
+ .wpo_logging_actions_row {
392
+ display: inline-block;
393
+ vertical-align: middle;
394
+ }
395
+
396
+ .wpo_logging_logger_title,
397
+ .wpo_logging_logger_row {
398
+ width: 38%;
399
+ }
400
+
401
+ .wpo_logging_options_title,
402
+ .wpo_logging_options_row {
403
+ width: 44%;
404
+ }
405
+
406
+ .wpo_logging_status_title,
407
+ .wpo_logging_status_row {
408
+ width: 8%;
409
+ }
410
+
411
+ .wpo_logging_actions_title,
412
+ .wpo_logging_actions_row {
413
+ width: 7%;
414
+ }
415
+
416
+ .wpo_logging_actions_row {
417
+ text-align: right;
418
+ }
419
+
420
+ .wpo_logging_options_row {
421
+ word-wrap: break-word;
422
+ }
423
+
424
+ .wpo_logging_actions_row .dashicons-no-alt,
425
+ .wpo_add_logger_form .dashicons-no-alt {
426
+ background-color: #F06666;
427
+ color: #FFF;
428
+ width: 20px;
429
+ height: 20px;
430
+ border-radius: 20px;
431
+ display: inline-block;
432
+ cursor: pointer;
433
+ margin-left: 5px;
434
+ }
435
+
436
+ .wpo_add_logger_form .dashicons-no-alt {
437
+ margin-top: 12px;
438
+ margin-right: 10px;
439
+ float: right;
440
+ }
441
+
442
+ .wpo_logger_type {
443
+ width: 90%;
444
+ margin-top: 10px;
445
+ }
446
+
447
+ .wpo_logger_addition_option {
448
+ width: 100%;
449
+ margin-top: 5px;
450
+ }
451
+
452
+ .wpo_alert_notice {
453
+ background-color: #F06666;
454
+ color: #FFF;
455
+ padding: 5px;
456
+ display: block;
457
+ margin-bottom: 5px;
458
+ border-radius: 5px;
459
+ }
460
+
461
+ .wpo_error_field {
462
+ border-color: #F06666 !important;
463
+ }
464
+
465
+ .save_settings_reminder {
466
+ display: none;
467
+ color: #333;
468
+ padding: 15px 20px;
469
+ background-color: #F0A5A4;
470
+ border-radius: 3px;
471
+ margin: 15px 0;
472
+ }
473
+
474
+ #wpo_remove_selected_sizes {
475
+ margin-top: 20px;
476
+ }
477
+
478
+ .wpo_unused_images_buttons_wrap {
479
+ display: none;
480
+ }
481
+
482
+ .wpo_unused_images_container h3 {
483
+ min-width: 150px;
484
+ }
485
+
486
+ #wpo_unused_images, #wpo_smush_images_grid {
487
+ max-height: 500px;
488
+ overflow-y: auto;
489
+ }
490
+
491
+ #wpo_unused_images a {
492
+ outline: none;
493
+ }
494
+
495
+ #wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup {
496
+ margin-left: 1%;
497
+ }
498
+
499
+ .run-single-table-delete {
500
+ margin-top: 3px;
501
+ }
502
+
503
+ #wpo_browser_cache_output,
504
+ #wpo_gzip_compression_output {
505
+ background: #F0F0F0;
506
+ padding: 10px;
507
+ border: 1px solid #CCC;
508
+ }
509
+
510
+ #wpo_browser_cache_error_message,
511
+ #wpo_gzip_compression_error_message,
512
+ .wpo-error {
513
+ color: #9B0000;
514
+ }
515
+
516
+ #wpo_browser_cache_expire_days,
517
+ #wpo_browser_cache_expire_hours {
518
+ width: 50px;
519
+ }
520
+
521
+ .wpo-enabled .wpo-disabled {
522
+ display: none;
523
+ }
524
+
525
+ .wpo-disabled .wpo-enabled {
526
+ display: none;
527
+ }
528
+
529
+ #wp-optimize-wrap {
530
+ position: relative;
531
+ padding-top: 100px;
532
+
533
+ }
534
+
535
+ @media (min-width: 820px) {
536
+
537
+ #wp-optimize-wrap {
538
+ padding-top: 120px;
539
+ }
540
+ }
541
+
542
+ @media (max-width: 782px) {
543
+
544
+ #wp-optimize-wrap {
545
+ margin-right: 0;
546
+ }
547
+ }
548
+
549
+ /* DASHBOARD */
550
+
551
+ .wpo-main-header {
552
+
553
+ height: 77px;
554
+ position: fixed;
555
+ top: 32px;
556
+ left: 160px;
557
+ background: #FFF;
558
+ right: 0;
559
+ z-index: 9980;
560
+ }
561
+
562
+ @media (min-width: 820px) {
563
+
564
+ .wpo-main-header {
565
+ height: 105px;
566
+ }
567
+ }
568
+
569
+ .wpo-main-header .wpo-logo__container {
570
+ display: -ms-flexbox;
571
+ display: flex;
572
+ -ms-flex-direction: column;
573
+ flex-direction: column;
574
+ -ms-flex-pack: center;
575
+ justify-content: center;
576
+ position: relative;
577
+ height: 100%;
578
+ line-height: 1;
579
+ font-size: 1rem;
580
+ padding-left: 50px;
581
+ margin-left: 10px;
582
+ }
583
+
584
+ .wpo-main-header .wpo-logo {
585
+ position: absolute;
586
+ left: 0;
587
+ top: 50%;
588
+ transform: translateY(-50%);
589
+ width: 50px;
590
+ }
591
+
592
+ .wpo-main-header .wpo-subheader {
593
+ margin: 0;
594
+ font-weight: 300;
595
+ color: #72777C;
596
+ line-height: 1.3;
597
+ }
598
+
599
+ @media (max-width: 1080px) {
600
+
601
+ .wpo-main-header .wpo-subheader {
602
+ display: none;
603
+ }
604
+ }
605
+
606
+ .wpo-main-header p.wpo-header-links {
607
+ margin: 0;
608
+ font-size: 0.7rem;
609
+ position: absolute;
610
+ right: 0;
611
+ padding: 6px 15px;
612
+ background: #EDEEEF;
613
+ border-bottom-left-radius: 5px;
614
+ z-index: 1;
615
+ }
616
+
617
+ .wpo-main-header p.wpo-header-links a {
618
+ text-decoration: none;
619
+ }
620
+
621
+ .wpo-main-header p.wpo-header-links .wpo-header-links__label {
622
+ color: #82868B;
623
+ position: absolute;
624
+ right: 100%;
625
+ width: 110px;
626
+ text-align: right;
627
+ padding-right: 10px;
628
+ }
629
+
630
+ @media (max-width: 820px) {
631
+
632
+ .wpo-main-header p.wpo-header-links {
633
+ display: none;
634
+ }
635
+ }
636
+
637
+ .wpo-main-header p.wpo-header-links__mobile {
638
+ padding: 10px;
639
+ background: #EDEEEF;
640
+ margin-bottom: 0;
641
+ }
642
+
643
+ @media (min-width: 820px) {
644
+
645
+ .wpo-main-header p.wpo-header-links__mobile {
646
+ display: none;
647
+ }
648
+ }
649
+
650
+ .wpo-main-header p.wpo-header-links__mobile a {
651
+ display: inline-block;
652
+ padding: 4px;
653
+ font-size: .8rem;
654
+ }
655
+
656
+ .wpo-main-header p.wpo-header-links__mobile .wpo-header-links__label {
657
+ color: #82868B;
658
+ }
659
+
660
+ @media (max-width: 600px) {
661
+
662
+ .wpo-main-header .wpo-logo__container strong {
663
+ width: 140px;
664
+ display: inline-block;
665
+ }
666
+ }
667
+
668
+ @media (max-width: 960px) {
669
+
670
+ body.auto-fold .wpo-main-header {
671
+ left: 36px;
672
+ }
673
+ }
674
+
675
+ @media (max-width: 782px) {
676
+
677
+ body.auto-fold .wpo-main-header {
678
+ left: 0;
679
+ top: 46px;
680
+ }
681
+ }
682
+
683
+ @media (max-width: 600px) {
684
+
685
+ body.auto-fold .wpo-main-header {
686
+ position: absolute;
687
+ left: -10px;
688
+ right: -10px;
689
+ top: 0;
690
+ }
691
+ }
692
+
693
+ @media (min-width: 782px) {
694
+
695
+ body.folded .wpo-main-header {
696
+ left: 36px;
697
+ }
698
+ }
699
+
700
+ body.is-scrolled .wpo-main-header {
701
+ box-shadow: 0 5px 25px rgba(0, 0, 0, 0.17);
702
+ }
703
+
704
+ @media (min-width: 769px) {
705
+
706
+ .wpo-page {
707
+ padding-right: 15px;
708
+ }
709
+ }
710
+
711
+ .wpo-page:not(.active) {
712
+ display: none;
713
+ }
714
+
715
+ /* Columns */
716
+
717
+ @media (min-width: 1200px) {
718
+
719
+ .wpo-tab-postbox.right-col {
720
+ width: 350px;
721
+ float: right;
722
+ box-sizing: border-box;
723
+ margin-top: 3.1rem;
724
+ }
725
+
726
+ .right-col + .wpo-main {
727
+ float: left;
728
+ box-sizing: border-box;
729
+ width: calc(100% - 380px);
730
+ }
731
+
732
+ }
733
+
734
+ /* Common BLOCKS */
735
+
736
+ /* Buttons */
737
+
738
+ @media (max-width: 782px) {
739
+
740
+ #wp-optimize-wrap .button-large {
741
+ display: block;
742
+ width: 100%;
743
+ }
744
+ }
745
+
746
+ #wp-optimize-wrap .red {
747
+ color: #E07575;
748
+ }
749
+
750
+ #wp-optimize-wrap div[id*="_notice"] div.updated {
751
+ margin-left: 0;
752
+ }
753
+
754
+ .button.button-block {
755
+ display: block;
756
+ width: 100%;
757
+ text-align: center;
758
+ }
759
+
760
+ .wpo-refresh-button {
761
+ float: right;
762
+ }
763
+
764
+ .wpo-refresh-button:hover {
765
+ cursor: pointer;
766
+ }
767
+
768
+ .wpo-refresh-button .dashicons {
769
+ text-decoration: none;
770
+ line-height: inherit;
771
+ font-size: inherit;
772
+ }
773
+
774
+ /* Helper classes */
775
+
776
+ *[class*="wpo-badge"] {
777
+ display: inline-block;
778
+ font-size: .8em;
779
+ text-transform: uppercase;
780
+ background: #EDEFF0;
781
+ padding: 3px 5px;
782
+ line-height: 1;
783
+ border-radius: 3px;
784
+ }
785
+
786
+ .wpo-badge__new {
787
+ background: #DBE3E6;
788
+ color: #00689a;
789
+ }
790
+
791
+ .wpo-text__dim {
792
+ color: #B5B9BE;
793
+ }
794
+
795
+ .wpo-fieldgroup .wpo-text__dim {
796
+ color: #82868B;
797
+ }
798
+
799
+ .wpo-first-child {
800
+ margin-top: 0;
801
+ }
802
+
803
+ #save_done, .save-done {
804
+ color: #009B24;
805
+ font-size: 250%;
806
+ }
807
+
808
+ p.wpo-take-a-backup {
809
+ display: inline-block;
810
+ margin: 0;
811
+ line-height: 1;
812
+ padding-top: 8px;
813
+ }
814
+
815
+ @media (min-width: 782px) {
816
+
817
+ p.wpo-take-a-backup {
818
+ margin-left: 20px;
819
+ }
820
+ }
821
+
822
+ /* Postbox */
823
+
824
+ #wp-optimize-nav-tab-wrapper ~ .wp-optimize-nav-tab-contents > .postbox {
825
+ border: none;
826
+
827
+ }
828
+
829
+ #wp-optimize-nav-tab-wrapper ~ .wp-optimize-nav-tab-contents > .postbox > h3:first-child {
830
+ margin-top: 0;
831
+ }
832
+
833
+ .wpo-p25,
834
+ .postbox.wpo-tab-postbox {
835
+ padding: 25px;
836
+ }
837
+
838
+ .wpo-tab-postbox > h3:first-child {
839
+ margin-top: 0;
840
+ }
841
+
842
+ /* Field group */
843
+
844
+ .wpo-fieldgroup {
845
+ background: #EDEFF0;
846
+ border-radius: 8px;
847
+ padding: 20px
848
+ }
849
+
850
+ .wpo-fieldgroup:not(:last-child) {
851
+ margin-bottom: 2em;
852
+ }
853
+
854
+ .wpo-fieldgroup > *:first-child {
855
+ margin-top: 0;
856
+ }
857
+
858
+ .wpo-fieldgroup > *:last-child {
859
+ margin-bottom: 0;
860
+ }
861
+
862
+ .wpo-fieldgroup__subgroup:not(:last-of-type) {
863
+ margin-bottom: 20px;
864
+ }
865
+
866
+ /* TABS */
867
+
868
+ h2#wp-optimize-nav-tab-wrapper {
869
+ margin-bottom: 0;
870
+ border-bottom: none;
871
+ position: relative;
872
+ }
873
+
874
+ h2#wp-optimize-nav-tab-wrapper .nav-tab,
875
+ h2#wp-optimize-nav-tab-wrapper .nav-tab:hover,
876
+ h2#wp-optimize-nav-tab-wrapper .nav-tab:focus,
877
+ h2#wp-optimize-nav-tab-wrapper .nav-tab:focus:active {
878
+ border: none;
879
+ background: transparent;
880
+ margin: 0;
881
+ border-top: 3px solid transparent;
882
+ padding: 7px 15px;
883
+ color: #0272AA;
884
+ }
885
+
886
+ h2#wp-optimize-nav-tab-wrapper .nav-tab .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab:hover .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab:focus .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab:focus:active .dashicons {
887
+ display: block;
888
+ margin: 0 auto;
889
+ color: #72777C;
890
+ font-size: 30px;
891
+ width: 30px;
892
+ height: 30px;
893
+ }
894
+
895
+ h2#wp-optimize-nav-tab-wrapper .nav-tab-active,
896
+ h2#wp-optimize-nav-tab-wrapper .nav-tab-active:hover,
897
+ h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus,
898
+ h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus:active {
899
+ background: #FFF;
900
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0.04);
901
+ border-top-color: #0272AA;
902
+ }
903
+
904
+ h2#wp-optimize-nav-tab-wrapper .nav-tab-active .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab-active:hover .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus .dashicons, h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus:active .dashicons {
905
+ color: #0272AA;
906
+ }
907
+
908
+ @media (max-width: 782px) {
909
+
910
+ h2#wp-optimize-nav-tab-wrapper a:not(.nav-tab-active) {
911
+ display: none;
912
+ }
913
+ }
914
+
915
+ h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"] {
916
+ display: block;
917
+ float: right;
918
+ }
919
+
920
+ @media (min-width: 782px) {
921
+
922
+ h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"] {
923
+ display: none;
924
+ }
925
+ }
926
+
927
+ h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back, h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active {
928
+ text-align: right;
929
+ }
930
+
931
+ h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back .dashicons, h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active .dashicons {
932
+ color: #B5B9BE;
933
+ font-size: 18px;
934
+ display: inline-block;
935
+ height: auto;
936
+ line-height: inherit;
937
+ width: 20px;
938
+ }
939
+
940
+ @media (min-width: 782px) {
941
+
942
+ h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back, h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active {
943
+ position: absolute;
944
+ bottom: 14px;
945
+ right: 0;
946
+ font-size: 12px;
947
+ font-weight: 400;
948
+ text-decoration: none;
949
+ padding: 0;
950
+ }
951
+
952
+ h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back .dashicons, h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active .dashicons {
953
+ color: #B5B9BE;
954
+ font-size: 18px;
955
+ display: inline-block;
956
+ height: auto;
957
+ line-height: inherit;
958
+ width: 20px;
959
+ }
960
+ }
961
+
962
+ .wpo-mobile-menu-opened .wpo-main .wpo-tab-postbox {
963
+ display: none;
964
+ }
965
+
966
+ .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a {
967
+ display: block;
968
+ float: none
969
+ }
970
+
971
+ .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active,
972
+ .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active:focus {
973
+ border-top: none;
974
+ border-left: 3px solid;
975
+ }
976
+
977
+ .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active .dashicons, .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active:focus .dashicons, .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a:focus .dashicons, .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a:hover .dashicons, .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a .dashicons {
978
+ display: inline-block;
979
+ line-height: inherit;
980
+ }
981
+
982
+ .wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"] {
983
+ display: none;
984
+ }
985
+
986
+ /* Pages MENU */
987
+
988
+ .wpo-pages-menu {
989
+ position: absolute;
990
+ bottom: 0;
991
+ right: 0;
992
+ display: none;
993
+
994
+ }
995
+
996
+ @media (max-width: 820px) {
997
+
998
+ .opened + .wpo-pages-menu {
999
+ display: block;
1000
+ box-shadow: 0 5px 25px rgba(0, 0, 0, 0.17);
1001
+ }
1002
+ }
1003
+
1004
+ @media (min-width: 821px) {
1005
+
1006
+ .wpo-pages-menu {
1007
+ display: -ms-flexbox;
1008
+ display: flex;
1009
+ height: 77px;
1010
+ }
1011
+ }
1012
+
1013
+ .wpo-pages-menu > a {
1014
+ text-decoration: none;
1015
+ position: relative;
1016
+ color: inherit;
1017
+ text-align: center;
1018
+ box-sizing: border-box;
1019
+ display: block;
1020
+ color: #555d66;
1021
+ }
1022
+
1023
+ @media (min-width: 821px) {
1024
+
1025
+ .wpo-pages-menu > a {
1026
+ padding: 0 8px;
1027
+ height: 77px;
1028
+ display: -ms-flexbox;
1029
+ display: flex;
1030
+ -ms-flex-direction: column;
1031
+ flex-direction: column;
1032
+ -ms-flex-pack: center;
1033
+ justify-content: center;
1034
+ }
1035
+
1036
+ .wpo-pages-menu > a > span {
1037
+ display: block;
1038
+ margin: 0 auto;
1039
+ }
1040
+ }
1041
+
1042
+ @media (max-width: 820px) {
1043
+
1044
+ .wpo-pages-menu > a {
1045
+ padding: 15px;
1046
+ font-size: 1.2em;
1047
+ }
1048
+ }
1049
+
1050
+ .wpo-pages-menu > a.active::after {
1051
+ content: '';
1052
+ display: block;
1053
+ position: absolute;
1054
+ bottom: 0;
1055
+ left: 0;
1056
+ width: 100%;
1057
+ height: 3px;
1058
+ background: #E46B1F;
1059
+ color: #191e23;
1060
+ }
1061
+
1062
+ @media (max-width: 820px) {
1063
+
1064
+ .wpo-pages-menu > a.active::after {
1065
+ width: 3px;
1066
+ height: 100%;
1067
+ }
1068
+ }
1069
+
1070
+ @media (max-width: 820px) {
1071
+
1072
+ .wpo-pages-menu > a.active {
1073
+ color: #E46B1F;
1074
+ }
1075
+ }
1076
+
1077
+ .wpo-pages-menu > a:hover {
1078
+ background: #F9F9F9;
1079
+ color: #191e23;
1080
+ }
1081
+
1082
+ .wpo-pages-menu span.separator {
1083
+ display: block;
1084
+ width: 2px;
1085
+ background: #EFEFEF;
1086
+ margin-top: 18px;
1087
+ margin-bottom: 18px;
1088
+ margin-right: 5px;
1089
+ margin-left: 5px;
1090
+ }
1091
+
1092
+ @media (max-width: 820px) {
1093
+
1094
+ .wpo-pages-menu span.separator {
1095
+ width: 80%;
1096
+ height: 2px;
1097
+ margin: 10px 10%;
1098
+ }
1099
+ }
1100
+
1101
+ @media (max-width: 820px) {
1102
+
1103
+ .wpo-pages-menu {
1104
+ text-align: center;
1105
+ top: 100%;
1106
+ width: 100%;
1107
+ bottom: auto;
1108
+ background: #FFF;
1109
+ }
1110
+ }
1111
+
1112
+ #wp-optimize-nav-page-menu {
1113
+ position: absolute;
1114
+ right: 0;
1115
+ bottom: 0;
1116
+ display: -ms-flexbox;
1117
+ display: flex;
1118
+ height: 77px;
1119
+ -ms-flex-direction: column;
1120
+ flex-direction: column;
1121
+ padding: 0 20px;
1122
+ -ms-flex-align: center;
1123
+ align-items: center;
1124
+ -ms-flex-pack: center;
1125
+ justify-content: center;
1126
+ text-decoration: none
1127
+ }
1128
+
1129
+ #wp-optimize-nav-page-menu:not(.opened) .dashicons-no-alt {
1130
+ display: none;
1131
+ }
1132
+
1133
+ #wp-optimize-nav-page-menu.opened .dashicons-menu {
1134
+ display: none;
1135
+ }
1136
+
1137
+ @media (min-width: 821px) {
1138
+
1139
+ #wp-optimize-nav-page-menu {
1140
+ display: none;
1141
+ }
1142
+ }
1143
+
1144
+ /* DASHBOARD Menu */
1145
+
1146
+ /* Calculate column width with a $spacing gutter */
1147
+
1148
+ .wpo-dashboard-pages-menu {
1149
+ display: -ms-flexbox;
1150
+ display: flex;
1151
+ -ms-flex-wrap: wrap;
1152
+ flex-wrap: wrap
1153
+
1154
+ /* Same size for 1 to 3 items */
1155
+
1156
+ }
1157
+
1158
+ .wpo-dashboard-pages-menu[data-itemscount="1"] .wpo-dashboard-pages-menu__item, .wpo-dashboard-pages-menu[data-itemscount="2"] .wpo-dashboard-pages-menu__item, .wpo-dashboard-pages-menu[data-itemscount="3"] .wpo-dashboard-pages-menu__item {
1159
+ width: calc(33.333% - 13.33333px);
1160
+ }
1161
+
1162
+ .wpo-dashboard-pages-menu {/* above 3 items, change sizes */
1163
+ }
1164
+
1165
+ .wpo-dashboard-pages-menu[data-itemscount="4"] .wpo-dashboard-pages-menu__item {
1166
+ width: calc(25% - 15px);
1167
+ }
1168
+
1169
+ .wpo-dashboard-pages-menu[data-itemscount="5"] .wpo-dashboard-pages-menu__item {
1170
+ width: calc(20% - 16px);
1171
+ }
1172
+
1173
+ .wpo-dashboard-pages-menu[data-itemscount="6"] .wpo-dashboard-pages-menu__item {
1174
+ width: calc(16.66667% - 16.66667px);
1175
+ }
1176
+
1177
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item {
1178
+ padding: 20px;
1179
+ margin-right: 20px;
1180
+ box-sizing: border-box;
1181
+ padding-bottom: 60px;
1182
+ min-width: 0;
1183
+ }
1184
+
1185
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item:last-child {
1186
+ margin-right: 0;
1187
+ }
1188
+
1189
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3 {
1190
+ margin-top: 0;
1191
+ }
1192
+
1193
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3 .dashicons {
1194
+ color: #72777C;
1195
+ line-height: 1;
1196
+ height: 18px;
1197
+ margin-top: -2px;
1198
+ margin-right: 10px
1199
+ }
1200
+
1201
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item a {
1202
+ position: absolute;
1203
+ bottom: 20px;
1204
+ left: 20px;
1205
+ width: calc(100% - 40px) !important;
1206
+ }
1207
+
1208
+ @media (max-width: 782px) {
1209
+
1210
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item {
1211
+ width: 100%;
1212
+ margin-right: 0;
1213
+ padding-bottom: 20px;
1214
+ }
1215
+
1216
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item a.button.button-large {
1217
+ width: auto !important;
1218
+ left: auto;
1219
+ bottom: auto;
1220
+ top: 50%;
1221
+ transform: translateY(-50%);
1222
+ right: 20px;
1223
+ }
1224
+
1225
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3 {
1226
+ margin: 0;
1227
+ }
1228
+
1229
+ .wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item p {
1230
+ display: none;
1231
+ }
1232
+ }
1233
+
1234
+ /* Admin bar separator */
1235
+
1236
+ #wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item {
1237
+ height: 2px;
1238
+ line-height: 2px;
1239
+ background: rgba(255, 255, 255, 0.0902);
1240
+ margin: 5px 10px;
1241
+ width: auto;
1242
+ min-width: 0;
1243
+ }
1244
+
1245
+ /* Unused images / wpo_smush_image / image grid*/
1246
+
1247
+ .wpo_unused_image, .wpo_smush_image {
1248
+ position: relative;
1249
+ margin: 4px;
1250
+ width: calc(50% - 8px);
1251
+ text-align: center;
1252
+
1253
+ }
1254
+
1255
+ @media (min-width: 500px) {
1256
+
1257
+ .wpo_unused_image, .wpo_smush_image {
1258
+ width: calc(25% - 8px);
1259
+ }
1260
+ }
1261
+
1262
+ @media (min-width: 782px) {
1263
+
1264
+ .wpo_unused_image, .wpo_smush_image {
1265
+ width: calc(16.6666% - 8px);
1266
+ }
1267
+ }
1268
+
1269
+ @media (min-width: 1100px) {
1270
+
1271
+ .wpo_unused_image, .wpo_smush_image {
1272
+ width: calc(12.5% - 8px);
1273
+ }
1274
+ }
1275
+
1276
+ .wpo_unused_image .wpo_unused_image__input, .wpo_smush_image .wpo_unused_image__input {
1277
+ position: absolute;
1278
+ top: 10px;
1279
+ visibility: hidden;
1280
+ }
1281
+
1282
+ .wpo_unused_image label, .wpo_smush_image label {
1283
+ display: block;
1284
+ width: 100%;
1285
+ position: relative;
1286
+ padding: 1px;
1287
+ border: 3px solid #EDEFF0;
1288
+ box-sizing: border-box;
1289
+ }
1290
+
1291
+ .wpo_unused_image label::before, .wpo_smush_image label::before {
1292
+ content: "";
1293
+ display: block;
1294
+ padding-top: 100%;
1295
+ }
1296
+
1297
+ .wpo_unused_image label .thumbnail, .wpo_smush_image label .thumbnail {
1298
+ position: absolute;
1299
+ top: 1px;
1300
+ left: 1px;
1301
+ width: calc(100% - 2px);
1302
+ height: calc(100% - 2px);
1303
+ background-repeat: no-repeat;
1304
+ background-size: cover;
1305
+ background-position: 50% 50%;
1306
+ overflow: hidden;
1307
+ background: rgba(220, 220, 220, 0.2);
1308
+ }
1309
+
1310
+ .wpo_unused_image label .thumbnail img, .wpo_smush_image label .thumbnail img {
1311
+ display: block;
1312
+ margin: 0;
1313
+ max-height: 100%;
1314
+ position: absolute;
1315
+ top: 50%;
1316
+ left: 50%;
1317
+ transform: translate(-50%,-50%);
1318
+ -webkit-user-select: none;
1319
+ -moz-user-select: none;
1320
+ -ms-user-select: none;
1321
+ user-select: none;
1322
+ }
1323
+
1324
+ .wpo_unused_image .wpo_unused_image__input:checked + label, .wpo_smush_image .wpo_unused_image__input:checked + label {
1325
+ border-color: #0272AA;
1326
+ }
1327
+
1328
+ .wpo_unused_image a, .wpo_unused_image a.button, .wpo_unused_image a.button:active, .wpo_smush_image a, .wpo_smush_image a.button, .wpo_smush_image a.button:active {
1329
+ position: absolute;
1330
+ z-index: 2;
1331
+ bottom: 13px;
1332
+ left: 50%;
1333
+ transform: translateX(-50%);
1334
+ display: none;
1335
+ }
1336
+
1337
+ .wpo_unused_image:hover a, .wpo_unused_image:hover a.button, .wpo_unused_image:hover a.button:active, .wpo_smush_image:hover a, .wpo_smush_image:hover a.button, .wpo_smush_image:hover a.button:active {
1338
+ display: inline-block;
1339
+ }
1340
+
1341
+ #wpo_unused_images, #wpo_smush_images_grid {
1342
+ width: calc(100% + 8px);
1343
+ margin-left: -4px;
1344
+ margin-right: -4px;
1345
+ max-height: 500px;
1346
+ overflow-y: auto;
1347
+ display: -ms-flexbox;
1348
+ display: flex;
1349
+ -ms-flex-wrap: wrap;
1350
+ flex-wrap: wrap;
1351
+
1352
+ }
1353
+
1354
+ #wpo_unused_images .wpo-fieldgroup, #wpo_smush_images_grid .wpo-fieldgroup {
1355
+ width: 100%;
1356
+ }
1357
+
1358
+ #wpo_unused_images a {
1359
+ outline: none;
1360
+ }
1361
+
1362
+ /* More Plugins page */
1363
+
1364
+ /* Plugins family / Premium */
1365
+
1366
+ p.wpo-plugin-installed {
1367
+ color: #009B24;
1368
+ }
1369
+
1370
+ /* Settings repeater */
1371
+
1372
+ .wpo-repeater__add {
1373
+ display: inline-block;
1374
+ cursor: pointer;
1375
+ font-weight: bold;
1376
+ text-decoration: none;
1377
+ }
1378
+
1379
+ /* Plugin familly tab */
1380
+
1381
+ .wpo-plugin-family__premium h2 {
1382
+ margin: 0;
1383
+ padding: 25px;
1384
+ }
1385
+
1386
+ .wpo-plugin-family__plugins {
1387
+ display: -ms-flexbox;
1388
+ display: flex;
1389
+ -ms-flex-wrap: wrap;
1390
+ flex-wrap: wrap;
1391
+ padding-left: 1px;
1392
+ padding-bottom: 1px;
1393
+ }
1394
+
1395
+ .wpo-plugin-family__plugin {
1396
+ -ms-flex: auto;
1397
+ flex: auto;
1398
+ width: 100%;
1399
+ padding: 30px;
1400
+ box-sizing: border-box;
1401
+ border: 1px solid #E3E4E7;
1402
+ margin-left: -1px;
1403
+ margin-bottom: -1px;
1404
+
1405
+ }
1406
+
1407
+ @media (min-width: 782px) {
1408
+
1409
+ .wpo-plugin-family__plugin {
1410
+ width: 50%;
1411
+ }
1412
+
1413
+ .wpo-plugin-family__free .wpo-plugin-family__plugin {
1414
+ width: 100%;
1415
+ }
1416
+ }
1417
+
1418
+ @media (max-width: 1080px) {
1419
+
1420
+ .wpo-plugin-family__free .wpo-plugin-family__plugin {
1421
+ width: 50%;
1422
+ }
1423
+ }
1424
+
1425
+ @media (max-width: 782px) {
1426
+
1427
+ .wpo-plugin-family__free .wpo-plugin-family__plugin {
1428
+ width: 100%;
1429
+ }
1430
+ }
1431
+
1432
+ div#wp-optimize-nav-tab-wpo_mayalso-may_also-contents .wpo-tab-postbox {
1433
+ padding: 0;
1434
+ }
1435
+
1436
+ /* Added for WPO Premium Features tab */
1437
+
1438
+ .wpo_feature_cont {
1439
+ width: 64.5%;
1440
+ }
1441
+
1442
+ .wpo_plugin_family_cont {
1443
+ width: 34.5%;
1444
+ }
1445
+
1446
+ @media (max-width: 1080px) {
1447
+
1448
+ .wpo_feature_cont,
1449
+ .wpo_plugin_family_cont {
1450
+ width: 100%;
1451
+ float: none;
1452
+ margin: 0;
1453
+ }
1454
+
1455
+ }
1456
+
1457
+ .wpo_feature_cont header, .wpo_plugin_family_cont header {
1458
+ padding: 20px;
1459
+
1460
+ }
1461
+
1462
+ @media (max-width: 1080px) {
1463
+
1464
+ .wpo_feature_cont header, .wpo_plugin_family_cont header {
1465
+ padding: 40px;
1466
+ }
1467
+ }
1468
+
1469
+ .wpo_feature_cont header h2, .wpo_plugin_family_cont header h2 {
1470
+ margin: 0;
1471
+ }
1472
+
1473
+ .wpo_feature_cont header p, .wpo_plugin_family_cont header p {
1474
+ margin-bottom: 0;
1475
+ }
1476
+
1477
+ .wpo_feat_table, .wpo_feat_th, .wpo_feat_table td {
1478
+ border: none;
1479
+ border-collapse: collapse;
1480
+ background-color: white;
1481
+ font-size: 120%;
1482
+ text-align: center;
1483
+ }
1484
+
1485
+ .wpo_feat_table td {
1486
+ border: 1px solid #F1F1F1;
1487
+ border-bottom-width: 4px;
1488
+ padding: 15px;
1489
+ }
1490
+
1491
+ .wpo_feat_table td:nth-child(2), .wpo_feat_table td:nth-child(3) {
1492
+ background: rgba(241, 241, 241, 0.38);
1493
+ }
1494
+
1495
+ .wpo_feat_table p {
1496
+ padding: 0px 10px;
1497
+ margin: 5px 0px;
1498
+ font-size: 13px;
1499
+ }
1500
+
1501
+ .wpo_feat_table h4 {
1502
+ margin: 5px 0px;
1503
+ }
1504
+
1505
+ .wpo_feat_table .dashicons {
1506
+ width: 25px;
1507
+ height: 25px;
1508
+ font-size: 25px;
1509
+ line-height: 1;
1510
+ }
1511
+
1512
+ .wpo_feat_table .dashicons-yes, .wpo_feat_table .updraft-yes {
1513
+ color: green;
1514
+ }
1515
+
1516
+ .wpo_feat_table .dashicons-no-alt, .wpo_feat_table .updraft-no {
1517
+ color: red;
1518
+ }
1519
+
1520
+ .wpo-premium-image {
1521
+ display: none;
1522
+ }
1523
+
1524
+ @media screen and (min-width: 720px) {
1525
+
1526
+ #wpoptimize_table_list_filter {
1527
+ width: 40%;
1528
+ }
1529
+
1530
+ .wpo-premium-image {
1531
+ display: block;
1532
+ float: left;
1533
+ padding: 16px 18px;
1534
+ width: 30px;
1535
+ height: auto;
1536
+ }
1537
+
1538
+ }
1539
+
1540
+ @media screen and (min-width: 1220px) {
1541
+
1542
+ .wpo_feat_table td:nth-child(2), .wpo_feat_table td:nth-child(3) {
1543
+ width: 110px;
1544
+ }
1545
+
1546
+ }
1547
+
1548
+ .other-plugin-title {
1549
+ text-decoration: none;
1550
+ }
1551
+
1552
+ @media screen and (max-width: 782px) {
1553
+
1554
+ table.wpo_feat_table {
1555
+
1556
+ display: block;
1557
+ }
1558
+
1559
+ table.wpo_feat_table tr {
1560
+ display: -ms-flexbox;
1561
+ display: flex;
1562
+ -ms-flex-wrap: wrap;
1563
+ flex-wrap: wrap;
1564
+ }
1565
+
1566
+ table.wpo_feat_table td {
1567
+ display: block
1568
+ }
1569
+
1570
+ table.wpo_feat_table td:first-child {
1571
+ width: 100%;
1572
+ border-bottom: none;
1573
+ }
1574
+
1575
+ table.wpo_feat_table td:not(:first-child) {
1576
+ width: 50%;
1577
+ box-sizing: border-box;
1578
+ }
1579
+
1580
+ table.wpo_feat_table td:first-child:empty {
1581
+ display: none;
1582
+ }
1583
+
1584
+ table.wpo_feat_table td[data-colname]::before {
1585
+ content: attr(data-colname);
1586
+ font-size: 0.8rem;
1587
+ color: #CCC;
1588
+ line-height: 1;
1589
+ }
1590
+
1591
+ }
1592
+
1593
+ /* tablesorter */
1594
+
1595
+ #wp-optimize-wrap .wp-list-table td {
1596
+ word-break: break-all;
1597
+ }
1598
+
1599
+ @media screen and (max-width: 782px ) {
1600
+
1601
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody, #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody tr, #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody th, #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td {
1602
+ display: block;
1603
+ }
1604
+
1605
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td {
1606
+ padding: 3px 8px 3px 35%;
1607
+ word-break: break-word;
1608
+ box-sizing: border-box
1609
+
1610
+ }
1611
+
1612
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td::before {
1613
+ color: #B5B9BE;
1614
+ }
1615
+
1616
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead, #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead tr {
1617
+ display: block;
1618
+ }
1619
+
1620
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead th.column-primary {
1621
+ display: block;
1622
+ box-sizing: border-box;
1623
+ }
1624
+
1625
+ #wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead th:not(.column-primary) {
1626
+ display: none !important;
1627
+ }
1628
+ }
1629
+
1630
+ th:not(.sorter-false) .tablesorter-header-inner {
1631
+
1632
+ color: #0074ab
1633
+
1634
+ }
1635
+
1636
+ th:not(.sorter-false) .tablesorter-header-inner::after {
1637
+ content: '';
1638
+ font-family: 'dashicons';
1639
+ font-size: 20px;
1640
+ line-height: 20px;
1641
+ height: 20px;
1642
+ width: 20px;
1643
+ display: inline-block;
1644
+ vertical-align: bottom;
1645
+ }
1646
+
1647
+ th.tablesorter-header.tablesorter-headerAsc,
1648
+ th.tablesorter-header.tablesorter-headerDesc {
1649
+ font-weight: 500;
1650
+ border-bottom-color: #0272AA;
1651
+ }
1652
+
1653
+ th.tablesorter-header.tablesorter-headerDesc .tablesorter-header-inner::after {
1654
+ content: "\f140";
1655
+ }
1656
+
1657
+ th.tablesorter-header.tablesorter-headerAsc .tablesorter-header-inner::after {
1658
+ content: "\f142";
1659
+ }
1660
+
1661
+ th.tablesorter-header:focus {
1662
+ outline: none;
1663
+ box-shadow: 0 0 3px rgba(0, 116, 171, 0.78)
1664
+
1665
+ }
1666
+
1667
+ th.tablesorter-header:focus:not(.tablesorter-headerAsc):not(.tablesorter-headerDesc) .tablesorter-header-inner::after {
1668
+ content: "\f142";
1669
+ opacity: 0.5;
1670
+ }
1671
+
1672
+ .tablesorter.hasFilters tr.filtered {
1673
+ display: none;
1674
+ }
css/wp-optimize-admin.min.css ADDED
@@ -0,0 +1,2 @@
 
 
1
+ .wpo_hidden{display:none}.wpo_info{background:#FFF;color:#444;font-family:-apple-system,"BlinkMacSystemFont","Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif;margin:2em auto;padding:1em 2em;max-width:700px;box-shadow:0 1px 3px rgba(0,0,0,0.13)}.wpo_primary_big{padding:4px 6px !important;font-size:22px !important;min-height:34px;min-width:200px}.wpo_section{clear:both;padding:0;margin:0}.wp-optimize-settings{margin-bottom:16px}.wp-optimize-settings td>label{font-weight:bold;display:block;margin-bottom:8px}.wpo_col{display:block;float:left;margin:1% 0 1% 1%}.wpo_col:first-child{margin-left:0}.wpo_group:before,.wpo_group:after{content:"";display:table}.wpo_group:after{clear:both}.wpo_half_width{width:48%}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:65.3%}.wpo_span_1_of_3{width:32.1%}.nav-tab-wrapper{margin:14px 0}@media screen and (min-width:549px){.show_on_default_sizes{display:block !important}.show_on_mobile_sizes{display:none !important}}@media screen and (max-width:548px){.show_on_default_sizes{display:none !important}.show_on_mobile_sizes{display:block !important}}@media screen and (max-width:768px){.wpo_col{margin:1% 0}.wpo_span_3_of_3{width:100%}.wpo_span_2_of_3{width:100%}.wpo_span_1_of_3{width:100%}.wpo_half_width{width:100%}}.wp-optimize-setting-is-sensitive td>label::before{content:"\f534";font-family:'dashicons';display:inline-block;margin-right:6px;font-style:normal;line-height:1;vertical-align:middle;width:20px;font-size:18px;height:20px;text-align:center;color:#72777c}.wpo-run-optimizations__container{margin-bottom:15px}td.wp-optimize-settings-optimization-checkbox{width:18px;padding-left:4px;padding-right:0}.wp-optimize-settings-optimization-checkbox input{margin:0;padding:0}#retention-period{width:60px}.wp-optimize-settings-optimization-info{font-size:80%;font-style:italic}img.addons{display:block;margin-left:auto;margin-right:auto;margin-bottom:20px;max-height:44px;height:auto;max-width:100%}.wpo_spinner{width:18px;height:18px;padding-left:10px;display:none;position:relative;top:4px}.optimization_spinner{width:20px;height:20px}#wp-optimize-auto-options{margin:20px 0 0 28px}.display-none{display:none}.visibility-hidden{visibility:hidden}.margin-one-percent{margin:1%}#save_done,.save-done{color:#d94f00;font-size:250% !important}.wp-optimize-settings-optimization-info a{text-decoration:underline}.wp-optimize-settings-optimization-run-spinner{position:relative;top:2px}@media screen and (min-width:782px){td.wp-optimize-settings-optimization-run{width:180px;padding-top:16px}}#wpoptimize_table_list .tablesorter-filter-row{display:none !important}#wpoptimize_table_list .optimization_spinner{position:relative;top:2px;left:5px}#wpoptimize_table_list .optimization_spinner.visibility-hidden{display:none}#wpoptimize_table_list_filter{width:100%;margin-bottom:15px}#wpoptimize_table_list_tables_not_found{display:none;margin:20px 0}div#wpoptimize_table_list_tables_not_found+h3{margin-top:30px}#optimize_form .select2-container,#wp-optimize-auto-options .select2-container{width:50% !important;top:-5px;height:40px;margin-left:10px}#wpoptimize_table_list .optimization_done_icon{color:#009b24;font-size:200%;display:inline-block;position:relative}#wpo_sitelist_show_moreoptions_cron{font-size:13px;line-height:1.5;letter-spacing:1px}#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3{display:inline-block}.wpo_remove_selected_sizes_btn__container{margin-top:20px}.unused-image-sizes__label{display:block;line-height:1.6}@media(max-width:782px){.unused-image-sizes__label{margin-left:30px;margin-bottom:15px;line-height:1}.unused-image-sizes__label input[type=checkbox]{margin-left:-30px}}#wp-optimize-nav-tab-contents-tables a{vertical-align:middle}#wpo_sitelist_moreoptions,#wpo_sitelist_moreoptions_cron{margin:4px 16px 6px 0;border:1px dotted;padding:6px 10px;max-height:300px;overflow-y:scroll;overflow-x:hidden}#wpo_sitelist_moreoptions{max-height:150px;margin-right:0}#wpo_settings_sites_list li,#wpo_settings_sites_list li a{font-size:13px;line-height:1.5}#wpo_sitelist_moreoptions_cron li{padding-left:20px}#wpo_import_error_message{display:none;color:#9b0000}#wpo_import_success_message{display:none;color:#46b450}#wp-optimize-logging-options{margin-top:10px}.wpo_logging_header{font-weight:bold;border-top:1px solid #333;border-bottom:1px solid #333;padding:5px 0;margin:0}.wpo_logging_row{border-bottom:1px solid #a1a2a3;padding:5px 0}.wpo_logging_logger_title,.wpo_logging_options_title,.wpo_logging_status_title,.wpo_logging_actions_title,.wpo_logging_logger_row,.wpo_logging_options_row,.wpo_logging_status_row,.wpo_logging_actions_row{display:inline-block;vertical-align:middle}.wpo_logging_logger_title,.wpo_logging_logger_row{width:38%}.wpo_logging_options_title,.wpo_logging_options_row{width:44%}.wpo_logging_status_title,.wpo_logging_status_row{width:8%}.wpo_logging_actions_title,.wpo_logging_actions_row{width:7%}.wpo_logging_actions_row{text-align:right}.wpo_logging_options_row{word-wrap:break-word}.wpo_logging_actions_row .dashicons-no-alt,.wpo_add_logger_form .dashicons-no-alt{background-color:#f06666;color:#FFF;width:20px;height:20px;border-radius:20px;display:inline-block;cursor:pointer;margin-left:5px}.wpo_add_logger_form .dashicons-no-alt{margin-top:12px;margin-right:10px;float:right}.wpo_logger_type{width:90%;margin-top:10px}.wpo_logger_addition_option{width:100%;margin-top:5px}.wpo_alert_notice{background-color:#f06666;color:#FFF;padding:5px;display:block;margin-bottom:5px;border-radius:5px}.wpo_error_field{border-color:#f06666 !important}.save_settings_reminder{display:none;color:#333;padding:15px 20px;background-color:#f0a5a4;border-radius:3px;margin:15px 0}#wpo_remove_selected_sizes{margin-top:20px}.wpo_unused_images_buttons_wrap{display:none}.wpo_unused_images_container h3{min-width:150px}#wpo_unused_images,#wpo_smush_images_grid{max-height:500px;overflow-y:auto}#wpo_unused_images a{outline:0}#wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup{margin-left:1%}.run-single-table-delete{margin-top:3px}#wpo_browser_cache_output,#wpo_gzip_compression_output{background:#f0f0f0;padding:10px;border:1px solid #CCC}#wpo_browser_cache_error_message,#wpo_gzip_compression_error_message,.wpo-error{color:#9b0000}#wpo_browser_cache_expire_days,#wpo_browser_cache_expire_hours{width:50px}.wpo-enabled .wpo-disabled{display:none}.wpo-disabled .wpo-enabled{display:none}#wp-optimize-wrap{position:relative;padding-top:100px}@media(min-width:820px){#wp-optimize-wrap{padding-top:120px}}@media(max-width:782px){#wp-optimize-wrap{margin-right:0}}.wpo-main-header{height:77px;position:fixed;top:32px;left:160px;background:#FFF;right:0;z-index:9980}@media(min-width:820px){.wpo-main-header{height:105px}}.wpo-main-header .wpo-logo__container{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;position:relative;height:100%;line-height:1;font-size:1rem;padding-left:50px;margin-left:10px}.wpo-main-header .wpo-logo{position:absolute;left:0;top:50%;transform:translateY(-50%);width:50px}.wpo-main-header .wpo-subheader{margin:0;font-weight:300;color:#72777c;line-height:1.3}@media(max-width:1080px){.wpo-main-header .wpo-subheader{display:none}}.wpo-main-header p.wpo-header-links{margin:0;font-size:.7rem;position:absolute;right:0;padding:6px 15px;background:#edeeef;border-bottom-left-radius:5px;z-index:1}.wpo-main-header p.wpo-header-links a{text-decoration:none}.wpo-main-header p.wpo-header-links .wpo-header-links__label{color:#82868b;position:absolute;right:100%;width:110px;text-align:right;padding-right:10px}@media(max-width:820px){.wpo-main-header p.wpo-header-links{display:none}}.wpo-main-header p.wpo-header-links__mobile{padding:10px;background:#edeeef;margin-bottom:0}@media(min-width:820px){.wpo-main-header p.wpo-header-links__mobile{display:none}}.wpo-main-header p.wpo-header-links__mobile a{display:inline-block;padding:4px;font-size:.8rem}.wpo-main-header p.wpo-header-links__mobile .wpo-header-links__label{color:#82868b}@media(max-width:600px){.wpo-main-header .wpo-logo__container strong{width:140px;display:inline-block}}@media(max-width:960px){body.auto-fold .wpo-main-header{left:36px}}@media(max-width:782px){body.auto-fold .wpo-main-header{left:0;top:46px}}@media(max-width:600px){body.auto-fold .wpo-main-header{position:absolute;left:-10px;right:-10px;top:0}}@media(min-width:782px){body.folded .wpo-main-header{left:36px}}body.is-scrolled .wpo-main-header{box-shadow:0 5px 25px rgba(0,0,0,0.17)}@media(min-width:769px){.wpo-page{padding-right:15px}}.wpo-page:not(.active){display:none}@media(min-width:1200px){.wpo-tab-postbox.right-col{width:350px;float:right;box-sizing:border-box;margin-top:3.1rem}.right-col+.wpo-main{float:left;box-sizing:border-box;width:calc(100% - 380px)}}@media(max-width:782px){#wp-optimize-wrap .button-large{display:block;width:100%}}#wp-optimize-wrap .red{color:#e07575}#wp-optimize-wrap div[id*="_notice"] div.updated{margin-left:0}.button.button-block{display:block;width:100%;text-align:center}.wpo-refresh-button{float:right}.wpo-refresh-button:hover{cursor:pointer}.wpo-refresh-button .dashicons{text-decoration:none;line-height:inherit;font-size:inherit}*[class*="wpo-badge"]{display:inline-block;font-size:.8em;text-transform:uppercase;background:#edeff0;padding:3px 5px;line-height:1;border-radius:3px}.wpo-badge__new{background:#dbe3e6;color:#00689a}.wpo-text__dim{color:#b5b9be}.wpo-fieldgroup .wpo-text__dim{color:#82868b}.wpo-first-child{margin-top:0}#save_done,.save-done{color:#009b24;font-size:250%}p.wpo-take-a-backup{display:inline-block;margin:0;line-height:1;padding-top:8px}@media(min-width:782px){p.wpo-take-a-backup{margin-left:20px}}#wp-optimize-nav-tab-wrapper ~ .wp-optimize-nav-tab-contents>.postbox{border:0}#wp-optimize-nav-tab-wrapper ~ .wp-optimize-nav-tab-contents>.postbox>h3:first-child{margin-top:0}.wpo-p25,.postbox.wpo-tab-postbox{padding:25px}.wpo-tab-postbox>h3:first-child{margin-top:0}.wpo-fieldgroup{background:#edeff0;border-radius:8px;padding:20px}.wpo-fieldgroup:not(:last-child){margin-bottom:2em}.wpo-fieldgroup>*:first-child{margin-top:0}.wpo-fieldgroup>*:last-child{margin-bottom:0}.wpo-fieldgroup__subgroup:not(:last-of-type){margin-bottom:20px}h2#wp-optimize-nav-tab-wrapper{margin-bottom:0;border-bottom:0;position:relative}h2#wp-optimize-nav-tab-wrapper .nav-tab,h2#wp-optimize-nav-tab-wrapper .nav-tab:hover,h2#wp-optimize-nav-tab-wrapper .nav-tab:focus,h2#wp-optimize-nav-tab-wrapper .nav-tab:focus:active{border:0;background:transparent;margin:0;border-top:3px solid transparent;padding:7px 15px;color:#0272aa}h2#wp-optimize-nav-tab-wrapper .nav-tab .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab:hover .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab:focus .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab:focus:active .dashicons{display:block;margin:0 auto;color:#72777c;font-size:30px;width:30px;height:30px}h2#wp-optimize-nav-tab-wrapper .nav-tab-active,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:hover,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus:active{background:#FFF;box-shadow:0 0 1px rgba(0,0,0,0.04);border-top-color:#0272aa}h2#wp-optimize-nav-tab-wrapper .nav-tab-active .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:hover .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus .dashicons,h2#wp-optimize-nav-tab-wrapper .nav-tab-active:focus:active .dashicons{color:#0272aa}@media(max-width:782px){h2#wp-optimize-nav-tab-wrapper a:not(.nav-tab-active){display:none}}h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"]{display:block;float:right}@media(min-width:782px){h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"]{display:none}}h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back,h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active{text-align:right}h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back .dashicons,h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active .dashicons{color:#b5b9be;font-size:18px;display:inline-block;height:auto;line-height:inherit;width:20px}@media(min-width:782px){h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back,h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active{position:absolute;bottom:14px;right:0;font-size:12px;font-weight:400;text-decoration:none;padding:0}h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back .dashicons,h2#wp-optimize-nav-tab-wrapper a.nav-tab.wp-optimize-nav-tab__back:focus:active .dashicons{color:#b5b9be;font-size:18px;display:inline-block;height:auto;line-height:inherit;width:20px}}.wpo-mobile-menu-opened .wpo-main .wpo-tab-postbox{display:none}.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a{display:block;float:none}.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active,.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active:focus{border-top:0;border-left:3px solid}.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active .dashicons,.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a.nav-tab-active:focus .dashicons,.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a:focus .dashicons,.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a:hover .dashicons,.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a .dashicons{display:inline-block;line-height:inherit}.wpo-mobile-menu-opened h2#wp-optimize-nav-tab-wrapper a[role="toggle-menu"]{display:none}.wpo-pages-menu{position:absolute;bottom:0;right:0;display:none}@media(max-width:820px){.opened+.wpo-pages-menu{display:block;box-shadow:0 5px 25px rgba(0,0,0,0.17)}}@media(min-width:821px){.wpo-pages-menu{display:-ms-flexbox;display:flex;height:77px}}.wpo-pages-menu>a{text-decoration:none;position:relative;color:inherit;text-align:center;box-sizing:border-box;display:block;color:#555d66}@media(min-width:821px){.wpo-pages-menu>a{padding:0 8px;height:77px;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center}.wpo-pages-menu>a>span{display:block;margin:0 auto}}@media(max-width:820px){.wpo-pages-menu>a{padding:15px;font-size:1.2em}}.wpo-pages-menu>a.active::after{content:'';display:block;position:absolute;bottom:0;left:0;width:100%;height:3px;background:#e46b1f;color:#191e23}@media(max-width:820px){.wpo-pages-menu>a.active::after{width:3px;height:100%}}@media(max-width:820px){.wpo-pages-menu>a.active{color:#e46b1f}}.wpo-pages-menu>a:hover{background:#f9f9f9;color:#191e23}.wpo-pages-menu span.separator{display:block;width:2px;background:#efefef;margin-top:18px;margin-bottom:18px;margin-right:5px;margin-left:5px}@media(max-width:820px){.wpo-pages-menu span.separator{width:80%;height:2px;margin:10px 10%}}@media(max-width:820px){.wpo-pages-menu{text-align:center;top:100%;width:100%;bottom:auto;background:#FFF}}#wp-optimize-nav-page-menu{position:absolute;right:0;bottom:0;display:-ms-flexbox;display:flex;height:77px;-ms-flex-direction:column;flex-direction:column;padding:0 20px;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;text-decoration:none}#wp-optimize-nav-page-menu:not(.opened) .dashicons-no-alt{display:none}#wp-optimize-nav-page-menu.opened .dashicons-menu{display:none}@media(min-width:821px){#wp-optimize-nav-page-menu{display:none}}.wpo-dashboard-pages-menu{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.wpo-dashboard-pages-menu[data-itemscount="1"] .wpo-dashboard-pages-menu__item,.wpo-dashboard-pages-menu[data-itemscount="2"] .wpo-dashboard-pages-menu__item,.wpo-dashboard-pages-menu[data-itemscount="3"] .wpo-dashboard-pages-menu__item{width:calc(33.333% - 13.33333px)}.wpo-dashboard-pages-menu[data-itemscount="4"] .wpo-dashboard-pages-menu__item{width:calc(25% - 15px)}.wpo-dashboard-pages-menu[data-itemscount="5"] .wpo-dashboard-pages-menu__item{width:calc(20% - 16px)}.wpo-dashboard-pages-menu[data-itemscount="6"] .wpo-dashboard-pages-menu__item{width:calc(16.66667% - 16.66667px)}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item{padding:20px;margin-right:20px;box-sizing:border-box;padding-bottom:60px;min-width:0}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item:last-child{margin-right:0}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3{margin-top:0}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3 .dashicons{color:#72777c;line-height:1;height:18px;margin-top:-2px;margin-right:10px}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item a{position:absolute;bottom:20px;left:20px;width:calc(100% - 40px) !important}@media(max-width:782px){.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item{width:100%;margin-right:0;padding-bottom:20px}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item a.button.button-large{width:auto !important;left:auto;bottom:auto;top:50%;transform:translateY(-50%);right:20px}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item h3{margin:0}.wpo-dashboard-pages-menu .postbox.wpo-dashboard-pages-menu__item p{display:none}}#wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item{height:2px;line-height:2px;background:rgba(255,255,255,0.0902);margin:5px 10px;width:auto;min-width:0}.wpo_unused_image,.wpo_smush_image{position:relative;margin:4px;width:calc(50% - 8px);text-align:center}@media(min-width:500px){.wpo_unused_image,.wpo_smush_image{width:calc(25% - 8px)}}@media(min-width:782px){.wpo_unused_image,.wpo_smush_image{width:calc(16.6666% - 8px)}}@media(min-width:1100px){.wpo_unused_image,.wpo_smush_image{width:calc(12.5% - 8px)}}.wpo_unused_image .wpo_unused_image__input,.wpo_smush_image .wpo_unused_image__input{position:absolute;top:10px;visibility:hidden}.wpo_unused_image label,.wpo_smush_image label{display:block;width:100%;position:relative;padding:1px;border:3px solid #edeff0;box-sizing:border-box}.wpo_unused_image label::before,.wpo_smush_image label::before{content:"";display:block;padding-top:100%}.wpo_unused_image label .thumbnail,.wpo_smush_image label .thumbnail{position:absolute;top:1px;left:1px;width:calc(100% - 2px);height:calc(100% - 2px);background-repeat:no-repeat;background-size:cover;background-position:50% 50%;overflow:hidden;background:rgba(220,220,220,0.2)}.wpo_unused_image label .thumbnail img,.wpo_smush_image label .thumbnail img{display:block;margin:0;max-height:100%;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.wpo_unused_image .wpo_unused_image__input:checked+label,.wpo_smush_image .wpo_unused_image__input:checked+label{border-color:#0272aa}.wpo_unused_image a,.wpo_unused_image a.button,.wpo_unused_image a.button:active,.wpo_smush_image a,.wpo_smush_image a.button,.wpo_smush_image a.button:active{position:absolute;z-index:2;bottom:13px;left:50%;transform:translateX(-50%);display:none}.wpo_unused_image:hover a,.wpo_unused_image:hover a.button,.wpo_unused_image:hover a.button:active,.wpo_smush_image:hover a,.wpo_smush_image:hover a.button,.wpo_smush_image:hover a.button:active{display:inline-block}#wpo_unused_images,#wpo_smush_images_grid{width:calc(100% + 8px);margin-left:-4px;margin-right:-4px;max-height:500px;overflow-y:auto;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}#wpo_unused_images .wpo-fieldgroup,#wpo_smush_images_grid .wpo-fieldgroup{width:100%}#wpo_unused_images a{outline:0}p.wpo-plugin-installed{color:#009b24}.wpo-repeater__add{display:inline-block;cursor:pointer;font-weight:bold;text-decoration:none}.wpo-plugin-family__premium h2{margin:0;padding:25px}.wpo-plugin-family__plugins{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:1px;padding-bottom:1px}.wpo-plugin-family__plugin{-ms-flex:auto;flex:auto;width:100%;padding:30px;box-sizing:border-box;border:1px solid #e3e4e7;margin-left:-1px;margin-bottom:-1px}@media(min-width:782px){.wpo-plugin-family__plugin{width:50%}.wpo-plugin-family__free .wpo-plugin-family__plugin{width:100%}}@media(max-width:1080px){.wpo-plugin-family__free .wpo-plugin-family__plugin{width:50%}}@media(max-width:782px){.wpo-plugin-family__free .wpo-plugin-family__plugin{width:100%}}div#wp-optimize-nav-tab-wpo_mayalso-may_also-contents .wpo-tab-postbox{padding:0}.wpo_feature_cont{width:64.5%}.wpo_plugin_family_cont{width:34.5%}@media(max-width:1080px){.wpo_feature_cont,.wpo_plugin_family_cont{width:100%;float:none;margin:0}}.wpo_feature_cont header,.wpo_plugin_family_cont header{padding:20px}@media(max-width:1080px){.wpo_feature_cont header,.wpo_plugin_family_cont header{padding:40px}}.wpo_feature_cont header h2,.wpo_plugin_family_cont header h2{margin:0}.wpo_feature_cont header p,.wpo_plugin_family_cont header p{margin-bottom:0}.wpo_feat_table,.wpo_feat_th,.wpo_feat_table td{border:0;border-collapse:collapse;background-color:white;font-size:120%;text-align:center}.wpo_feat_table td{border:1px solid #f1f1f1;border-bottom-width:4px;padding:15px}.wpo_feat_table td:nth-child(2),.wpo_feat_table td:nth-child(3){background:rgba(241,241,241,0.38)}.wpo_feat_table p{padding:0 10px;margin:5px 0;font-size:13px}.wpo_feat_table h4{margin:5px 0}.wpo_feat_table .dashicons{width:25px;height:25px;font-size:25px;line-height:1}.wpo_feat_table .dashicons-yes,.wpo_feat_table .updraft-yes{color:green}.wpo_feat_table .dashicons-no-alt,.wpo_feat_table .updraft-no{color:red}.wpo-premium-image{display:none}@media screen and (min-width:720px){#wpoptimize_table_list_filter{width:40%}.wpo-premium-image{display:block;float:left;padding:16px 18px;width:30px;height:auto}}@media screen and (min-width:1220px){.wpo_feat_table td:nth-child(2),.wpo_feat_table td:nth-child(3){width:110px}}.other-plugin-title{text-decoration:none}@media screen and (max-width:782px){table.wpo_feat_table{display:block}table.wpo_feat_table tr{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}table.wpo_feat_table td{display:block}table.wpo_feat_table td:first-child{width:100%;border-bottom:0}table.wpo_feat_table td:not(:first-child){width:50%;box-sizing:border-box}table.wpo_feat_table td:first-child:empty{display:none}table.wpo_feat_table td[data-colname]::before{content:attr(data-colname);font-size:.8rem;color:#CCC;line-height:1}}#wp-optimize-wrap .wp-list-table td{word-break:break-all}@media screen and (max-width:782px){#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody,#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody tr,#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody th,#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td{display:block}#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td{padding:3px 8px 3px 35%;word-break:break-word;box-sizing:border-box}#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels tbody td::before{color:#b5b9be}#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead,#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead tr{display:block}#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead th.column-primary{display:block;box-sizing:border-box}#wp-optimize-wrap .wp-list-table.wp-list-table-mobile-labels thead th:not(.column-primary){display:none !important}}th:not(.sorter-false) .tablesorter-header-inner{color:#0074ab}th:not(.sorter-false) .tablesorter-header-inner::after{content:'';font-family:'dashicons';font-size:20px;line-height:20px;height:20px;width:20px;display:inline-block;vertical-align:bottom}th.tablesorter-header.tablesorter-headerAsc,th.tablesorter-header.tablesorter-headerDesc{font-weight:500;border-bottom-color:#0272aa}th.tablesorter-header.tablesorter-headerDesc .tablesorter-header-inner::after{content:"\f140"}th.tablesorter-header.tablesorter-headerAsc .tablesorter-header-inner::after{content:"\f142"}th.tablesorter-header:focus{outline:0;box-shadow:0 0 3px rgba(0,116,171,0.78)}th.tablesorter-header:focus:not(.tablesorter-headerAsc):not(.tablesorter-headerDesc) .tablesorter-header-inner::after{content:"\f142";opacity:.5}.tablesorter.hasFilters tr.filtered{display:none}
2
+ /*# sourceMappingURL=wp-optimize-admin.min.css.map */
css/wp-optimize-admin.min.css.map ADDED
@@ -0,0 +1 @@
 
1
+ {"version":3,"sources":["css/wp-optimize-admin.scss","css/admin.css","css/scss/_layout.scss","css/scss/_common.scss","css/scss/_menu-and-tabs.scss","css/scss/_image-list.scss","css/scss/_plugin-family-tab.scss","css/scss/_table-sorter.scss"],"names":[],"mappings":"AAAA,YAAY;;AAcZ,gBAAgB;;ACdhB;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB,YAAY;CACZ,2IAA2I;CAC3I,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CAEjB,uCAAuC;CACvC;;AAED,gBAAgB;;AAChB;CACC,4BAA4B;CAC5B,2BAA2B;CAC3B,iBAAiB;CACjB,iBAAiB;CACjB;;AAED,gBAAgB;;AAChB;CACC,YAAY;CACZ,WAAW;CACX,UAAU;CACV;;AAED;CACC,oBAAoB;CACpB;;AAED;CACC,kBAAkB;CAClB,eAAe;CACf,mBAAmB;CACnB;;AAED,oBAAoB;;AACpB;CACC,eAAe;CACf,YAAY;CACZ,mBAAmB;CACnB;;AAED;CACC,eAAe;CACf;;AAED,gBAAgB;;AAChB;;CAEC,YAAY;CACZ,eAAe;CACf;;AAED;CACC,YAAY;CACZ;;AAED;CACC,WAAW;CACX;;AAED,qBAAqB;;AACrB;CACC,YAAY;CACZ;;AAED;CACC,aAAa;CACb;;AAED;CACC,aAAa;CACb;;AAED;CACC,iBAAiB;CACjB;;AAED;;CAEC;EACC,0BAA0B;EAC1B;;CAED;EACC,yBAAyB;EACzB;;CAED;;AAED;;CAEC;EACC,yBAAyB;EACzB;;CAED;EACC,0BAA0B;EAC1B;;CAED;;AAED;;CAEC;EACC,aAAa;EACb;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;EACC,YAAY;EACZ;;CAED;;AAED,qRAAqR;;AAErR;CACC,iBAAiB;CACjB,yBAAyB;CACzB,sBAAsB;CACtB,kBAAkB;CAClB,mBAAmB;CACnB,eAAe;CACf,uBAAuB;CACvB,YAAY;CACZ,gBAAgB;CAChB,aAAa;CACb,mBAAmB;CACnB,eAAe;CACf;;AAED;CACC,oBAAoB;CACpB;;AAED;CACC,YAAY;CACZ,kBAAkB;CAClB,mBAAmB;CACnB;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,YAAY;CACZ;;AAED;CACC,eAAe;CACf,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB;;AAED,sCAAsC;;AACtC;CACC,eAAe;CACf,kBAAkB;CAClB,mBAAmB;CACnB,oBAAoB;CACpB,iBAAiB;CACjB,aAAa;CACb,gBAAgB;CAChB;;AAED;CACC,YAAY;CACZ,aAAa;CACb,mBAAmB;CACnB,cAAc;CACd,mBAAmB;CACnB,SAAS;CACT;;AAED;CACC,YAAY;CACZ,aAAa;CACb;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,cAAc;CACd;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,WAAW;CACX;;AAED;CACC,eAAe;CACf,2BAA2B;CAC3B;;AAED;CACC,2BAA2B;CAC3B;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT;;AAED;;CAEC;EACC,aAAa;EACb,kBAAkB;EAClB;;CAED;;AAED;CACC,yBAAyB;CACzB;;AAED;CACC,mBAAmB;CACnB,SAAS;CACT,UAAU;CACV;;AAED;CACC,cAAc;CACd;;AAED;CACC,YAAY;CACZ,oBAAoB;CACpB;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED;;CAEC,sBAAsB;CACtB,UAAU;CACV,aAAa;CACb,kBAAkB;CAClB;;AAED;CACC,eAAe;CACf,gBAAgB;CAChB,sBAAsB;CACtB,mBAAmB;CACnB;;AAED;CACC,gBAAgB;CAChB,iBAAiB;CACjB,oBAAoB;CACpB;;AAED;CACC,sBAAsB;CACtB;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,eAAe;CACf,iBAAiB;CACjB;;AAED;;CAEC;EACC,kBAAkB;EAClB,oBAAoB;EACpB,eAAe;EACf;;CAED;EACC,mBAAmB;EACnB;;CAED;;AAED;CACC,uBAAuB;CACvB;;AAED;;CAEC,uBAAuB;CACvB,mBAAmB;CACnB,kBAAkB;CAClB,kBAAkB;CAClB,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB,gBAAgB;CAChB;;AAED;;CAEC,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,mBAAmB;CACnB;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,cAAc;CACd,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED,oBAAoB;;AACpB;CACC,kBAAkB;CAClB,2BAA2B;CAC3B,8BAA8B;CAC9B,eAAe;CACf,UAAU;CACV;;AAED;CACC,iCAAiC;CACjC,eAAe;CACf;;AAED;;;;;;;;CAQC,sBAAsB;CACtB,uBAAuB;CACvB;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,WAAW;CACX;;AAED;;CAEC,UAAU;CACV;;AAED;;CAEC,UAAU;CACV;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,sBAAsB;CACtB;;AAED;;CAEC,0BAA0B;CAC1B,YAAY;CACZ,YAAY;CACZ,aAAa;CACb,oBAAoB;CACpB,sBAAsB;CACtB,gBAAgB;CAChB,iBAAiB;CACjB;;AAED;CACC,iBAAiB;CACjB,mBAAmB;CACnB,aAAa;CACb;;AAED;CACC,WAAW;CACX,iBAAiB;CACjB;;AAED;CACC,YAAY;CACZ,gBAAgB;CAChB;;AAED;CACC,0BAA0B;CAC1B,YAAY;CACZ,aAAa;CACb,eAAe;CACf,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,iCAAiC;CACjC;;AAED;CACC,cAAc;CACd,YAAY;CACZ,mBAAmB;CACnB,0BAA0B;CAC1B,mBAAmB;CACnB,eAAe;CACf;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd;;AAED;CACC,iBAAiB;CACjB;;AAED;CACC,kBAAkB;CAClB,iBAAiB;CACjB;;AAED;CACC,cAAc;CACd;;AAED;CACC,gBAAgB;CAChB;;AAED;CACC,gBAAgB;CAChB;;AAED;;CAEC,oBAAoB;CACpB,cAAc;CACd,uBAAuB;CACvB;;AAED;;;CAGC,eAAe;CACf;;AAED;;CAEC,YAAY;CACZ;;AAED;CACC,cAAc;CACd;;AAED;CACC,cAAc;CACd;;ACpgBD;CACC,mBAAmB;CACnB,mBAAmB;;CAUnB;;AARA;;CAJD;EAKE,mBAAmB;EAOpB;CANC;;AAED;;CARD;EASE,gBAAgB;EAGjB;CAFC;;AAIF,eAAe;;AAEf;;IAEI,aAAa;IACb,gBAAgB;IAChB,UAAU;IACV,YAAY;IACZ,iBAAiB;IACjB,SAAS;IACT,cAAc;CAqHjB;;AAnHA;;CAVD;EAWE,cAAc;EAkHf;CAjHC;;AAED;EACC,qBAAc;EAAd,cAAc;EACd,2BAAuB;MAAvB,uBAAuB;EACvB,sBAAwB;MAAxB,wBAAwB;EACxB,mBAAmB;EACnB,aAAa;EACb,eAAe;EACf,gBAAgB;EAChB,mBAAmB;EACnB,kBAAkB;CAClB;;AAED;EACC,mBAAmB;EACnB,QAAQ;EACR,SAAS;EACT,4BAA4B;EAC5B,YAAY;CACZ;;AAED;EACC,UAAU;EACV,iBAAiB;EACjB,eAA0B;EAC1B,iBAAiB;CAKjB;;AAHA;;CAND;EAOE,cAAc;EAEf;CADC;;AAGF;EACC,UAAU;EACV,kBAAkB;EAClB,mBAAmB;EACnB,SAAS;EACT,kBAAkB;EAClB,oBAAoB;EACpB,+BAA+B;EAC/B,WAAW;CAkBX;;AAhBA;GACC,sBAAsB;GACtB;;AAED;GACC,eAAgC;GAChC,mBAAmB;GACnB,YAAY;GACZ,aAAa;GACb,kBAAkB;GAClB,oBAAoB;GACpB;;AAED;;CAvBD;EAwBE,cAAc;EAEf;CADC;;AAGF;EACC,cAAc;EACd,oBAAoB;EACpB,iBAAiB;CAcjB;;AAbA;;CAJD;EAKE,cAAc;EAYf;CAXC;;AAED;GACC,sBAAsB;GACtB,aAAa;GACb,iBAAiB;CACjB;;AACD;GACC,eAAgC;CAChC;;AAIF;;CAEC;GACC,aAAa;GACb,sBAAsB;EACtB;CAED;;AAGA;;CADD;EAEE,WAAW;EAYZ;CAXC;;AACD;;CAJD;EAKE,QAAQ;EACR,UAAU;EAQX;CAPC;;AACD;;CARD;EASE,mBAAmB;EACnB,YAAY;EACZ,aAAa;EACb,OAAO;EAER;CADC;;AAID;;CADD;EAEE,WAAW;EAEZ;CADC;;AAEF;EACC,2CAA2C;CAC3C;;AAID;;CADD;EAEE,oBAAoB;EAMrB;CALC;;AAED;CACC,cAAc;CACd;;AAGF,aAAa;;AACb;;CAEC;EACC,aAAa;EACb,aAAa;EACb,uBAAuB;EACvB,mBAAmB;EACnB;;CAED;EACC,YAAY;EACZ,uBAAuB;EACvB,0BAA0B;EAC1B;;CAED;;ACzKD,mBAAmB;;AAGnB,aAAa;;AAKX;;CADD;EAEE,eAAe;EACf,YAAY;EAEb;CADC;;AAGF;EACC,eAAY;CACZ;;AAED;EACC,eAAe;CACf;;AAGF;CACC,eAAe;CACf,YAAY;CACZ,mBAAmB;CACnB;;AAED;CACC,aAAa;CACb;;AAED;CACC,gBAAgB;CAChB;;AAED;CACC,sBAAsB;IACnB,qBAAqB;IACrB,mBAAmB;CACtB;;AAED,oBAAoB;;AAEpB;CACC,sBAAsB;CACtB,gBAAgB;CAChB,0BAA0B;CAC1B,oBAA6B;CAC7B,iBAAiB;CACjB,eAAe;CACf,mBAAmB;CACnB;;AAED;CACC,oBAAoB;CACpB,eAAe;CACf;;AAED;CACC,eAAsB;CACtB;;AAED;CACC,eAAgC;CAChC;;AAED;CACC,cAAc;CACd;;AAED;CACC,eAAgB;CAChB,gBAAgB;CAChB;;AAED;CACC,sBAAsB;CACtB,UAAU;CACV,eAAe;CACf,iBAAiB;CAIjB;;AAHA;;CALD;EAME,kBAAkB;EAEnB;CADC;;AAGF,aAAa;;AAEb;IACI,aAAa;;CAMhB;;AAJA;EACC,cAAc;EACd;;AAIF;;CAEC,cAAc;CACd;;AAIA;EACC,cAAc;EACd;;AAGF,iBAAiB;;AAEjB;IACI,oBAA6B;IAC7B,mBAAmB;CACtB,aAAc;CAad;;AAXA;CACC,mBAAmB;CACnB;;AAED;EACC,cAAc;CACd;;AAED;EACC,iBAAiB;CACjB;;AAID;CACC,oBAAoB;CACpB;;ACrIF,UAAU;;AAEV;IACI,iBAAiB;CACpB,oBAAoB;CACpB,mBAAmB;CAuFnB;;AArFA;;;;EAIC,aAAa;EACb,wBAAwB;EACxB,UAAU;EACV,kCAAkC;EAClC,kBAAkB;EAClB,eAAgB;EAUhB;;AARA;GACC,eAAe;GACf,eAAe;GACf,eAA0B;GAC1B,gBAAgB;GAChB,YAAY;GACZ,aAAa;GACb;;AAGF;;;;EAIC,iBAAiB;EACjB,wCAAwC;EACxC,0BAA2B;EAK3B;;AAHA;GACC,eAAgB;GAChB;;AAGF;;CACC;GACC,cAAc;EACd;CACD;;AAED;EACC,eAAe;EACf,aAAa;CAIb;;AAHA;;CAHD;EAIE,cAAc;EAEf;CADC;;AAKD;CAEC,kBAAkB;CA8BlB;;AA5BA;IACC,eAAsB;IACtB,gBAAgB;IAChB,sBAAsB;IACtB,aAAa;IACb,qBAAqB;IACrB,YAAY;CACZ;;AAED;;CAbD;EAcE,mBAAmB;EACnB,aAAa;EACb,SAAS;EACT,gBAAgB;EAChB,iBAAiB;EACjB,sBAAsB;EACtB,WAAW;EAYZ;;CAVC;KACC,eAAsB;KACtB,gBAAgB;KAChB,sBAAsB;KACtB,aAAa;KACb,qBAAqB;KACrB,YAAY;EACZ;CACD;;AASH;EACC,cAAc;EACd;;AAED;EACC,eAAe;EACf,WAAY;EAsBZ;;AApBA;;CAEC,iBAAiB;CACjB,uBAAuB;CACvB;;AAOA;IACC,sBAAsB;IACtB,qBAAqB;CACrB;;AAGF;CACC,cAAc;CACd;;AAMH,gBAAgB;;AAEhB;CACC,mBAAmB;CACnB,UAAU;CACV,SAAS;CACT,cAAc;;CA8Fd;;AA5FA;;CACC;GACC,eAAe;GACf,2CAA2C;EAC3C;CACD;;AAED;;CAbD;EAcE,qBAAc;EAAd,cAAc;EACd,aAAa;EAmFd;CAlFC;;AAED;EACC,sBAAsB;EACtB,mBAAmB;EACnB,eAAe;EACf,mBAAmB;EACnB,uBAAuB;EACvB,eAAe;EACf,eAAqB;CA+CrB;;AA7CA;;CATD;EAUE,eAAe;EACf,aAAa;EACb,qBAAc;EAAd,cAAc;EACd,2BAAuB;MAAvB,uBAAuB;EACvB,sBAAwB;MAAxB,wBAAwB;EAwCzB;;CAtCC;IACC,eAAe;IACf,eAAe;EACf;CACD;;AAED;;CAtBD;EAuBE,cAAc;EACd,iBAAiB;EA8BlB;CA7BC;;AAGA;CACC,YAAY;CACZ,eAAe;CACf,mBAAmB;CACnB,UAAU;CACV,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,oBAAmB;CACnB,eAAuB;CAOvB;;AALA;;CAXD;EAYE,WAAW;EACX,aAAa;EAGd;CAFC;;AAGF;;CAlBD;EAmBE,eAAc;EAEf;CADC;;AAGF;CACC,oBAAoB;CACpB,eAAuB;CACvB;;AAGF;EACC,eAAe;EACf,WAAW;EACX,oBAAoB;EACpB,iBAAiB;EACjB,oBAAoB;EACpB,kBAAkB;EAClB,iBAAiB;CAMjB;;AALA;;CARD;EASE,WAAW;EACX,YAAY;EACZ,iBAAiB;EAElB;CADC;;AAGF;;CAzFD;EA0FE,mBAAmB;EACnB,UAAU;EACV,YAAY;EACZ,aAAa;EACb,iBAAiB;EAIlB;CAFC;;AAIF;CACC,mBAAmB;CACnB,SAAS;CACT,UAAU;CACV,qBAAc;CAAd,cAAc;CACd,aAAa;IACV,2BAAuB;QAAvB,uBAAuB;IACvB,gBAAgB;IAChB,uBAAoB;QAApB,oBAAoB;IACpB,sBAAwB;QAAxB,wBAAwB;CAC3B,qBAAsB;CAatB;;AAXA;CACC,cAAc;CACd;;AAED;CACC,cAAc;CACd;;AAED;;CApBD;EAqBE,cAAc;EAEf;CADC;;AAGF,oBAAoB;;AAEpB,mDAAmD;;AACnD;CACC,qBAAc;CAAd,cAAc;CACd,oBAAgB;KAAhB,eAAgB;;CAEhB,gCAAgC;;CA2EhC;;AAvEC;GACC,kCAAgC;CAChC;;AAVH,2BAaC,iCAAiC;CAkEjC;;AA/DE;IACC,wBAA8D;CAC9D;;AAFD;IACC,wBAA8D;CAC9D;;AAFD;IACC,oCAA8D;CAC9D;;AAIH;EACC,cAAkB;EAClB,mBAAuB;EACvB,uBAAuB;EACvB,qBAAqB;EACrB,aAAa;CAkDb;;AAhDA;CACC,gBAAgB;CAChB;;AAED;GACC,cAAc;CAUd;;AARA;IACC,eAA0B;IAC1B,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,kBAAkB;IAClB;;AAIF;GACC,mBAAmB;GACnB,aAAiB;GACjB,WAAe;GACf,oCAA4C;CAC5C;;AAED;;CA/BD;EAgCE,YAAY;EACZ,gBAAgB;EAChB,qBAAqB;EAqBtB;;CAnBC;IACC,uBAAuB;IACvB,WAAW;IACX,aAAa;IACb,SAAS;IACT,4BAA4B;IAC5B,YAAgB;EAChB;;CAED;IACC,UAAU;EACV;;CAED;IACC,cAAc;EACd;CAED;;AAMH,yBAAyB;;AAEzB;IACI,YAAY;IACZ,iBAAiB;IACjB,wCAAsB;IACtB,iBAAiB;IACjB,YAAY;IACZ,aAAa;CAChB;;AC7VD,iDAAiD;;AAEjD;CACC,mBAAmB;CACnB,YAAY;CACZ,uBAAuB;CACvB,mBAAmB;;CAkFnB;;AAhFA;;CAND;EAOE,uBAAuB;EA+ExB;CA9EC;;AAED;;CAVD;EAWE,4BAA4B;EA2E7B;CA1EC;;AAED;;CAdD;EAeE,yBAAyB;EAuE1B;CAtEC;;AAED;EACC,mBAAmB;EACnB,UAAU;EACV,mBAAmB;CACnB;;AAED;EACC,eAAe;EACf,YAAY;EACZ,mBAAmB;EACnB,aAAa;EACb,0BAAmC;EACnC,uBAAuB;CAiCvB;;AA/BA;CACC,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB;;AAED;GACC,mBAAmB;GACnB,SAAS;GACT,UAAU;GACV,wBAAwB;GACxB,yBAAyB;GACzB,6BAA6B;GAC7B,uBAAuB;GACvB,6BAA6B;GAC7B,iBAAiB;GACjB,qCAAqC;CAarC;;AAXA;IACC,eAAe;IACf,UAAU;IACV,iBAAiB;IACjB,mBAAmB;IACnB,SAAS;IACT,UAAU;IACV,gCAAgC;IAChC,0BAAkB;OAAlB,uBAAkB;QAAlB,sBAAkB;YAAlB,kBAAkB;IAClB;;AAMH;EACC,sBAAuB;CACvB;;AAED;EACC,mBAAmB;EACnB,WAAW;EACX,aAAa;EACb,UAAU;EACV,4BAA4B;EAC5B,cAAc;CACd;;AAIA;GACC,sBAAsB;CACtB;;AAMH;CACC,wBAAwB;IACrB,kBAAkB;IAClB,mBAAmB;CACtB,kBAAkB;CAClB,iBAAiB;IACd,qBAAc;IAAd,cAAc;CACjB,oBAAgB;KAAhB,gBAAgB;;CAMhB;;AAJA;EACC,YAAY;EACZ;;AAIF;CACC,cAAc;CACd;;AC3GD,uBAAuB;;AAEvB,8BAA8B;;AAE9B;IACI,eAAgB;CACnB;;AAED,uBAAuB;;AAEvB;CACC,sBAAsB;CACtB,gBAAgB;CAChB,kBAAkB;CAClB,sBAAsB;CACtB;;AAGD,wBAAwB;;AAExB;IACI,UAAU;IACV,cAAc;CACjB;;AAED;IACI,qBAAc;IAAd,cAAc;IACd,oBAAgB;QAAhB,gBAAgB;CACnB,kBAAkB;CAClB,oBAAoB;CACpB;;AAED;IACI,eAAW;QAAX,WAAW;IACX,YAAY;IACZ,cAAc;IACd,uBAAuB;IACvB,0BAA0B;CAC7B,kBAAkB;CAClB,oBAAoB;;CAsBpB;;AApBA;;CATD;EAUE,WAAW;EAmBZ;;CAjBC;GACC,YAAY;EACZ;CACD;;AAED;;CACC;GACC,WAAW;EACX;CACD;;AAED;;CACC;GACC,YAAY;EACZ;CACD;;AAIF;IACI,WAAW;CACd;;AAED,wCAAwC;;AACxC;CACC,aAAa;CACb;;AAED;CACC,aAAa;CACb;;AAED;;CAEC;;EAEC,YAAY;EACZ,YAAY;EACZ,UAAU;EACV;;CAED;;AAKA;EACC,cAAc;;EAcd;;AAZA;;CAHD;EAIE,cAAc;EAWf;CAVC;;AAED;GACC,UAAU;CACV;;AAED;GACC,iBAAiB;CACjB;;AAMH;CACC,aAAa;CACb,0BAA0B;CAC1B,wBAAwB;CACxB,gBAAgB;CAChB,mBAAmB;CACnB;;AAGA;EACC,0BAA0B;EAC1B,yBAAyB;EACzB,cAAc;EACd;;AAED;EACC,sCAAsC;EACtC;;AAED;EACC,kBAAkB;EAClB,gBAAgB;EAChB,gBAAgB;EAChB;;AAED;EACC,gBAAgB;EAChB;;AAED;EACC,YAAY;EACZ,aAAa;EACb,gBAAgB;EAChB,eAAe;EACf;;AAED;EACC,aAAa;EACb;;AAED;EACC,WAAW;EACX;;AAMF;CACC,cAAc;CACd;;AAED;;CAEC;EACC,WAAW;EACX;;CAED;EACC,eAAe;EACf,YAAY;EACZ,mBAAmB;EACnB,YAAY;EACZ,aAAa;EACb;;CAED;;AAED;;CAEC;EACC,aAAa;EACb;;CAED;;AAED;CACC,sBAAsB;CACtB;;AAED;;CAEC;;EAEC,eAAe;EA+Bf;;EA7BA;GACC,qBAAc;GAAd,cAAc;GACd,oBAAgB;OAAhB,gBAAgB;GAChB;;EAED;GACC,cAAe;GAsBf;;EApBA;EACC,YAAY;EACZ,oBAAoB;EACpB;;EAED;EACC,WAAW;EACX,uBAAuB;EACvB;;EAED;EACC,cAAc;EACd;;EAED;EACC,4BAA4B;EAC5B,kBAAkB;EAClB,YAAY;EACZ,eAAe;EACf;;CAIH;;ACjOD,iBAAiB;;AAMf;GACC,sBAAsB;GACtB;;AAIF;;GAIE;IACC,eAAe;IACf;;GAED;IACC,yBAAyB;IACzB,uBAAuB;IACvB,sBAAuB;;IAMvB;;GAJA;EACC,eAAsB;EACtB;;GAQF;IACC,eAAe;IACf;;GAED;IACC,eAAe;IACf,uBAAuB;IACvB;;GAED;IACC,yBAAyB;IACzB;CAIF;;AAIF;;CAEC,cAAe;;CAaf;;AAXA;CACC,YAAY;CACZ,yBAAyB;CACzB,gBAAgB;CAChB,kBAAkB;CAClB,aAAa;CACb,YAAY;CACZ,sBAAsB;CACtB,uBAAuB;CACvB;;AAIF;;IAEI,iBAAiB;IACjB,6BAA8B;CACjC;;AAED;IACI,iBAAiB;CACpB;;AAED;IACI,iBAAiB;CACpB;;AAED;IACI,cAAc;CACjB,2CAA4C;;CAO5C;;AALA;CACC,iBAAiB;CACjB,aAAa;CACb;;AAIF;IACI,cAAc;CACjB","file":"wp-optimize-admin.min.css","sourcesContent":["/* COLORS */\n$wp-blue: #0272AA;\n$wp-gray-dark: #555d66;\n$wp-gray-darker: #191e23;\n$wp-secondary-gray: #72777C;\n$wp-secondary-gray-light: #82868B;\n$wp-light-gray: #B5B9BE;\n$wp-lighter-gray: #EDEFF0;\n$success: #009B24;\n$error: #9B3600;\n$red: #E07575;\n$brand: #E46B1F;\n$spacing: 20px; \n\n/* OTHER VARS */\n$breakpoint-small: 782px;\n\n@import \"admin.css\";\n\n@import \"scss/layout\";\n\n@import \"scss/common\";\n\n@import \"scss/menu-and-tabs\";\n\n@import \"scss/image-list\";\n\n@import \"scss/plugin-family-tab\";\n\n@import \"scss/table-sorter\";\n",".wpo_hidden {\n\tdisplay: none;\n}\n\n.wpo_info {\n\tbackground: #FFF;\n\tcolor: #444;\n\tfont-family: -apple-system, \"BlinkMacSystemFont\", \"Segoe UI\", \"Roboto\", \"Oxygen-Sans\", \"Ubuntu\", \"Cantarell\", \"Helvetica Neue\", sans-serif;\n\tmargin: 2em auto;\n\tpadding: 1em 2em;\n\tmax-width: 700px;\n\t-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.13);\n}\n\n/* big button */\n.wpo_primary_big {\n\tpadding: 4px 6px !important;\n\tfont-size: 22px !important;\n\tmin-height: 34px;\n\tmin-width: 200px;\n}\n\n/* SECTIONS */\n.wpo_section {\n\tclear: both;\n\tpadding: 0;\n\tmargin: 0;\n}\n\n.wp-optimize-settings {\n\tmargin-bottom: 16px;\n}\n\n.wp-optimize-settings td > label {\n\tfont-weight: bold;\n\tdisplay: block;\n\tmargin-bottom: 8px;\n}\n\n/* COLUMN SETUP */\n.wpo_col {\n\tdisplay: block;\n\tfloat: left;\n\tmargin: 1% 0 1% 1%;\n}\n\n.wpo_col:first-child {\n\tmargin-left: 0;\n}\n\n/* GROUPING */\n.wpo_group:before,\n.wpo_group:after {\n\tcontent: \"\";\n\tdisplay: table;\n}\n\n.wpo_group:after {\n\tclear: both;\n}\n\n.wpo_half_width {\n\twidth: 48%;\n}\n\n/* GRID OF THREE */\n.wpo_span_3_of_3 {\n\twidth: 100%;\n}\n\n.wpo_span_2_of_3 {\n\twidth: 65.3%;\n}\n\n.wpo_span_1_of_3 {\n\twidth: 32.1%;\n}\n\n.nav-tab-wrapper {\n\tmargin: 14px 0px;\n}\n\n@media screen and (min-width: 549px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: block !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: none !important;\n\t}\n\n}\n\n@media screen and (max-width: 548px) {\n\n\t.show_on_default_sizes {\n\t\tdisplay: none !important;\n\t}\n\n\t.show_on_mobile_sizes {\n\t\tdisplay: block !important;\n\t}\n\n}\n\n@media screen and (max-width: 768px) {\n\n\t.wpo_col {\n\t\tmargin: 1% 0;\n\t}\n\n\t.wpo_span_3_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_2_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_span_1_of_3 {\n\t\twidth: 100%;\n\t}\n\n\t.wpo_half_width {\n\t\twidth: 100%;\n\t}\n\n}\n\n/* .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label */\n\n.wp-optimize-setting-is-sensitive td > label::before {\n\tcontent: \"\\f534\";\n\tfont-family: 'dashicons';\n\tdisplay: inline-block;\n\tmargin-right: 6px;\n\tfont-style: normal;\n\tline-height: 1;\n\tvertical-align: middle;\n\twidth: 20px;\n\tfont-size: 18px;\n\theight: 20px;\n\ttext-align: center;\n\tcolor: #72777C;\n}\n\n.wpo-run-optimizations__container {\n\tmargin-bottom: 15px;\n}\n\ntd.wp-optimize-settings-optimization-checkbox {\n\twidth: 18px;\n\tpadding-left: 4px;\n\tpadding-right: 0px;\n}\n\n.wp-optimize-settings-optimization-checkbox input {\n\tmargin: 0px;\n\tpadding: 0px;\n}\n\n#retention-period {\n\twidth: 60px;\n}\n\n.wp-optimize-settings-optimization-info {\n\tfont-size: 80%;\n\tfont-style: italic;\n}\n\n.wp-optimize-settings input[type=\"checkbox\"] {\n\t/* width: 18px; */\n}\n\n/* Added for the Image on Addons tab*/\nimg.addons {\n\tdisplay: block;\n\tmargin-left: auto;\n\tmargin-right: auto;\n\tmargin-bottom: 20px;\n\tmax-height: 44px;\n\theight: auto;\n\tmax-width: 100%;\n}\n\n.wpo_spinner {\n\twidth: 18px;\n\theight: 18px;\n\tpadding-left: 10px;\n\tdisplay: none;\n\tposition: relative;\n\ttop: 4px;\n}\n\n.optimization_spinner {\n\twidth: 20px;\n\theight: 20px;\n}\n\n#wp-optimize-auto-options {\n\tmargin: 20px 0 0 28px;\n}\n\n.display-none {\n\tdisplay: none;\n}\n\n.visibility-hidden {\n\tvisibility: hidden;\n}\n\n.margin-one-percent {\n\tmargin: 1%;\n}\n\n#save_done, .save-done {\n\tcolor: #D94F00;\n\tfont-size: 250% !important;\n}\n\n.wp-optimize-settings-optimization-info a {\n\ttext-decoration: underline;\n}\n\n.wp-optimize-settings-optimization-run-spinner {\n\tposition: relative;\n\ttop: 2px;\n}\n\n@media screen and (min-width: 782px) {\n\n\ttd.wp-optimize-settings-optimization-run {\n\t\twidth: 180px;\n\t\tpadding-top: 16px;\n\t}\n\n}\n\n#wpoptimize_table_list .tablesorter-filter-row {\n\tdisplay: none !important;\n}\n\n#wpoptimize_table_list .optimization_spinner {\n\tposition: relative;\n\ttop: 2px;\n\tleft: 5px;\n}\n\n#wpoptimize_table_list .optimization_spinner.visibility-hidden {\n\tdisplay: none;\n}\n\n#wpoptimize_table_list_filter {\n\twidth: 100%;\n\tmargin-bottom: 15px;\n}\n\n#wpoptimize_table_list_tables_not_found {\n\tdisplay: none;\n\tmargin: 20px 0;\n}\n\ndiv#wpoptimize_table_list_tables_not_found + h3 {\n\tmargin-top: 30px;\n}\n\n#optimize_form .select2-container,\n#wp-optimize-auto-options .select2-container {\n\twidth: 50% !important;\n\ttop: -5px;\n\theight: 40px;\n\tmargin-left: 10px;\n}\n\n#wpoptimize_table_list .optimization_done_icon {\n\tcolor: #009B24;\n\tfont-size: 200%;\n\tdisplay: inline-block;\n\tposition: relative;\n}\n\n#wpo_sitelist_show_moreoptions_cron {\n\tfont-size: 13px;\n\tline-height: 1.5;\n\tletter-spacing: 1px;\n}\n\n#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {\n\tdisplay: inline-block;\n}\n\n.wpo_remove_selected_sizes_btn__container {\n\tmargin-top: 20px;\n}\n\n.unused-image-sizes__label {\n\tdisplay: block;\n\tline-height: 1.6;\n}\n\n@media (max-width: 782px) {\n\n\t.unused-image-sizes__label {\n\t\tmargin-left: 30px;\n\t\tmargin-bottom: 15px;\n\t\tline-height: 1;\n\t}\n\n\t.unused-image-sizes__label input[type=checkbox] {\n\t\tmargin-left: -30px;\n\t}\n\n}\n\n#wp-optimize-nav-tab-contents-tables a {\n\tvertical-align: middle;\n}\n\n#wpo_sitelist_moreoptions,\n#wpo_sitelist_moreoptions_cron {\n\tmargin: 4px 16px 6px 0;\n\tborder: 1px dotted;\n\tpadding: 6px 10px;\n\tmax-height: 300px;\n\toverflow-y: scroll;\n\toverflow-x: hidden;\n}\n\n#wpo_sitelist_moreoptions {\n\tmax-height: 150px;\n\tmargin-right: 0;\n}\n\n#wpo_settings_sites_list li,\n#wpo_settings_sites_list li a {\n\tfont-size: 13px;\n\tline-height: 1.5;\n}\n\n#wpo_sitelist_moreoptions_cron li {\n\tpadding-left: 20px;\n}\n\n#wpo_import_error_message {\n\tdisplay: none;\n\tcolor: #9B0000;\n}\n\n#wpo_import_success_message {\n\tdisplay: none;\n\tcolor: #46B450;\n}\n\n#wp-optimize-logging-options {\n\tmargin-top: 10px;\n}\n\n/* Logger settings*/\n.wpo_logging_header {\n\tfont-weight: bold;\n\tborder-top: 1px solid #333;\n\tborder-bottom: 1px solid #333;\n\tpadding: 5px 0;\n\tmargin: 0;\n}\n\n.wpo_logging_row {\n\tborder-bottom: 1px solid #A1A2A3;\n\tpadding: 5px 0;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_options_title,\n.wpo_logging_status_title,\n.wpo_logging_actions_title,\n.wpo_logging_logger_row,\n.wpo_logging_options_row,\n.wpo_logging_status_row,\n.wpo_logging_actions_row {\n\tdisplay: inline-block;\n\tvertical-align: middle;\n}\n\n.wpo_logging_logger_title,\n.wpo_logging_logger_row {\n\twidth: 38%;\n}\n\n.wpo_logging_options_title,\n.wpo_logging_options_row {\n\twidth: 44%;\n}\n\n.wpo_logging_status_title,\n.wpo_logging_status_row {\n\twidth: 8%;\n}\n\n.wpo_logging_actions_title,\n.wpo_logging_actions_row {\n\twidth: 7%;\n}\n\n.wpo_logging_actions_row {\n\ttext-align: right;\n}\n\n.wpo_logging_options_row {\n\tword-wrap: break-word;\n}\n\n.wpo_logging_actions_row .dashicons-no-alt,\n.wpo_add_logger_form .dashicons-no-alt {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\twidth: 20px;\n\theight: 20px;\n\tborder-radius: 20px;\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tmargin-left: 5px;\n}\n\n.wpo_add_logger_form .dashicons-no-alt {\n\tmargin-top: 12px;\n\tmargin-right: 10px;\n\tfloat: right;\n}\n\n.wpo_logger_type {\n\twidth: 90%;\n\tmargin-top: 10px;\n}\n\n.wpo_logger_addition_option {\n\twidth: 100%;\n\tmargin-top: 5px;\n}\n\n.wpo_alert_notice {\n\tbackground-color: #F06666;\n\tcolor: #FFF;\n\tpadding: 5px;\n\tdisplay: block;\n\tmargin-bottom: 5px;\n\tborder-radius: 5px;\n}\n\n.wpo_error_field {\n\tborder-color: #F06666 !important;\n}\n\n.save_settings_reminder {\n\tdisplay: none;\n\tcolor: #333;\n\tpadding: 15px 20px;\n\tbackground-color: #F0A5A4;\n\tborder-radius: 3px;\n\tmargin: 15px 0;\n}\n\n#wpo_remove_selected_sizes {\n\tmargin-top: 20px;\n}\n\n.wpo_unused_images_buttons_wrap {\n\tdisplay: none;\n}\n\n.wpo_unused_images_container h3 {\n\tmin-width: 150px;\n}\n\n#wpo_unused_images, #wpo_smush_images_grid {\n\tmax-height: 500px;\n\toverflow-y: auto;\n}\n\n#wpo_unused_images a {\n\toutline: none;\n}\n\n#wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup {\n\tmargin-left: 1%;\n}\n\n.run-single-table-delete {\n\tmargin-top: 3px;\n}\n\n#wpo_browser_cache_output,\n#wpo_gzip_compression_output {\n\tbackground: #F0F0F0;\n\tpadding: 10px;\n\tborder: 1px solid #CCC;\n}\n\n#wpo_browser_cache_error_message,\n#wpo_gzip_compression_error_message,\n.wpo-error {\n\tcolor: #9B0000;\n}\n\n#wpo_browser_cache_expire_days,\n#wpo_browser_cache_expire_hours {\n\twidth: 50px;\n}\n\n.wpo-enabled .wpo-disabled {\n\tdisplay: none;\n}\n\n.wpo-disabled .wpo-enabled {\n\tdisplay: none;\n}","#wp-optimize-wrap {\n\tposition: relative;\n\tpadding-top: 100px;\n\n\t@media (min-width: 820px) {\n\t\tpadding-top: 120px;\n\t}\n\n\t@media(max-width: $breakpoint-small) {\n\t\tmargin-right: 0;\n\t}\n\n}\n\n/* DASHBOARD */\n\n.wpo-main-header {\n\n height: 77px;\n position: fixed;\n top: 32px;\n left: 160px;\n background: #FFF;\n right: 0;\n z-index: 9980;\n\n\t@media (min-width: 820px) {\n\t\theight: 105px;\n\t}\t\n\n\t.wpo-logo__container {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\tjustify-content: center;\n\t\tposition: relative;\n\t\theight: 100%;\n\t\tline-height: 1;\n\t\tfont-size: 1rem;\n\t\tpadding-left: 50px;\n\t\tmargin-left: 10px;\n\t}\n\n\t.wpo-logo {\n\t\tposition: absolute;\n\t\tleft: 0;\n\t\ttop: 50%;\n\t\ttransform: translateY(-50%);\n\t\twidth: 50px;\n\t}\n\n\t.wpo-subheader {\n\t\tmargin: 0;\n\t\tfont-weight: 300;\n\t\tcolor: $wp-secondary-gray;\n\t\tline-height: 1.3;\n\n\t\t@media (max-width: 1080px) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\tp.wpo-header-links {\n\t\tmargin: 0;\n\t\tfont-size: 0.7rem;\n\t\tposition: absolute;\n\t\tright: 0;\n\t\tpadding: 6px 15px;\n\t\tbackground: #EDEEEF;\n\t\tborder-bottom-left-radius: 5px;\n\t\tz-index: 1;\n\n\t\ta {\n\t\t\ttext-decoration: none;\n\t\t}\n\n\t\t.wpo-header-links__label {\n\t\t\tcolor: $wp-secondary-gray-light;\n\t\t\tposition: absolute;\n\t\t\tright: 100%;\n\t\t\twidth: 110px;\n\t\t\ttext-align: right;\n\t\t\tpadding-right: 10px;\n\t\t}\n\n\t\t@media (max-width: 820px) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\tp.wpo-header-links__mobile {\n\t\tpadding: 10px;\n\t\tbackground: #EDEEEF;\n\t\tmargin-bottom: 0;\n\t\t@media (min-width: 820px) {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\ta {\n\t\t\tdisplay: inline-block;\n\t\t\tpadding: 4px;\n\t\t\tfont-size: .8rem;\n\t\t}\n\t\t.wpo-header-links__label {\n\t\t\tcolor: $wp-secondary-gray-light;\n\t\t}\n\n\t}\n\n\t@media (max-width: 600px) {\n\t\t\n\t\t.wpo-logo__container strong {\n\t\t\twidth: 140px;\n\t\t\tdisplay: inline-block;\n\t\t}\n\n\t}\n\n\tbody.auto-fold & {\n\t\t@media (max-width: 960px) {\n\t\t\tleft: 36px;\n\t\t}\n\t\t@media (max-width: $breakpoint-small) {\n\t\t\tleft: 0;\n\t\t\ttop: 46px;\n\t\t}\n\t\t@media (max-width: 600px) {\n\t\t\tposition: absolute;\n\t\t\tleft: -10px;\n\t\t\tright: -10px;\n\t\t\ttop: 0;\n\t\t}\t\t\n\t}\n\n\tbody.folded & {\n\t\t@media (min-width: $breakpoint-small) {\n\t\t\tleft: 36px;\n\t\t}\n\t}\n\tbody.is-scrolled & {\n\t\tbox-shadow: 0 5px 25px rgba(0, 0, 0, 0.17);\n\t}\n}\n\n.wpo-page {\n\t@media (min-width: 769px) {\n\t\tpadding-right: 15px;\n\t}\n\n\t&:not(.active) {\n\t\tdisplay: none;\n\t}\n}\n\n/* Columns */\n@media (min-width: 1200px) {\n\n\t.wpo-tab-postbox.right-col {\n\t\twidth: 350px;\n\t\tfloat: right;\n\t\tbox-sizing: border-box;\n\t\tmargin-top: 3.1rem;\n\t}\n\n\t.right-col + .wpo-main {\n\t\tfloat: left;\n\t\tbox-sizing: border-box;\n\t\twidth: calc(100% - 380px);\n\t}\n\n}\n","/* Common BLOCKS */\n\n\n/* Buttons */\n\n#wp-optimize-wrap {\n\n\t.button-large {\n\t\t@media (max-width: $breakpoint-small) {\n\t\t\tdisplay: block;\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t.red {\n\t\tcolor: $red;\n\t}\n\n\tdiv[id*=\"_notice\"] div.updated {\n\t\tmargin-left: 0;\n\t}\n}\n\n.button.button-block {\n\tdisplay: block;\n\twidth: 100%;\n\ttext-align: center;\n}\n\n.wpo-refresh-button {\n\tfloat: right;\n}\n\n.wpo-refresh-button:hover {\n\tcursor: pointer;\n}\n\n.wpo-refresh-button .dashicons {\n\ttext-decoration: none;\n line-height: inherit;\n font-size: inherit;\n}\n\n/* Helper classes */\n\n*[class*=\"wpo-badge\"] {\n\tdisplay: inline-block;\n\tfont-size: .8em;\n\ttext-transform: uppercase;\n\tbackground: $wp-lighter-gray;\n\tpadding: 3px 5px;\n\tline-height: 1;\n\tborder-radius: 3px;\n}\n\n.wpo-badge__new {\n\tbackground: #DBE3E6;\n\tcolor: #00689a;\n}\n\n.wpo-text__dim {\n\tcolor: $wp-light-gray;\n}\n\n.wpo-fieldgroup .wpo-text__dim {\n\tcolor: $wp-secondary-gray-light;\n}\n\n.wpo-first-child {\n\tmargin-top: 0;\n}\n\n#save_done, .save-done {\n\tcolor: $success;\n\tfont-size: 250%;\n}\n\np.wpo-take-a-backup {\n\tdisplay: inline-block;\n\tmargin: 0;\n\tline-height: 1;\n\tpadding-top: 8px;\n\t@media (min-width: $breakpoint-small) {\n\t\tmargin-left: 20px;\n\t}\n}\n\n/* Postbox */\n\n#wp-optimize-nav-tab-wrapper ~ .wp-optimize-nav-tab-contents > .postbox {\n border: none;\n\n\t> h3:first-child {\n\t\tmargin-top: 0;\n\t}\n\n}\n\n.wpo-p25,\n.postbox.wpo-tab-postbox {\n\tpadding: 25px;\n}\n\n.wpo-tab-postbox {\n\t\n\t> h3:first-child {\n\t\tmargin-top: 0;\n\t}\n}\n\n/* Field group */\n\n.wpo-fieldgroup {\n background: $wp-lighter-gray;\n border-radius: 8px;\n\tpadding: 20px;\n\n\t&:not(:last-child) {\n\t\tmargin-bottom: 2em;\n\t}\n\n\t> *:first-child {\n\t\tmargin-top: 0;\n\t}\n\t\n\t> *:last-child {\n\t\tmargin-bottom: 0;\n\t}\n}\n\n.wpo-fieldgroup__subgroup {\n\t&:not(:last-of-type) {\n\t\tmargin-bottom: 20px;\n\t}\n}","/* TABS */\n\nh2#wp-optimize-nav-tab-wrapper {\n margin-bottom: 0;\n\tborder-bottom: none;\n\tposition: relative;\n\t\n\t.nav-tab,\n\t.nav-tab:hover,\n\t.nav-tab:focus,\n\t.nav-tab:focus:active {\n\t\tborder: none;\n\t\tbackground: transparent;\n\t\tmargin: 0;\n\t\tborder-top: 3px solid transparent;\n\t\tpadding: 7px 15px;\n\t\tcolor: $wp-blue;\n\n\t\t.dashicons {\n\t\t\tdisplay: block;\n\t\t\tmargin: 0 auto;\n\t\t\tcolor: $wp-secondary-gray;\n\t\t\tfont-size: 30px;\n\t\t\twidth: 30px;\n\t\t\theight: 30px;\n\t\t}\n\t}\n\t\n\t.nav-tab-active,\n\t.nav-tab-active:hover,\n\t.nav-tab-active:focus,\n\t.nav-tab-active:focus:active {\n\t\tbackground: #FFF;\n\t\tbox-shadow: 0 0 1px rgba(0, 0, 0, 0.04);\n\t\tborder-top-color: $wp-blue;\n\n\t\t.dashicons {\n\t\t\tcolor: $wp-blue;\n\t\t}\n\t}\n\n\t@media (max-width: $breakpoint-small) {\n\t\ta:not(.nav-tab-active) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\t\n\ta[role=\"toggle-menu\"] {\n\t\tdisplay: block;\n\t\tfloat: right;\n\t\t@media (min-width: $breakpoint-small) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n\n\ta.nav-tab.wp-optimize-nav-tab__back {\n\t\t&, &:focus:active {\t\n\n\t\t\ttext-align: right;\n\n\t\t\t.dashicons {\n\t\t\t\tcolor: $wp-light-gray;\n\t\t\t\tfont-size: 18px;\n\t\t\t\tdisplay: inline-block;\n\t\t\t\theight: auto;\n\t\t\t\tline-height: inherit;\n\t\t\t\twidth: 20px;\n\t\t\t}\n\n\t\t\t@media (min-width: $breakpoint-small) {\n\t\t\t\tposition: absolute;\n\t\t\t\tbottom: 14px;\n\t\t\t\tright: 0;\n\t\t\t\tfont-size: 12px;\n\t\t\t\tfont-weight: 400;\n\t\t\t\ttext-decoration: none;\n\t\t\t\tpadding: 0;\n\t\t\t\n\t\t\t\t.dashicons {\n\t\t\t\t\tcolor: $wp-light-gray;\n\t\t\t\t\tfont-size: 18px;\n\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\theight: auto;\n\t\t\t\t\tline-height: inherit;\n\t\t\t\t\twidth: 20px;\n\t\t\t\t}\n\t\t\t}\n\t\n\t\t}\n\t\n\t}\n}\n\n.wpo-mobile-menu-opened {\n\n\t.wpo-main .wpo-tab-postbox {\n\t\tdisplay: none;\n\t}\n\t\n\th2#wp-optimize-nav-tab-wrapper a {\n\t\tdisplay: block;\n\t\tfloat: none;\n\n\t\t&.nav-tab-active,\n\t\t&.nav-tab-active:focus {\n\t\t\tborder-top: none;\n\t\t\tborder-left: 3px solid;\n\t\t}\n\t\t\n\t\t&.nav-tab-active,\n\t\t&.nav-tab-active:focus,\n\t\t&:focus,\n\t\t&:hover,\n\t\t& {\n\t\t\t.dashicons {\n\t\t\t\tdisplay: inline-block; \n\t\t\t\tline-height: inherit;\n\t\t\t}\n\t\t}\n\n\t\t&[role=\"toggle-menu\"] {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\n}\n\n\n/* Pages MENU */\n\n.wpo-pages-menu {\n\tposition: absolute;\n\tbottom: 0;\n\tright: 0;\n\tdisplay: none;\n\n\t@media (max-width: 820px) {\n\t\t.opened + & {\n\t\t\tdisplay: block;\n\t\t\tbox-shadow: 0 5px 25px rgba(0, 0, 0, 0.17);\n\t\t}\n\t}\n\n\t@media (min-width: 821px) {\n\t\tdisplay: flex;\n\t\theight: 77px;\n\t}\n\n\t> a {\n\t\ttext-decoration: none;\n\t\tposition: relative;\n\t\tcolor: inherit;\n\t\ttext-align: center;\n\t\tbox-sizing: border-box;\n\t\tdisplay: block;\n\t\tcolor: $wp-gray-dark;\n\n\t\t@media (min-width: 821px) {\n\t\t\tpadding: 0 8px;\n\t\t\theight: 77px;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tjustify-content: center;\n\n\t\t\t> span {\n\t\t\t\tdisplay: block;\n\t\t\t\tmargin: 0 auto;\n\t\t\t}\n\t\t}\n\n\t\t@media (max-width: 820px) {\n\t\t\tpadding: 15px;\n\t\t\tfont-size: 1.2em;\n\t\t}\n\n\t\t&.active {\n\t\t\t&::after {\n\t\t\t\tcontent: '';\n\t\t\t\tdisplay: block;\n\t\t\t\tposition: absolute;\n\t\t\t\tbottom: 0;\n\t\t\t\tleft: 0;\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 3px;\n\t\t\t\tbackground: $brand;\n\t\t\t\tcolor: $wp-gray-darker;\n\n\t\t\t\t@media (max-width: 820px) {\n\t\t\t\t\twidth: 3px;\n\t\t\t\t\theight: 100%;\n\t\t\t\t}\n\n\t\t\t}\n\t\t\t@media (max-width: 820px) {\n\t\t\t\tcolor: $brand;\n\t\t\t}\n\t\t}\n\n\t\t&:hover {\n\t\t\tbackground: #F9F9F9;\n\t\t\tcolor: $wp-gray-darker;\n\t\t}\n\t}\n\n\tspan.separator {\n\t\tdisplay: block;\n\t\twidth: 2px;\n\t\tbackground: #EFEFEF;\n\t\tmargin-top: 18px;\n\t\tmargin-bottom: 18px;\n\t\tmargin-right: 5px;\n\t\tmargin-left: 5px;\n\t\t@media (max-width: 820px) {\n\t\t\twidth: 80%;\n\t\t\theight: 2px;\n\t\t\tmargin: 10px 10%;\n\t\t}\n\t}\n\n\t@media (max-width: 820px) {\n\t\ttext-align: center;\n\t\ttop: 100%;\n\t\twidth: 100%;\n\t\tbottom: auto;\n\t\tbackground: #FFF;\t\t\n\n\t}\n\n}\n\n#wp-optimize-nav-page-menu {\n\tposition: absolute;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\theight: 77px;\n flex-direction: column;\n padding: 0 20px;\n align-items: center;\n justify-content: center;\n\ttext-decoration: none;\n\n\t&:not(.opened) .dashicons-no-alt {\n\t\tdisplay: none;\n\t}\n\n\t&.opened .dashicons-menu {\n\t\tdisplay: none;\n\t}\n\n\t@media (min-width: 821px) {\n\t\tdisplay: none;\n\t}\n}\n\n/* DASHBOARD Menu */\n\n/* Calculate column width with a $spacing gutter */\n.wpo-dashboard-pages-menu {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\n\t/* Same size for 1 to 3 items */\n\t&[data-itemscount=\"1\"],\n\t&[data-itemscount=\"2\"],\n\t&[data-itemscount=\"3\"] {\n\t\t.wpo-dashboard-pages-menu__item {\n\t\t\twidth: calc(33.333% - 40px / 3);\n\t\t}\n\t}\n\n\t/* above 3 items, change sizes */\n\t@for $count from 4 to 6 {\n\t\t&[data-itemscount=\"$count\"] {\n\t\t\t.wpo-dashboard-pages-menu__item {\n\t\t\t\twidth: calc(100% / $count - $spacing * ($count - 1) / $count);\n\t\t\t}\n\t\t}\n\t}\n\n\t.postbox.wpo-dashboard-pages-menu__item {\n\t\tpadding: $spacing;\n\t\tmargin-right: $spacing;\n\t\tbox-sizing: border-box;\n\t\tpadding-bottom: 60px;\n\t\tmin-width: 0;\n\t\n\t\t&:last-child {\n\t\t\tmargin-right: 0;\n\t\t}\n\t\n\t\th3 {\n\t\t\tmargin-top: 0;\n\n\t\t\t.dashicons {\n\t\t\t\tcolor: $wp-secondary-gray;\n\t\t\t\tline-height: 1;\n\t\t\t\theight: 18px;\n\t\t\t\tmargin-top: -2px;\n\t\t\t\tmargin-right: 10px\n\t\t\t}\n\n\t\t}\n\n\t\ta {\n\t\t\tposition: absolute;\n\t\t\tbottom: $spacing;\n\t\t\tleft: $spacing;\n\t\t\twidth: calc(100% - $spacing * 2) !important;\n\t\t}\n\n\t\t@media (max-width: $breakpoint-small) {\n\t\t\twidth: 100%;\n\t\t\tmargin-right: 0;\n\t\t\tpadding-bottom: 20px;\n\n\t\t\ta.button.button-large {\n\t\t\t\twidth: auto !important;\n\t\t\t\tleft: auto;\n\t\t\t\tbottom: auto;\n\t\t\t\ttop: 50%;\n\t\t\t\ttransform: translateY(-50%);\n\t\t\t\tright: $spacing;\n\t\t\t}\n\n\t\t\th3 {\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\tp {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\n\t\t}\n\t\n\t}\n\n}\n\n/* Admin bar separator */\n\n#wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item {\n height: 2px;\n line-height: 2px;\n background: #ffffff17;\n margin: 5px 10px;\n width: auto;\n min-width: 0;\n}","/* Unused images / wpo_smush_image / image grid*/\n\n.wpo_unused_image, .wpo_smush_image {\n\tposition: relative;\n\tmargin: 4px;\n\twidth: calc(50% - 8px);\n\ttext-align: center;\n\n\t@media (min-width: 500px) {\n\t\twidth: calc(25% - 8px);\n\t}\n\n\t@media (min-width: $breakpoint-small) {\n\t\twidth: calc(16.6666% - 8px);\n\t}\n\n\t@media (min-width: 1100px) {\n\t\twidth: calc(12.5% - 8px);\n\t}\n\n\t.wpo_unused_image__input {\n\t\tposition: absolute;\n\t\ttop: 10px;\n\t\tvisibility: hidden;\n\t}\n\t\n\tlabel {\n\t\tdisplay: block;\n\t\twidth: 100%;\n\t\tposition: relative;\n\t\tpadding: 1px;\n\t\tborder: 3px solid $wp-lighter-gray;\n\t\tbox-sizing: border-box;\n\n\t\t&::before {\n\t\t\tcontent: \"\";\n\t\t\tdisplay: block;\n\t\t\tpadding-top: 100%;\n\t\t}\n\n\t\t.thumbnail {\n\t\t\tposition: absolute;\n\t\t\ttop: 1px;\n\t\t\tleft: 1px;\n\t\t\twidth: calc(100% - 2px);\n\t\t\theight: calc(100% - 2px);\n\t\t\tbackground-repeat: no-repeat;\n\t\t\tbackground-size: cover;\n\t\t\tbackground-position: 50% 50%;\n\t\t\toverflow: hidden;\n\t\t\tbackground: rgba(220, 220, 220, 0.2);\n\n\t\t\timg {\n\t\t\t\tdisplay: block;\n\t\t\t\tmargin: 0;\n\t\t\t\tmax-height: 100%;\n\t\t\t\tposition: absolute;\n\t\t\t\ttop: 50%;\n\t\t\t\tleft: 50%;\n\t\t\t\ttransform: translate(-50%,-50%);\n\t\t\t\tuser-select: none;\n\t\t\t}\n\n\t\t}\n\t\t\n\t}\n\t\n\t.wpo_unused_image__input:checked + label {\n\t\tborder-color: $wp-blue;\n\t}\n\n\ta, a.button, a.button:active {\n\t\tposition: absolute;\n\t\tz-index: 2;\n\t\tbottom: 13px;\n\t\tleft: 50%;\n\t\ttransform: translateX(-50%);\n\t\tdisplay: none;\n\t}\n\n\t&:hover {\n\n\t\ta, a.button, a.button:active {\n\t\t\tdisplay: inline-block;\n\t\t}\n\n\t}\n\n}\n\n#wpo_unused_images, #wpo_smush_images_grid {\n\twidth: calc(100% + 8px);\n margin-left: -4px;\n margin-right: -4px;\n\tmax-height: 500px;\n\toverflow-y: auto;\n display: flex;\n\tflex-wrap: wrap;\n\n\t.wpo-fieldgroup {\n\t\twidth: 100%;\n\t}\n\n}\n\n#wpo_unused_images a {\n\toutline: none;\n}","/* More Plugins page */\n\n/* Plugins family / Premium */\n\np.wpo-plugin-installed {\n color: $success;\n}\n\n/* Settings repeater */\n\n.wpo-repeater__add {\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tfont-weight: bold;\n\ttext-decoration: none;\n}\n\n\n/* Plugin familly tab */\n\n.wpo-plugin-family__premium h2 {\n margin: 0;\n padding: 25px;\n}\n\n.wpo-plugin-family__plugins {\n display: flex;\n flex-wrap: wrap;\n\tpadding-left: 1px;\n\tpadding-bottom: 1px;\n}\n\n.wpo-plugin-family__plugin {\n flex: auto;\n width: 100%;\n padding: 30px;\n box-sizing: border-box;\n border: 1px solid #E3E4E7;\n\tmargin-left: -1px;\n\tmargin-bottom: -1px;\n\n\t@media (min-width: $breakpoint-small) {\n\t\twidth: 50%;\n\n\t\t.wpo-plugin-family__free & {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n\t@media (max-width: 1080px) {\n\t\t.wpo-plugin-family__free & {\n\t\t\twidth: 50%;\n\t\t}\n\t}\n\n\t@media (max-width: $breakpoint-small) {\n\t\t.wpo-plugin-family__free & {\n\t\t\twidth: 100%;\n\t\t}\n\t}\n\n}\n\ndiv#wp-optimize-nav-tab-wpo_mayalso-may_also-contents .wpo-tab-postbox {\n padding: 0;\n}\n\n/* Added for WPO Premium Features tab */\n.wpo_feature_cont {\n\twidth: 64.5%;\n}\n\n.wpo_plugin_family_cont {\n\twidth: 34.5%;\n}\n\n@media (max-width: 1080px) {\n\n\t.wpo_feature_cont,\n\t.wpo_plugin_family_cont {\n\t\twidth: 100%;\n\t\tfloat: none;\n\t\tmargin: 0;\n\t}\n\n}\n\n.wpo_feature_cont,\n.wpo_plugin_family_cont {\n\n\theader {\n\t\tpadding: 20px;\n\n\t\t@media (max-width: 1080px) {\n\t\t\tpadding: 40px;\t\t\n\t\t}\n\n\t\th2 {\n\t\t\tmargin: 0;\n\t\t}\n\t\n\t\tp {\n\t\t\tmargin-bottom: 0;\n\t\t}\n\n\t}\n\n}\n\n.wpo_feat_table, .wpo_feat_th, .wpo_feat_table td {\n\tborder: none;\n\tborder-collapse: collapse;\n\tbackground-color: white;\n\tfont-size: 120%;\n\ttext-align: center;\n}\n\n.wpo_feat_table {\n\ttd {\n\t\tborder: 1px solid #F1F1F1;\n\t\tborder-bottom-width: 4px;\n\t\tpadding: 15px;\n\t}\n\n\ttd:nth-child(2), td:nth-child(3) {\n\t\tbackground: rgba(241, 241, 241, 0.38);\n\t}\n\n\tp {\n\t\tpadding: 0px 10px;\n\t\tmargin: 5px 0px;\n\t\tfont-size: 13px;\n\t}\n\n\th4 {\n\t\tmargin: 5px 0px;\n\t}\n\n\t.dashicons {\n\t\twidth: 25px;\n\t\theight: 25px;\n\t\tfont-size: 25px;\n\t\tline-height: 1;\n\t}\n\n\t.dashicons-yes, .updraft-yes {\n\t\tcolor: green;\n\t}\n\t\n\t.dashicons-no-alt, .updraft-no {\n\t\tcolor: red;\n\t}\n\n}\n\n\n\n.wpo-premium-image {\n\tdisplay: none;\n}\n\n@media screen and (min-width: 720px) {\n\n\t#wpoptimize_table_list_filter {\n\t\twidth: 40%;\n\t}\n\n\t.wpo-premium-image {\n\t\tdisplay: block;\n\t\tfloat: left;\n\t\tpadding: 16px 18px;\n\t\twidth: 30px;\n\t\theight: auto;\n\t}\n\n}\n\n@media screen and (min-width: 1220px) {\n\n\t.wpo_feat_table td:nth-child(2), .wpo_feat_table td:nth-child(3) {\n\t\twidth: 110px;\n\t}\n\n}\n\n.other-plugin-title {\n\ttext-decoration: none;\n}\n\n@media screen and (max-width: $breakpoint-small) {\n\n\ttable.wpo_feat_table {\n\n\t\tdisplay: block;\n\n\t\ttr {\n\t\t\tdisplay: flex;\n\t\t\tflex-wrap: wrap;\n\t\t}\n\n\t\ttd {\n\t\t\tdisplay: block;\n\n\t\t\t&:first-child {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-bottom: none;\n\t\t\t}\n\n\t\t\t&:not(:first-child) {\n\t\t\t\twidth: 50%;\n\t\t\t\tbox-sizing: border-box;\n\t\t\t}\n\n\t\t\t&:first-child:empty {\n\t\t\t\tdisplay: none;\n\t\t\t}\n\n\t\t\t&[data-colname]::before {\n\t\t\t\tcontent: attr(data-colname);\n\t\t\t\tfont-size: 0.8rem;\n\t\t\t\tcolor: #CCC;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\t\t}\n\t}\n\n}","\n/* tablesorter */\n\n#wp-optimize-wrap {\n\n\t.wp-list-table {\n\t\t\n\t\ttd {\n\t\t\tword-break: break-all; \n\t\t}\n\n\t}\n\n\t@media screen and (max-width: $breakpoint-small ) {\n\n\t\t.wp-list-table.wp-list-table-mobile-labels tbody {\n\n\t\t\t&, tr, th, td {\n\t\t\t\tdisplay: block;\n\t\t\t}\n\n\t\t\ttd {\n\t\t\t\tpadding: 3px 8px 3px 35%;\n\t\t\t\tword-break: break-word;\n\t\t\t\tbox-sizing: border-box; \n\n\t\t\t\t&::before {\n\t\t\t\t\tcolor: $wp-light-gray;\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\t\t\n\n\t\t.wp-list-table.wp-list-table-mobile-labels thead {\n\n\t\t\t&, tr {\n\t\t\t\tdisplay: block;\n\t\t\t}\n\n\t\t\tth.column-primary {\n\t\t\t\tdisplay: block;\n\t\t\t\tbox-sizing: border-box; \n\t\t\t}\n\n\t\t\tth:not(.column-primary) {\n\t\t\t\tdisplay: none !important; \n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nth:not(.sorter-false) .tablesorter-header-inner {\n\n\tcolor: #0074ab;\n\n\t&::after {\n\t\tcontent: '';\n\t\tfont-family: 'dashicons';\n\t\tfont-size: 20px;\n\t\tline-height: 20px;\n\t\theight: 20px;\n\t\twidth: 20px;\n\t\tdisplay: inline-block;\n\t\tvertical-align: bottom;\n\t}\n\n}\n\nth.tablesorter-header.tablesorter-headerAsc,\nth.tablesorter-header.tablesorter-headerDesc {\n font-weight: 500;\n border-bottom-color: $wp-blue;\n}\n\nth.tablesorter-header.tablesorter-headerDesc .tablesorter-header-inner::after {\n content: \"\\f140\";\n}\n\nth.tablesorter-header.tablesorter-headerAsc .tablesorter-header-inner::after {\n content: \"\\f142\";\n}\n\nth.tablesorter-header:focus {\n outline: none;\n\tbox-shadow: 0 0 3px rgba(0, 116, 171, 0.78);\n\n\t&:not(.tablesorter-headerAsc):not(.tablesorter-headerDesc) .tablesorter-header-inner::after {\n\t\tcontent: \"\\f142\";\n\t\topacity: 0.5;\n\t}\n\n}\n\n.tablesorter.hasFilters tr.filtered {\n display: none;\n}\n"]}
css/wp-optimize-notices.css CHANGED
@@ -7,6 +7,7 @@
7
  .updraft_notice_container {
8
  height: auto;
9
  overflow: hidden;
 
10
  }
11
 
12
  .updraft_advert_content_left {
@@ -59,6 +60,11 @@ h4.updraft_advert_heading {
59
  text-align: center;
60
  }
61
 
 
 
 
 
 
62
  @media screen and (min-width: 560px) {
63
 
64
  .updraft_advert_content_left {
@@ -67,3 +73,12 @@ h4.updraft_advert_heading {
67
 
68
  }
69
 
 
 
 
 
 
 
 
 
 
7
  .updraft_notice_container {
8
  height: auto;
9
  overflow: hidden;
10
+ padding: 7px;
11
  }
12
 
13
  .updraft_advert_content_left {
60
  text-align: center;
61
  }
62
 
63
+ .wpo-main-header + .updraft-ad-container,
64
+ .wpo-main-header + .updated {
65
+ margin-bottom: 20px;
66
+ }
67
+
68
  @media screen and (min-width: 560px) {
69
 
70
  .updraft_advert_content_left {
73
 
74
  }
75
 
76
+ @media screen and (max-width: 768px) {
77
+
78
+ .wpo-main-header + .updraft-ad-container,
79
+ .wpo-main-header + .updated {
80
+ margin-right: 0;
81
+ }
82
+
83
+ }
84
+
css/wp-optimize-notices.min.css CHANGED
@@ -1,2 +1,2 @@
1
- .updraft-ad-container{margin-left:0 !important}.updraft_notice_container{height:auto;overflow:hidden}.updraft_advert_content_left{float:none;width:65px}.updraft_advert_content_right{float:none;width:auto;overflow:hidden}.updraft_advert_bottom{margin:10px 0;padding:10px;font-size:140%;background-color:#FFF;border-color:#e6db55;border:1px solid;border-radius:4px}.updraft-advert-dismiss{float:right;font-size:13px;font-weight:normal}h3.updraft_advert_heading{margin-top:5px !important;margin-bottom:5px !important}h4.updraft_advert_heading{margin-top:2px !important;margin-bottom:3px !important}.updraft_center_content{text-align:center;margin-bottom:5px}.updraft_notice_link{padding-left:5px}.updraft_text_center{text-align:center}@media screen and (min-width:560px){.updraft_advert_content_left{float:left}}
2
  /*# sourceMappingURL=wp-optimize-notices.min.css.map */
1
+ .updraft-ad-container{margin-left:0 !important}.updraft_notice_container{height:auto;overflow:hidden;padding:7px}.updraft_advert_content_left{float:none;width:65px}.updraft_advert_content_right{float:none;width:auto;overflow:hidden}.updraft_advert_bottom{margin:10px 0;padding:10px;font-size:140%;background-color:#FFF;border-color:#e6db55;border:1px solid;border-radius:4px}.updraft-advert-dismiss{float:right;font-size:13px;font-weight:normal}h3.updraft_advert_heading{margin-top:5px !important;margin-bottom:5px !important}h4.updraft_advert_heading{margin-top:2px !important;margin-bottom:3px !important}.updraft_center_content{text-align:center;margin-bottom:5px}.updraft_notice_link{padding-left:5px}.updraft_text_center{text-align:center}.wpo-main-header+.updraft-ad-container,.wpo-main-header+.updated{margin-bottom:20px}@media screen and (min-width:560px){.updraft_advert_content_left{float:left}}@media screen and (max-width:768px){.wpo-main-header+.updraft-ad-container,.wpo-main-header+.updated{margin-right:0}}
2
  /*# sourceMappingURL=wp-optimize-notices.min.css.map */
css/wp-optimize-notices.min.css.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["css/wp-optimize-notices.css"],"names":[],"mappings":"AAAA,qBAAqB;;AAErB;CACC,4BAA4B;CAC5B;;AAED;CACC,aAAa;CACb,iBAAiB;CACjB;;AAED;CACC,YAAY;CACZ,YAAY;CACZ;;AAED;CACC,YAAY;CACZ,YAAY;CACZ,iBAAiB;CACjB;;AAED;CACC,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,uBAAuB;CACvB,sBAAsB;CACtB,kBAAkB;CAClB,mBAAmB;CACnB;;AAED;CACC,aAAa;CACb,gBAAgB;CAChB,oBAAoB;CACpB;;AAED;CACC,2BAA2B;CAC3B,8BAA8B;CAC9B;;AAED;CACC,2BAA2B;CAC3B,8BAA8B;CAC9B;;AAED;CACC,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,mBAAmB;CACnB;;AAED;;CAEC;EACC,YAAY;EACZ;;CAED","file":"wp-optimize-notices.min.css","sourcesContent":["/* CSS for adverts */\n\n.updraft-ad-container {\n\tmargin-left: 0px !important;\n}\n\n.updraft_notice_container {\n\theight: auto;\n\toverflow: hidden;\n}\n\n.updraft_advert_content_left {\n\tfloat: none;\n\twidth: 65px;\n}\n\n.updraft_advert_content_right {\n\tfloat: none;\n\twidth: auto;\n\toverflow: hidden;\n}\n\n.updraft_advert_bottom {\n\tmargin: 10px 0;\n\tpadding: 10px;\n\tfont-size: 140%;\n\tbackground-color: #FFF;\n\tborder-color: #E6DB55;\n\tborder: 1px solid;\n\tborder-radius: 4px;\n}\n\n.updraft-advert-dismiss {\n\tfloat: right;\n\tfont-size: 13px;\n\tfont-weight: normal;\n}\n\nh3.updraft_advert_heading {\n\tmargin-top: 5px !important;\n\tmargin-bottom: 5px !important;\n}\n\nh4.updraft_advert_heading {\n\tmargin-top: 2px !important;\n\tmargin-bottom: 3px !important;\n}\n\n.updraft_center_content {\n\ttext-align: center;\n\tmargin-bottom: 5px;\n}\n\n.updraft_notice_link {\n\tpadding-left: 5px;\n}\n\n.updraft_text_center {\n\ttext-align: center;\n}\n\n@media screen and (min-width: 560px) {\n\n\t.updraft_advert_content_left {\n\t\tfloat: left;\n\t}\n\n}\n\n"]}
1
+ {"version":3,"sources":["css/wp-optimize-notices.css"],"names":[],"mappings":"AAAA,qBAAqB;;AAErB;CACC,4BAA4B;CAC5B;;AAED;CACC,aAAa;CACb,iBAAiB;CACjB,aAAa;CACb;;AAED;CACC,YAAY;CACZ,YAAY;CACZ;;AAED;CACC,YAAY;CACZ,YAAY;CACZ,iBAAiB;CACjB;;AAED;CACC,eAAe;CACf,cAAc;CACd,gBAAgB;CAChB,uBAAuB;CACvB,sBAAsB;CACtB,kBAAkB;CAClB,mBAAmB;CACnB;;AAED;CACC,aAAa;CACb,gBAAgB;CAChB,oBAAoB;CACpB;;AAED;CACC,2BAA2B;CAC3B,8BAA8B;CAC9B;;AAED;CACC,2BAA2B;CAC3B,8BAA8B;CAC9B;;AAED;CACC,mBAAmB;CACnB,mBAAmB;CACnB;;AAED;CACC,kBAAkB;CAClB;;AAED;CACC,mBAAmB;CACnB;;AAED;;CAEC,oBAAoB;CACpB;;AAED;;CAEC;EACC,YAAY;EACZ;;CAED;;AAED;;CAEC;;EAEC,gBAAgB;EAChB;;CAED","file":"wp-optimize-notices.min.css","sourcesContent":["/* CSS for adverts */\n\n.updraft-ad-container {\n\tmargin-left: 0px !important;\n}\n\n.updraft_notice_container {\n\theight: auto;\n\toverflow: hidden;\n\tpadding: 7px;\n}\n\n.updraft_advert_content_left {\n\tfloat: none;\n\twidth: 65px;\n}\n\n.updraft_advert_content_right {\n\tfloat: none;\n\twidth: auto;\n\toverflow: hidden;\n}\n\n.updraft_advert_bottom {\n\tmargin: 10px 0;\n\tpadding: 10px;\n\tfont-size: 140%;\n\tbackground-color: #FFF;\n\tborder-color: #E6DB55;\n\tborder: 1px solid;\n\tborder-radius: 4px;\n}\n\n.updraft-advert-dismiss {\n\tfloat: right;\n\tfont-size: 13px;\n\tfont-weight: normal;\n}\n\nh3.updraft_advert_heading {\n\tmargin-top: 5px !important;\n\tmargin-bottom: 5px !important;\n}\n\nh4.updraft_advert_heading {\n\tmargin-top: 2px !important;\n\tmargin-bottom: 3px !important;\n}\n\n.updraft_center_content {\n\ttext-align: center;\n\tmargin-bottom: 5px;\n}\n\n.updraft_notice_link {\n\tpadding-left: 5px;\n}\n\n.updraft_text_center {\n\ttext-align: center;\n}\n\n.wpo-main-header + .updraft-ad-container,\n.wpo-main-header + .updated {\n\tmargin-bottom: 20px;\n}\n\n@media screen and (min-width: 560px) {\n\n\t.updraft_advert_content_left {\n\t\tfloat: left;\n\t}\n\n}\n\n@media screen and (max-width: 768px) {\n\n\t.wpo-main-header + .updraft-ad-container,\n\t.wpo-main-header + .updated {\n\t\tmargin-right: 0;\n\t}\n\n}\n\n"]}
includes/class-commands.php CHANGED
@@ -37,11 +37,11 @@ class WP_Optimize_Commands {
37
  }
38
 
39
  public function get_status_box_contents() {
40
- return WP_Optimize()->include_template('status-box-contents.php', true, array('optimize_db' => false));
41
  }
42
 
43
  public function get_optimizations_table() {
44
- return WP_Optimize()->include_template('optimizations-table.php', true);
45
  }
46
 
47
  /**
@@ -51,7 +51,8 @@ class WP_Optimize_Commands {
51
  * @return array An array containing the WPO translations and the "WP Optimize" tab's rendered contents
52
  */
53
  public function get_wp_optimize_contents() {
54
- $content = WP_Optimize()->include_template('optimize-table.php', true, array('optimize_db' => false));
 
55
 
56
  return array(
57
  'content' => $content,
@@ -66,7 +67,7 @@ class WP_Optimize_Commands {
66
  * @return array An array containing the WPO translations and the "Table Information" tab's rendered contents
67
  */
68
  public function get_table_information_contents() {
69
- $content = WP_Optimize()->include_template('tables.php', true, array('optimize_db' => false));
70
 
71
  return array(
72
  'content' => $content,
@@ -81,10 +82,13 @@ class WP_Optimize_Commands {
81
  * @return array An array containing the WPO translations and the "Settings" tab's rendered contents
82
  */
83
  public function get_settings_contents() {
84
- $admin_settings = WP_Optimize()->include_template('admin-settings-general.php', true, array('optimize_db' => false));
85
- $admin_settings .= WP_Optimize()->include_template('admin-settings-auto-cleanup.php', true, array('optimize_db' => false));
86
- $admin_settings .= WP_Optimize()->include_template('admin-settings-logging.php', true, array('optimize_db' => false));
87
- $admin_settings .= WP_Optimize()->include_template('admin-settings-sidebar.php', true, array('optimize_db' => false));
 
 
 
88
  $content = $admin_settings;
89
 
90
  return array(
@@ -289,7 +293,7 @@ class WP_Optimize_Commands {
289
  list ($total_size, $part2) = $this->optimizer->get_current_db_size();
290
 
291
  return array(
292
- 'table_list' => WP_Optimize()->include_template('tables-body.php', true, array('optimize_db' => false)),
293
  'total_size' => $total_size
294
  );
295
  }
@@ -364,6 +368,27 @@ class WP_Optimize_Commands {
364
  }
365
  }
366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  /**
368
  * Import WP-Optimize settings.
369
  *
37
  }
38
 
39
  public function get_status_box_contents() {
40
+ return WP_Optimize()->include_template('settings/status-box-contents.php', true, array('optimize_db' => false));
41
  }
42
 
43
  public function get_optimizations_table() {
44
+ return WP_Optimize()->include_template('database/optimizations-table.php', true);
45
  }
46
 
47
  /**
51
  * @return array An array containing the WPO translations and the "WP Optimize" tab's rendered contents
52
  */
53
  public function get_wp_optimize_contents() {
54
+ $content = WP_Optimize()->include_template('database/optimize-table.php', true, array('optimize_db' => false));
55
+ $content .= $this->get_status_box_contents();
56
 
57
  return array(
58
  'content' => $content,
67
  * @return array An array containing the WPO translations and the "Table Information" tab's rendered contents
68
  */
69
  public function get_table_information_contents() {
70
+ $content = WP_Optimize()->include_template('database/tables.php', true, array('optimize_db' => false));
71
 
72
  return array(
73
  'content' => $content,
82
  * @return array An array containing the WPO translations and the "Settings" tab's rendered contents
83
  */
84
  public function get_settings_contents() {
85
+ $admin_settings = '<form action="#" method="post" enctype="multipart/form-data" name="settings_form" id="settings_form">';
86
+ $admin_settings .= WP_Optimize()->include_template('settings/settings-general.php', true, array('optimize_db' => false));
87
+ $admin_settings .= WP_Optimize()->include_template('settings/settings-auto-cleanup.php', true, array('optimize_db' => false));
88
+ $admin_settings .= WP_Optimize()->include_template('settings/settings-logging.php', true, array('optimize_db' => false));
89
+ $admin_settings .= '<input id="wp-optimize-settings-save" class="button button-primary" type="submit" name="wp-optimize-settings" value="' . esc_attr('Save settings', 'wp-optimize') .'" />';
90
+ $admin_settings .= '</form>';
91
+ $admin_settings .= WP_Optimize()->include_template('settings/settings-trackback-and-comments.php', true, array('optimize_db' => false));
92
  $content = $admin_settings;
93
 
94
  return array(
293
  list ($total_size, $part2) = $this->optimizer->get_current_db_size();
294
 
295
  return array(
296
+ 'table_list' => WP_Optimize()->include_template('database/tables-body.php', true, array('optimize_db' => false)),
297
  'total_size' => $total_size
298
  );
299
  }
368
  }
369
  }
370
 
371
+ /**
372
+ * Enable or disable Gzip compression.
373
+ *
374
+ * @param array $params - ['enable' => true|false]
375
+ * @return array
376
+ */
377
+ public function enable_gzip_compression($params) {
378
+ return WP_Optimize()->get_gzip_compression()->enable_gzip_command_handler($params);
379
+ }
380
+
381
+
382
+ /**
383
+ * Enable or disable browser cache.
384
+ *
385
+ * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache]
386
+ * @return array
387
+ */
388
+ public function enable_browser_cache($params) {
389
+ return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params);
390
+ }
391
+
392
  /**
393
  * Import WP-Optimize settings.
394
  *
includes/class-updraft-smush-manager-commands.php CHANGED
@@ -139,7 +139,7 @@ class Updraft_Smush_Manager_Commands extends Updraft_Task_Manager_Commands_1_0 {
139
  $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
140
  $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
141
 
142
- $ui_update['summary'] = sprintf(__("A total of %d image(s) were compressed on this site, saving appoximately %s of space at an average of %02d percent per image.", 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], number_format($ui_update['percent_saved'], 2));
143
  $ui_update['failed'] = sprintf(__("%d image(s) could not be compressed. Please see the logs for more information or try again later.", 'wp-optimize'), $ui_update['failed_task_count']);
144
  $ui_update['pending'] = sprintf(__("%d image(s) images were selected for compressing previously, but were not all processed. You can either complete them now or cancel and retry later.", 'wp-optimize'), $ui_update['pending_tasks']);
145
  $ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
@@ -252,7 +252,7 @@ class Updraft_Smush_Manager_Commands extends Updraft_Task_Manager_Commands_1_0 {
252
  readfile($logfile);
253
  exit;
254
  } else {
255
- return new WP_Error('log_file_error', __('Log file does not exist or cant be read', 'wp-optimize'));
256
  }
257
 
258
  return $response;
139
  $ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
140
  $ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
141
 
142
+ $ui_update['summary'] = sprintf(__("A total of %d image(s) were compressed on this site, saving approximately %s of space at an average of %02d percent per image.", 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], number_format($ui_update['percent_saved'], 2));
143
  $ui_update['failed'] = sprintf(__("%d image(s) could not be compressed. Please see the logs for more information or try again later.", 'wp-optimize'), $ui_update['failed_task_count']);
144
  $ui_update['pending'] = sprintf(__("%d image(s) images were selected for compressing previously, but were not all processed. You can either complete them now or cancel and retry later.", 'wp-optimize'), $ui_update['pending_tasks']);
145
  $ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
252
  readfile($logfile);
253
  exit;
254
  } else {
255
+ return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
256
  }
257
 
258
  return $response;
includes/class-updraft-smush-manager.php CHANGED
@@ -431,7 +431,7 @@ class Updraft_Smush_Manager extends Updraft_Task_Manager_1_0 {
431
  */
432
  public function smush_js_translations() {
433
  return apply_filters('smush_js_translations', array(
434
- 'all_images_compressed' => __('All valid images are compresed now', 'wp-optimize'),
435
  'error_unexpected_response' => __('An unexpected response was received from the server.', 'wp-optimize'),
436
  'compress_single_image_dialog' => __('Please wait. Compressing the selected image.', 'wp-optimize'),
437
  'error_try_again_later' => __('Please try again later.', 'wp-optimize'),
431
  */
432
  public function smush_js_translations() {
433
  return apply_filters('smush_js_translations', array(
434
+ 'all_images_compressed' => __('All valid images are compressed now', 'wp-optimize'),
435
  'error_unexpected_response' => __('An unexpected response was received from the server.', 'wp-optimize'),
436
  'compress_single_image_dialog' => __('Please wait. Compressing the selected image.', 'wp-optimize'),
437
  'error_try_again_later' => __('Please try again later.', 'wp-optimize'),
includes/class-updraft-smush-task.php CHANGED
@@ -234,7 +234,7 @@ abstract class Updraft_Smush_Task extends Updraft_Task_1_0 {
234
  'connecting' => __('Connecting to API server', 'wp-optimize'),
235
  'processing_response' => __('Processing response', 'wp-optimize'),
236
  'backup_original' => __('Backing up original image', 'wp-optimize'),
237
- 'saving_image' => __('Saving optimised image', 'wp-optimize'),
238
  'completed' => __('Successful', 'wp-optimize'),
239
  );
240
 
234
  'connecting' => __('Connecting to API server', 'wp-optimize'),
235
  'processing_response' => __('Processing response', 'wp-optimize'),
236
  'backup_original' => __('Backing up original image', 'wp-optimize'),
237
+ 'saving_image' => __('Saving optimized image', 'wp-optimize'),
238
  'completed' => __('Successful', 'wp-optimize'),
239
  );
240
 
includes/class-wp-optimize-browser-cache.php ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('WPO_VERSION')) die('No direct access allowed');
4
+
5
+ require_once 'class-wp-optimize-htaccess.php';
6
+
7
+ /**
8
+ * Class WP_Optimize_Browser_Cache
9
+ */
10
+ class WP_Optimize_Browser_Cache {
11
+
12
+ private $_htaccess = null;
13
+
14
+ private $_options = null;
15
+
16
+ private $_wp_optimize = null;
17
+
18
+ /**
19
+ * Browser cache section in htaccess will wrapped with this comment
20
+ *
21
+ * @var string
22
+ */
23
+ private $_htaccess_section_comment = 'WP-Optimize Browser Cache';
24
+
25
+ /**
26
+ * WP_Optimize_Browser_Cache constructor.
27
+ */
28
+ public function __construct() {
29
+ $this->_wp_optimize = WP_Optimize();
30
+
31
+ $this->_htaccess = new WP_Optimize_Htaccess();
32
+
33
+ $this->_options = $this->_wp_optimize->get_options();
34
+ }
35
+
36
+ /***
37
+ * Check headers for Cache-Control and Etag. And if they are exist return true.
38
+ *
39
+ * @return bool|WP_Error
40
+ */
41
+ public function is_cache_enabled() {
42
+ $style = get_template_directory_uri() . '/style.css';
43
+
44
+ $response = wp_remote_get($style, array('timeout' => 15));
45
+
46
+ if (is_a($response, 'WP_Error')) return $response;
47
+
48
+ $headers = wp_remote_retrieve_headers($response);
49
+
50
+ if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
51
+ $headers = $headers->getAll();
52
+ }
53
+
54
+ if (false === array_key_exists('etag', $headers) && array_key_exists('cache-control', $headers)) {
55
+ return true;
56
+ }
57
+
58
+ if ($this->is_browser_cache_section_exists() && !$this->_wp_optimize->is_apache_module_loaded(array('mod_expires', 'mod_headers'))) {
59
+ return new WP_Error('Browser cache', __('We successfully updated your .htaccess file. But it seems one of Apache modules - mod_expires or mod_headers is not active.', 'wp-optimize'));
60
+ }
61
+
62
+ return false;
63
+ }
64
+
65
+ /**
66
+ * Enable browser cache - add settings into .htaccess.
67
+ *
68
+ * @param string $expiry_time
69
+ */
70
+ public function enable($expiry_time = '1 month') {
71
+ $this->_htaccess->update_commented_section($this->prepare_browser_cache_section($expiry_time), $this->_htaccess_section_comment);
72
+ $this->_htaccess->write_file();
73
+ }
74
+
75
+ /**
76
+ * Disable cache - remove settings from .htaccess added in enable() function.
77
+ */
78
+ public function disable() {
79
+ $this->_htaccess->remove_commented_section($this->_htaccess_section_comment);
80
+ $this->_htaccess->write_file();
81
+ }
82
+
83
+ /**
84
+ * Check if section with browser cache settings already exists.
85
+ */
86
+ public function is_browser_cache_section_exists() {
87
+ return $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
88
+ }
89
+
90
+ /**
91
+ * Handle for enable_browser_cache command used in WP_Optimize_Commands.
92
+ *
93
+ * @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache]
94
+ * @return array
95
+ */
96
+ public function enable_browser_cache_command_handler($params) {
97
+ $expire_days = isset($params['browser_cache_expire_days']) ? $params['browser_cache_expire_days'] : '';
98
+ $expire_hours = isset($params['browser_cache_expire_hours']) ? $params['browser_cache_expire_hours'] : '';
99
+
100
+ $current_expire_days = $this->_options->get_option('browser_cache_expire_days', '');
101
+ $current_expire_hours = $this->_options->get_option('browser_cache_expire_hours', '');
102
+
103
+ $section_updated = false;
104
+
105
+ $expiry_time = $this->prepare_interval($expire_days, $expire_hours);
106
+
107
+ $enable = ('' == $expiry_time) ? false : true;
108
+
109
+ /**
110
+ * If we don't need to do anything in .htaccess then return message.
111
+ */
112
+ if ($enable == $this->_htaccess->is_commented_section_exists() && $expire_days == $current_expire_days && $expire_hours == $current_expire_hours) {
113
+ $message = __('Browser static caching settings already exists in the .htaccess file', 'wp-optimize');
114
+
115
+ return array(
116
+ 'success' => true,
117
+ 'enabled' => $enable,
118
+ 'message' => $message,
119
+ );
120
+ }
121
+
122
+ if ($this->_htaccess->is_writable()) {
123
+ // update commented section
124
+
125
+ if ($enable) {
126
+ $this->enable($expiry_time);
127
+ } else {
128
+ $this->disable();
129
+ }
130
+
131
+ // read updated file.
132
+ $this->_htaccess->read_file();
133
+ // check if section added or removed successfully.
134
+ $section_exists = $this->_htaccess->is_commented_section_exists();
135
+ // set correct $section-updated flag.
136
+ $section_updated = $enable === $section_exists;
137
+ }
138
+
139
+ if ($section_updated) {
140
+ $enabled = $this->is_cache_enabled();
141
+
142
+ // save $expire value to options.
143
+ $this->_options->update_option('browser_cache_expire_days', $expire_days);
144
+ $this->_options->update_option('browser_cache_expire_hours', $expire_hours);
145
+
146
+ if (is_wp_error($enabled)) {
147
+ return array(
148
+ 'success' => true,
149
+ 'enabled' => $enabled,
150
+ 'error_message' => $enabled->get_error_message(),
151
+ );
152
+ } else {
153
+ return array(
154
+ 'success' => true,
155
+ 'enabled' => $enabled,
156
+ 'message' => __('We successfully updated your .htaccess file.', 'wp-optimize'),
157
+ );
158
+ }
159
+ } else {
160
+ $cache_section = $this->prepare_browser_cache_section($expiry_time);
161
+
162
+ if ($enable) {
163
+ $message = sprintf(__('We can\'t update your %s file. Please try to add following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
164
+ $output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
165
+ join(PHP_EOL, $this->_htaccess->get_flat_array($cache_section)).
166
+ PHP_EOL . $this->_htaccess->get_section_end_comment());
167
+ } else {
168
+ $message = sprintf(__('We can\'t update your %s file. Please try to remove following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
169
+ $output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
170
+ ' ... ... ... '.
171
+ PHP_EOL . $this->_htaccess->get_section_end_comment());
172
+ }
173
+
174
+ return array(
175
+ 'success' => false,
176
+ 'enabled' => $this->is_cache_enabled(),
177
+ 'error_message' => $message,
178
+ 'output' => $output,
179
+ );
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Use $days an $hours values to build correct time interval as a string like '2 days 3 hours' or empty string if date is empty.
185
+ *
186
+ * @param int $days
187
+ * @param int $hours
188
+ * @return string
189
+ */
190
+ private function prepare_interval($days, $hours) {
191
+
192
+ $days = floor($days);
193
+ $hours = floor($hours);
194
+
195
+ if (0 == $days && 0 == $hours) {
196
+ return '';
197
+ }
198
+
199
+ $parts = array();
200
+
201
+ // if hours value more than one day then fix it.
202
+ $days += floor($hours / 24);
203
+ $hours = $hours % 24;
204
+
205
+ $years = floor($days / 365);
206
+ $days = $days % 365;
207
+ $months = floor($days / 30);
208
+ $days = $days % 30;
209
+
210
+ if ($years > 0) {
211
+ $parts[] = $years . ($years > 1 ? ' years' : ' year');
212
+ }
213
+
214
+ if ($months > 0) {
215
+ $parts[] = $months . ($months > 1 ? ' months' : ' month');
216
+ }
217
+
218
+ if ($days > 0) {
219
+ $parts[] = $days . ($days > 1 ? ' days' : ' day');
220
+ }
221
+
222
+ if ($hours > 0) {
223
+ $parts[] = $hours . ($hours > 1 ? ' hours' : ' hour');
224
+ }
225
+
226
+ return join(' ', $parts);
227
+ }
228
+
229
+ /**
230
+ * Build browser cache section array.
231
+ *
232
+ * @param string $expire - value like - 1 day 12 hours 15 minutes
233
+ * @return array
234
+ */
235
+ public function prepare_browser_cache_section($expire) {
236
+ return array(
237
+ array(
238
+ '<IfModule mod_expires.c>',
239
+ 'ExpiresActive On',
240
+ 'ExpiresByType text/css "access '.$expire.'"',
241
+ 'ExpiresByType text/html "access '.$expire.'"',
242
+ 'ExpiresByType image/gif "access '.$expire.'"',
243
+ 'ExpiresByType image/png "access '.$expire.'"',
244
+ 'ExpiresByType image/jpg "access '.$expire.'"',
245
+ 'ExpiresByType image/jpeg "access '.$expire.'"',
246
+ 'ExpiresByType image/webp "access '.$expire.'"',
247
+ 'ExpiresByType image/x-icon "access '.$expire.'"',
248
+ 'ExpiresByType application/pdf "access '.$expire.'"',
249
+ 'ExpiresByType application/javascript "access '.$expire.'"',
250
+ 'ExpiresByType text/x-javascript "access '.$expire.'"',
251
+ 'ExpiresByType application/x-shockwave-flash "access '.$expire.'"',
252
+ 'ExpiresDefault "access '.$expire.'"',
253
+ '</IfModule>',
254
+ ),
255
+ '',
256
+ array(
257
+ '<IfModule mod_headers.c>',
258
+ array(
259
+ '<filesMatch "\.(ico|jpe?g|png|gif|webp|swf)$">',
260
+ 'Header set Cache-Control "public"',
261
+ '</filesMatch>',
262
+ ),
263
+ array(
264
+ '<filesMatch "\.(css)$">',
265
+ 'Header set Cache-Control "public"',
266
+ '</filesMatch>',
267
+ ),
268
+ array(
269
+ '<filesMatch "\.(js)$">',
270
+ 'Header set Cache-Control "private"',
271
+ '</filesMatch>',
272
+ ),
273
+ array(
274
+ '<filesMatch "\.(x?html?|php)$">',
275
+ 'Header set Cache-Control "private, must-revalidate"',
276
+ '</filesMatch>',
277
+ ),
278
+ '</IfModule>',
279
+ ),
280
+ '',
281
+ '#Disable ETag',
282
+ 'FileETag None',
283
+ );
284
+ }
285
+ }
includes/class-wp-optimize-gzip-compression.php ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class WP_Optimize_Gzip_Compression
5
+ */
6
+ class WP_Optimize_Gzip_Compression {
7
+
8
+ /**
9
+ * WP_Optimize_Htaccess instance.
10
+ *
11
+ * @var WP_Optimize_Htaccess
12
+ */
13
+ private $_htaccess = null;
14
+
15
+ /**
16
+ * WP_Optimize instance.
17
+ *
18
+ * @var WP_Optimize
19
+ */
20
+ private $_wp_optimize = null;
21
+
22
+ /**
23
+ * Gzip section in htaccess will wrapped with this comment
24
+ *
25
+ * @var string
26
+ */
27
+ private $_htaccess_section_comment = 'WP-Optimize Gzip compression';
28
+
29
+ /**
30
+ * WP_Optimize_Gzip_Compression constructor.
31
+ */
32
+ public function __construct() {
33
+ $this->_wp_optimize = WP_Optimize();
34
+ $this->_htaccess = $this->_wp_optimize->get_htaccess();
35
+ }
36
+
37
+ /**
38
+ * Make http request to theme style.css and check returned headers for gzip encoding option.
39
+ *
40
+ * @return bool|WP_Error
41
+ */
42
+ public function check_headers_for_gzip() {
43
+ // get url to theme style.css file.
44
+ $url = get_template_directory_uri() . '/style.css';
45
+ // trying to load style.css.
46
+ $response = wp_remote_get($url, array('timeout' => 10));
47
+
48
+ if (is_wp_error($response)) return $response;
49
+
50
+ // get returned headers.
51
+ $headers = wp_remote_retrieve_headers($response);
52
+
53
+ /**
54
+ * Since 4.6.0 wp_remote_retrieve_headers() returns Requests_Utility_CaseInsensitiveDictionary instance.
55
+ * Therefore we use getAll() function to get array with headers as array and keep compatibility with
56
+ * previous WordPress versions.
57
+ */
58
+ if (is_a($headers, 'Requests_Utility_CaseInsensitiveDictionary')) {
59
+ $headers = $headers->getAll();
60
+ }
61
+
62
+ // check if there exists Content-encoding header with gzip value.
63
+ if (array_key_exists('content-encoding', $headers) && preg_match('/gzip/i', $headers['content-encoding'])) {
64
+ return true;
65
+ }
66
+
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ * Make request to checkgzipcompression.com api and check if gzip option enabled.
72
+ *
73
+ * @return bool|WP_Error
74
+ */
75
+ public function check_api_for_gzip() {
76
+ $url = get_template_directory_uri() . '/style.css';
77
+
78
+ $api_url = 'https://checkgzipcompression.com/js/checkgzip.json?url=' . urlencode($url);
79
+
80
+ $result = wp_remote_get($api_url, array('timeout' => 10));
81
+
82
+ if (is_wp_error($result)) return $result;
83
+
84
+ if (!isset($result['body'])) return new WP_Error('Gzip', __("We can't definitely determine Gzip status as API doesn't return correct answer.", 'wp-optimize'));
85
+
86
+ $body = json_decode($result['body']);
87
+
88
+ if (isset($body->error) && $body->error) return new WP_Error('Gzip', __("We can't definitely determine Gzip status as API doesn't return correct answer.", 'wp-optimize'));
89
+
90
+ if ($body->result->gzipenabled && !$body->error) {
91
+ return true;
92
+ }
93
+
94
+ return false;
95
+ }
96
+
97
+ /**
98
+ * Check if Gzip compression is enabled.
99
+ *
100
+ * @return bool|WP_Error
101
+ */
102
+ public function is_gzip_compression_enabled() {
103
+ // trying to get info about gzip in headers.
104
+ $is_gzip_compression_enabled = $this->check_headers_for_gzip();
105
+
106
+ // if we got error then trying to get info from api otherwise get result from check_headers_for_gzip().
107
+ $is_gzip_compression_enabled = is_wp_error($is_gzip_compression_enabled) ? $this->check_api_for_gzip() : $is_gzip_compression_enabled;
108
+
109
+ // we can't determine then return WP_Error.
110
+ if (is_wp_error($is_gzip_compression_enabled)) return $is_gzip_compression_enabled;
111
+
112
+ // if Gzip is not enabled but we have added settings and Apache modules nt loaded then return error.
113
+ if (false == $is_gzip_compression_enabled && $this->is_gzip_compression_section_exists() && false === $this->_wp_optimize->is_apache_module_loaded(array('mod_filter', 'mod_deflate'))) {
114
+ return new WP_Error('Gzip', __('We successfully added Gzip compression settings into .htaccess file. But it seems one of Apache modules - mod_filter or mod_deflate is not active.', 'wp-optimize'));
115
+ }
116
+
117
+ return $is_gzip_compression_enabled;
118
+ }
119
+
120
+ /**
121
+ * Check if section with Gzip options already exists in htaccess file.
122
+ *
123
+ * @return bool
124
+ */
125
+ public function is_gzip_compression_section_exists() {
126
+ return $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
127
+ }
128
+
129
+ /**
130
+ * Enable Gzip compression - add settings into .htaccess.
131
+ */
132
+ public function enable() {
133
+ $this->_htaccess->update_commented_section($this->prepare_gzip_section(), $this->_htaccess_section_comment);
134
+ $this->_htaccess->write_file();
135
+ }
136
+
137
+ /**
138
+ * Disable Gzip compression - remove settings from .htaccess.
139
+ */
140
+ public function disable() {
141
+ $this->_htaccess->remove_commented_section($this->_htaccess_section_comment);
142
+ $this->_htaccess->write_file();
143
+ }
144
+
145
+ /**
146
+ * Handler for Gzip compression enable command, called from WP_Optimize_Commands.
147
+ *
148
+ * @param array $params - ['enable' => true|false]
149
+ * @return array
150
+ */
151
+ public function enable_gzip_command_handler($params) {
152
+ $section_updated = false;
153
+
154
+ $enable = (isset($params['enable']) && $params['enable']) ? true : false;
155
+
156
+ if ($this->_htaccess->is_writable()) {
157
+
158
+ // update commented section
159
+ if ($enable) {
160
+ $this->enable();
161
+ } else {
162
+ $this->disable();
163
+ }
164
+
165
+ // read updated file.
166
+ $this->_htaccess->read_file();
167
+ // check if section added or removed successfully.
168
+ $section_exists = $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
169
+ // set correct $section-updated flag.
170
+ $section_updated = $enable === $section_exists;
171
+ }
172
+
173
+ $is_gzip_compression_enabled = $this->is_gzip_compression_enabled();
174
+
175
+ if ($section_updated) {
176
+ return array(
177
+ 'success' => true,
178
+ 'enabled' => is_wp_error($is_gzip_compression_enabled) ? false : $is_gzip_compression_enabled,
179
+ // if we can't determine gzip status then return error message.
180
+ 'message' => is_wp_error($is_gzip_compression_enabled) ? $is_gzip_compression_enabled->get_error_message() : '',
181
+ );
182
+ } else {
183
+ $gzip_section = $this->prepare_gzip_section();
184
+
185
+ if ($is_gzip_compression_enabled) {
186
+ $message = sprintf(__('We can\'t update your %s file. Please try to remove following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
187
+ } else {
188
+ $message = sprintf(__('We can\'t update your %s file. Please try to add following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
189
+ }
190
+
191
+ return array(
192
+ 'success' => false,
193
+ 'enabled' => is_wp_error($is_gzip_compression_enabled) ? false : $is_gzip_compression_enabled,
194
+ 'message' => $message,
195
+ 'output' =>
196
+ htmlentities($this->_htaccess->get_section_begin_comment($this->_htaccess_section_comment).PHP_EOL.
197
+ join(PHP_EOL, $this->_htaccess->get_flat_array($gzip_section)).
198
+ PHP_EOL.$this->_htaccess->get_section_end_comment($this->_htaccess_section_comment)),
199
+ );
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Prepare array with options to switch on gzip in htaccess.
205
+ *
206
+ * @return array
207
+ */
208
+ private function prepare_gzip_section() {
209
+ return array(
210
+ array(
211
+ '<IfModule mod_filter.c>',
212
+ array(
213
+ '<IfModule mod_deflate.c>',
214
+ '# Compress HTML, CSS, JavaScript, Text, XML and fonts',
215
+ 'AddType application/vnd.ms-fontobject .eot',
216
+ 'AddType font/ttf .ttf',
217
+ 'AddType font/otf .otf',
218
+ 'AddType font/x-woff .woff',
219
+ 'AddType image/svg+xml .svg',
220
+ '',
221
+ 'AddOutputFilterByType DEFLATE application/javascript',
222
+ 'AddOutputFilterByType DEFLATE application/rss+xml',
223
+ 'AddOutputFilterByType DEFLATE application/vnd.ms-fontobject',
224
+ 'AddOutputFilterByType DEFLATE application/x-font',
225
+ 'AddOutputFilterByType DEFLATE application/x-font-opentype',
226
+ 'AddOutputFilterByType DEFLATE application/x-font-otf',
227
+ 'AddOutputFilterByType DEFLATE application/x-font-truetype',
228
+ 'AddOutputFilterByType DEFLATE application/x-font-ttf',
229
+ 'AddOutputFilterByType DEFLATE application/x-font-woff',
230
+ 'AddOutputFilterByType DEFLATE application/x-javascript',
231
+ 'AddOutputFilterByType DEFLATE application/xhtml+xml',
232
+ 'AddOutputFilterByType DEFLATE application/xml',
233
+ 'AddOutputFilterByType DEFLATE font/opentype',
234
+ 'AddOutputFilterByType DEFLATE font/otf',
235
+ 'AddOutputFilterByType DEFLATE font/ttf',
236
+ 'AddOutputFilterByType DEFLATE font/woff',
237
+ 'AddOutputFilterByType DEFLATE image/svg+xml',
238
+ 'AddOutputFilterByType DEFLATE image/x-icon',
239
+ 'AddOutputFilterByType DEFLATE text/css',
240
+ 'AddOutputFilterByType DEFLATE text/html',
241
+ 'AddOutputFilterByType DEFLATE text/javascript',
242
+ 'AddOutputFilterByType DEFLATE text/plain',
243
+ 'AddOutputFilterByType DEFLATE text/xml',
244
+ '',
245
+ '# Remove browser bugs (only needed for really old browsers)',
246
+ 'BrowserMatch ^Mozilla/4 gzip-only-text/html',
247
+ 'BrowserMatch ^Mozilla/4\.0[678] no-gzip',
248
+ 'BrowserMatch \bMSIE !no-gzip !gzip-only-text/html',
249
+ 'Header append Vary User-Agent',
250
+ '</IfModule>',
251
+ ),
252
+ '</IfModule>',
253
+ ),
254
+ );
255
+ }
256
+ }
includes/class-wp-optimize-htaccess.php ADDED
@@ -0,0 +1,309 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('WPO_VERSION')) die('No direct access allowed');
4
+
5
+ class WP_Optimize_Htaccess {
6
+
7
+ /**
8
+ * Full path to .htaccess file.
9
+ *
10
+ * @var string
11
+ */
12
+ private $_htaccess_file = '';
13
+
14
+ /**
15
+ * Structured content of .htaccess file.
16
+ *
17
+ * @var array
18
+ */
19
+ private $_file_tree = array();
20
+
21
+ /**
22
+ * WP_Optimize_Htaccess constructor.
23
+ *
24
+ * @param string $htaccess_file Full path to .htaccess file.
25
+ */
26
+ public function __construct($htaccess_file = '') {
27
+ $this->_htaccess_file = ('' != $htaccess_file) ? $htaccess_file : get_home_path() . '.htaccess';
28
+ // read .htaccess content into $_file_tree.
29
+ $this->read_file();
30
+ }
31
+
32
+ /**
33
+ * Returns .htaccess filename.
34
+ *
35
+ * @return string
36
+ */
37
+ public function get_filename() {
38
+ return $this->_htaccess_file;
39
+ }
40
+
41
+ /**
42
+ * Checks if .htaccess file exists.
43
+ *
44
+ * @return bool
45
+ */
46
+ public function is_exists() {
47
+ return is_file($this->_htaccess_file);
48
+ }
49
+
50
+ /**
51
+ * Checks if .htaccess file is readaable.
52
+ *
53
+ * @return bool
54
+ */
55
+ public function is_readable() {
56
+ return is_readable($this->_htaccess_file);
57
+ }
58
+
59
+ /**
60
+ * Checks if .htaccess file is writable.
61
+ *
62
+ * @return bool
63
+ */
64
+ public function is_writable() {
65
+ return is_writable($this->_htaccess_file);
66
+ }
67
+
68
+ /**
69
+ * Read content of .htaccess file and store it as a tree in $_file_tree variable.
70
+ * For ex.
71
+ * [0] => '# BEGIN WordPress',
72
+ * [1] => [
73
+ * [0] => '<IfModule mod_rewrite.c>',
74
+ * [1] => 'RewriteEngine On',
75
+ * [2] => 'RewriteBase /',
76
+ * [3] => 'RewriteRule ^index\.php$ - [L]',
77
+ * [4] => 'RewriteCond %{REQUEST_FILENAME} !-f',
78
+ * [5] => 'RewriteCond %{REQUEST_FILENAME} !-d',
79
+ * [6] => 'RewriteRule . /index.php [L]',
80
+ * [7] => '</IfModule>',
81
+ * [2] => '# END WordPress'
82
+ *
83
+ * @return void
84
+ */
85
+ public function read_file() {
86
+ if (false == $this->is_exists() || false == $this->is_readable()) return;
87
+
88
+ $content = file_get_contents($this->_htaccess_file);
89
+
90
+ $content = explode("\n", $content);
91
+
92
+ $content_tree = array();
93
+
94
+ $section = array();
95
+ $sections = array();
96
+
97
+ foreach ($content as $line) {
98
+ $line = trim($line);
99
+
100
+ if (preg_match("/^\<\/(.+)(\s.*)?\>/", $line, $matches)) {
101
+ $section[] = $line;
102
+
103
+ // close section
104
+ if (!empty($sections)) {
105
+ $_section = $section;
106
+ $section = array_pop($sections);
107
+ $section[] = $_section;
108
+ } else {
109
+ $content_tree[] = $section;
110
+ $section = array();
111
+ }
112
+ } elseif (preg_match('/^\<(.+)>/', $line, $matches)) {
113
+ // open section
114
+ if (!empty($section)) {
115
+ $sections[] = $section;
116
+ }
117
+
118
+ $section = array();
119
+ $section[] = $line;
120
+ } elseif (!empty($section)) {
121
+ $section[] = $line;
122
+ } else {
123
+ $content_tree[] = $line;
124
+ }
125
+ }
126
+
127
+ $this->_file_tree = $content_tree;
128
+ }
129
+
130
+ /**
131
+ * Write current $_file_tree content into .htaccess file.
132
+ */
133
+ public function write_file() {
134
+ $content = implode(PHP_EOL, $this->get_flat_array($this->_file_tree));
135
+ file_put_contents($this->_htaccess_file, $content);
136
+ }
137
+
138
+ /**
139
+ * Recursive function used to prepare data for output - build flat array from $_file_tree.
140
+ *
141
+ * @param array $array
142
+ * @param string $prefix
143
+ *
144
+ * @return array
145
+ */
146
+ public function get_flat_array($array, $prefix = '') {
147
+ $flat_array = array();
148
+
149
+ if (!empty($array)) {
150
+ foreach ($array as $item) {
151
+ if (is_array($item)) {
152
+ $item = $this->get_flat_array($item, "\t");
153
+ $flat_array = array_merge($flat_array, $item);
154
+ } else {
155
+ $flat_array[] = $item;
156
+ }
157
+ }
158
+ }
159
+
160
+ reset($flat_array);
161
+ $first = key($flat_array);
162
+ end($flat_array);
163
+ $last = key($flat_array);
164
+
165
+ foreach ($flat_array as $key => $value) {
166
+ if ('' != $value && '#' == $value[0]) {
167
+ // never add prefix for comment lines.
168
+ $flat_array[$key] = $value;
169
+ } else {
170
+ $flat_array[$key] = ($key == $first || $key == $last) ? $value : $prefix . $value;
171
+ }
172
+ }
173
+
174
+ return $flat_array;
175
+ }
176
+
177
+ /**
178
+ * Update commented section in array $_file_tree, i.e. section wrapped with comments
179
+ * # BEGIN WP-Optimize Browser Cache
180
+ * ...
181
+ * # END WP-Optimize Browser Cache
182
+ *
183
+ * @param array $content
184
+ * @param string $section
185
+ */
186
+ public function update_commented_section($content, $section = 'WP-Optimize Browser Cache') {
187
+ $section_begin = $this->get_section_begin_comment($section);
188
+ $section_end = $this->get_section_end_comment($section);
189
+
190
+ // add begin-end section comments.
191
+ array_unshift($content, $section_begin);
192
+ array_push($content, $section_end);
193
+
194
+ $section_index = $this->search_commented_section($section);
195
+
196
+ // check if section with cache settings already in the file.
197
+ if (false === $section_index) {
198
+ // no section in file then add it to the end of file.
199
+ $this->_file_tree = array_merge($this->_file_tree, $content);
200
+ } else {
201
+ $remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
202
+ array_splice($this->_file_tree, $section_index['begin'], $remove_length, $content);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Removes commented section in $_file_tree, i.e. section wrapped with comments
208
+ * # BEGIN WP-Optimize Browser Cache
209
+ * ...
210
+ * # END WP-Optimize Browser Cache
211
+ *
212
+ * @param string $comment
213
+ *
214
+ * @return bool
215
+ */
216
+ public function remove_commented_section($comment = 'WP-Optimize Browser Cache') {
217
+ $section_index = $this->search_commented_section($comment);
218
+
219
+ if (false === $section_index) return false;
220
+
221
+ $remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
222
+ array_splice($this->_file_tree, $section_index['begin'], $remove_length);
223
+
224
+ $this->_file_tree = array_values($this->_file_tree);
225
+
226
+ return true;
227
+ }
228
+
229
+ /**
230
+ * Check if section exists wrapped by comments like
231
+ *
232
+ * # BEGIN WP-Optimize Browser Cache
233
+ * ...
234
+ * # END WP-Optimize Browser Cache
235
+ *
236
+ * @param string $section
237
+ * @return bool
238
+ */
239
+ public function is_commented_section_exists($section = 'WP-Optimize Browser Cache') {
240
+ $search = $this->search_commented_section($section);
241
+
242
+ return (false === $search) ? false : true;
243
+ }
244
+
245
+ /**
246
+ * Search section in $_file_tree array wrapped by begin and end comments.
247
+ *
248
+ * @param string $section
249
+ * @return array|bool
250
+ */
251
+ private function search_commented_section($section) {
252
+ $section_begin = $this->get_section_begin_comment($section);
253
+ $section_end = $this->get_section_end_comment($section);
254
+
255
+ $section_begin_index = $section_end_index = false;
256
+
257
+ $section_begin_normalized = $this->normalize_string($section_begin);
258
+ $section_end_normalized = $this->normalize_string($section_end);
259
+
260
+ foreach ($this->_file_tree as $i => $value) {
261
+ // if it is subsection then we don't go in deep.
262
+ if (is_array($value)) continue;
263
+
264
+ $value = $this->normalize_string($value);
265
+
266
+ if ($value == $section_begin_normalized) $section_begin_index = $i;
267
+ if ($value == $section_end_normalized) $section_end_index = $i;
268
+ }
269
+
270
+ if (false == $section_begin_index) {
271
+ return false;
272
+ } else {
273
+ return array(
274
+ 'begin' => $section_begin_index,
275
+ 'end' => $section_end_index,
276
+ );
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Generate begin cache section comment.
282
+ *
283
+ * @param string $section
284
+ * @return string
285
+ */
286
+ public function get_section_begin_comment($section = 'WP-Optimize Browser Cache') {
287
+ return '# BEGIN ' . $section;
288
+ }
289
+
290
+ /**
291
+ * Generate end cache section comment.
292
+ *
293
+ * @param string $section
294
+ * @return string
295
+ */
296
+ public function get_section_end_comment($section = 'WP-Optimize Browser Cache') {
297
+ return '# END ' . $section;
298
+ }
299
+
300
+ /**
301
+ * Normalize string - make all letters lowercase and remove spaces.
302
+ *
303
+ * @param string $string
304
+ * @return string
305
+ */
306
+ private function normalize_string($string) {
307
+ return strtolower(str_replace(array("\n", "\r", ' '), '', $string));
308
+ }
309
+ }
includes/class-wp-optimizer.php CHANGED
@@ -229,6 +229,9 @@ class WP_Optimizer {
229
  $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
230
 
231
  if (isset($optimization_options[$option_id])) {
 
 
 
232
  if ('auto' == $which_option && empty($optimization->available_for_auto)) continue;
233
 
234
  $this->change_time_limit();
@@ -289,7 +292,13 @@ class WP_Optimizer {
289
  $table_status[$index]->is_type_supported = WP_Optimize()->get_db_info()->is_table_type_optimize_supported($table_name);
290
  // add information about corrupted tables.
291
  $table_status[$index]->is_needing_repair = WP_Optimize()->get_db_info()->is_table_needing_repair($table_name);
292
-
 
 
 
 
 
 
293
  }
294
  }
295
 
@@ -310,6 +319,14 @@ class WP_Optimizer {
310
  $table->is_type_supported = WP_Optimize()->get_db_info()->is_table_type_optimize_supported($table_name);
311
  $table->is_needing_repair = WP_Optimize()->get_db_info()->is_table_needing_repair($table_name);
312
 
 
 
 
 
 
 
 
 
313
  $table = apply_filters('wp_optimize_get_table', $table);
314
  return $table;
315
  }
229
  $option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
230
 
231
  if (isset($optimization_options[$option_id])) {
232
+ // if options saved as a string then compare with string (for support different versions)
233
+ if (is_string($optimization_options[$option_id]) && 'false' === $optimization_options[$option_id]) continue;
234
+
235
  if ('auto' == $which_option && empty($optimization->available_for_auto)) continue;
236
 
237
  $this->change_time_limit();
292
  $table_status[$index]->is_type_supported = WP_Optimize()->get_db_info()->is_table_type_optimize_supported($table_name);
293
  // add information about corrupted tables.
294
  $table_status[$index]->is_needing_repair = WP_Optimize()->get_db_info()->is_table_needing_repair($table_name);
295
+ // add information about using table by any of installed plugins.
296
+ $table_status[$index]->plugin = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
297
+ $table_status[$index]->is_using = WP_Optimize()->get_db_info()->is_table_using_by_plugin($table_name);
298
+ // if table belongs to any plugin then add plugins status.
299
+ if ($table_status[$index]->plugin) {
300
+ $table_status[$index]->plugin_status = WP_Optimize()->get_db_info()->get_plugin_status($table_status[$index]->plugin);
301
+ }
302
  }
303
  }
304
 
319
  $table->is_type_supported = WP_Optimize()->get_db_info()->is_table_type_optimize_supported($table_name);
320
  $table->is_needing_repair = WP_Optimize()->get_db_info()->is_table_needing_repair($table_name);
321
 
322
+ // add information about using table by any of installed plugins.
323
+ $table->plugin = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
324
+ $table->is_using = WP_Optimize()->get_db_info()->is_table_using_by_plugin($table_name);
325
+ // if table belongs to any plugin then add plugins status.
326
+ if ($table->plugin) {
327
+ $table->plugin_status = WP_Optimize()->get_db_info()->get_plugin_status($table->plugin);
328
+ }
329
+
330
  $table = apply_filters('wp_optimize_get_table', $table);
331
  return $table;
332
  }
includes/updraft-notices.php CHANGED
@@ -36,7 +36,7 @@ abstract class Updraft_Notices_1_0 {
36
  */
37
  abstract protected function notices_init();
38
 
39
- protected function is_plugin_installed($product = null, $also_require_active = false) {
40
  if ($also_require_active) return class_exists($product);
41
  if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
42
  $plugins = get_plugins();
36
  */
37
  abstract protected function notices_init();
38
 
39
+ public function is_plugin_installed($product = null, $also_require_active = false) {
40
  if ($also_require_active) return class_exists($product);
41
  if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
42
  $plugins = get_plugins();
includes/wp-optimize-database-information.php CHANGED
@@ -392,4 +392,159 @@ class WP_Optimize_Database_Information {
392
  return false;
393
  }
394
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  }
392
  return false;
393
  }
394
  }
395
+
396
+ /**
397
+ * Check if $table using by any of installed plugins.
398
+ *
399
+ * @param string $table
400
+ * @return bool
401
+ */
402
+ public function is_table_using_by_plugin($table) {
403
+ $plugin_name = $this->get_table_plugin($table);
404
+
405
+ // if we can't determine which plugin use $table then return true.
406
+ if (false == $plugin_name) {
407
+ return true;
408
+ }
409
+
410
+ // is WordPress core table or using by any of installed plugins then return true.
411
+ if (__('WordPress core', 'wp-optimize') == $plugin_name || in_array($plugin_name, $this->get_all_installed_plugins())) {
412
+ return true;
413
+ }
414
+
415
+ return false;
416
+ }
417
+
418
+ /**
419
+ * Get information about relations between tables and plugins. [ 'table' => 'plugin', ... ].
420
+ *
421
+ * @return array
422
+ */
423
+ private function get_all_plugin_tables_relationship() {
424
+ static $plugin_tables;
425
+
426
+ $wp_core_tables = array(
427
+ 'blogs',
428
+ 'blogversions',
429
+ 'commentmeta',
430
+ 'comments',
431
+ 'links',
432
+ 'options',
433
+ 'postmeta',
434
+ 'posts',
435
+ 'term_relationships',
436
+ 'term_taxonomy',
437
+ 'termmeta',
438
+ 'terms',
439
+ 'usermeta',
440
+ 'users',
441
+ 'site',
442
+ 'sitemeta',
443
+ );
444
+
445
+ if (is_array($plugin_tables)) return $plugin_tables;
446
+
447
+ $plugin_tables_json_file = WPO_PLUGIN_MAIN_PATH.'/plugin.json';
448
+ $plugin_tables = array();
449
+
450
+ if (is_file($plugin_tables_json_file) && is_readable($plugin_tables_json_file)) {
451
+ // get data from plugin.json file.
452
+ $plugin_tables = json_decode(file_get_contents($plugin_tables_json_file), true);
453
+ }
454
+
455
+ foreach ($wp_core_tables as $table) {
456
+ $plugin_tables[$table] = __('WordPress core', 'wp-optimize');
457
+ }
458
+
459
+ // add WP-Optimize tables.
460
+ $plugin_tables['tm_taskmeta'] = 'wp-optimize';
461
+ $plugin_tables['tm_tasks'] = 'wp-optimize';
462
+
463
+ return $plugin_tables;
464
+ }
465
+
466
+ /**
467
+ * Try to get plugin name by table name and return it or return false if plugin is not defined.
468
+ *
469
+ * @param string $table
470
+ * @return string|bool
471
+ */
472
+ public function get_table_plugin($table) {
473
+ global $wpdb;
474
+
475
+ // delete table prefix.
476
+ $table = preg_replace('/^'.$wpdb->prefix.'([0-9]+_)?/', '', $table);
477
+ $plugins_tables = $this->get_all_plugin_tables_relationship();
478
+
479
+ if (array_key_exists($table, $plugins_tables)) {
480
+ return $plugins_tables[$table];
481
+ }
482
+
483
+ return false;
484
+ }
485
+
486
+ /**
487
+ * Get all installed plugin slugs.
488
+ *
489
+ * @return array
490
+ */
491
+ public function get_all_installed_plugins() {
492
+ static $installed_plugins;
493
+
494
+ if (is_array($installed_plugins)) return $installed_plugins;
495
+
496
+ $installed_plugins = array();
497
+ $plugins = get_plugins();
498
+
499
+ foreach ($plugins as $plugin_file => $plugin_data) {
500
+ if ('' != $plugin_data['TextDomain']) {
501
+ $installed_plugins[] = $plugin_data['TextDomain'];
502
+ } else {
503
+ $plugin_file_parts = explode('/', $plugin_file);
504
+ $installed_plugins[]= $plugin_file_parts[0];
505
+ }
506
+ }
507
+
508
+ return $installed_plugins;
509
+ }
510
+
511
+ /**
512
+ * Check current plugin status installed/not installed and active/inactive.
513
+ *
514
+ * @param string $plugin
515
+ * @return array - ['installed' => true|false, 'active' => true|false]
516
+ */
517
+ public function get_plugin_status($plugin) {
518
+ $plugins = get_plugins();
519
+
520
+ // return true for wp-optimize without checking.
521
+ if ('wp-optimize' == $plugin) {
522
+ return array(
523
+ 'installed' => true,
524
+ 'active' => true,
525
+ );
526
+ }
527
+
528
+ $installed = false;
529
+ $active = false;
530
+
531
+ foreach ($plugins as $plugin_file => $plugin_data) {
532
+ if ('' != $plugin_data['TextDomain']) {
533
+ $plugin_slug = $plugin_data['TextDomain'];
534
+ } else {
535
+ $plugin_file_parts = explode('/', $plugin_file);
536
+ $plugin_slug = $plugin_file_parts[0];
537
+ }
538
+
539
+ if ($plugin == $plugin_slug) {
540
+ $installed = true;
541
+ $active = is_plugin_active($plugin_file);
542
+ }
543
+ }
544
+
545
+ return array(
546
+ 'installed' => $installed,
547
+ 'active' => $active,
548
+ );
549
+ }
550
  }
js/serialize-json/jquery.serializejson.js CHANGED
@@ -1,9 +1,9 @@
1
  /*!
2
  SerializeJSON jQuery plugin.
3
  https://github.com/marioizquierdo/jquery.serializeJSON
4
- version 2.8.1 (Dec, 2016)
5
 
6
- Copyright (c) 2012, 2017 Mario Izquierdo
7
  Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
8
  and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
9
  */
@@ -137,8 +137,12 @@
137
  parsedVal = (valStr === "true");
138
  } else if (opts.parseNulls && valStr == "null") { // auto: null
139
  parsedVal = null;
 
 
140
  }
141
- if (opts.parseWithFunction && !type) { // custom parse function (apply after previous parsing options, but not if there's a specific type)
 
 
142
  parsedVal = opts.parseWithFunction(parsedVal, inputName);
143
  }
144
 
1
  /*!
2
  SerializeJSON jQuery plugin.
3
  https://github.com/marioizquierdo/jquery.serializeJSON
4
+ version 2.9.0 (Jan, 2018)
5
 
6
+ Copyright (c) 2012-2018 Mario Izquierdo
7
  Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
8
  and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
9
  */
137
  parsedVal = (valStr === "true");
138
  } else if (opts.parseNulls && valStr == "null") { // auto: null
139
  parsedVal = null;
140
+ } else if (opts.typeFunctions && opts.typeFunctions["string"]) { // make sure to apply :string type if it was re-defined
141
+ parsedVal = opts.typeFunctions["string"](valStr);
142
  }
143
+
144
+ // Custom parse function: apply after parsing options, unless there's an explicit type.
145
+ if (opts.parseWithFunction && !type) {
146
  parsedVal = opts.parseWithFunction(parsedVal, inputName);
147
  }
148
 
js/serialize-json/jquery.serializejson.min.js CHANGED
@@ -1,10 +1,10 @@
1
  /*!
2
  SerializeJSON jQuery plugin.
3
  https://github.com/marioizquierdo/jquery.serializeJSON
4
- version 2.8.1 (Dec, 2016)
5
 
6
- Copyright (c) 2012, 2017 Mario Izquierdo
7
  Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
8
  and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
9
  */
10
- !function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"==typeof exports){var b=require("jquery");module.exports=a(b)}else a(window.jQuery||window.Zepto||window.$)}(function(a){"use strict";a.fn.serializeJSON=function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o;return c=a.serializeJSON,d=this,e=c.setupOpts(b),f=d.serializeArray(),c.readCheckboxUncheckedValues(f,e,d),g={},a.each(f,function(a,b){h=b.name,i=b.value,k=c.extractTypeAndNameWithNoType(h),l=k.nameWithNoType,m=k.type,m||(m=c.attrFromInputWithName(d,h,"data-value-type")),c.validateType(h,m,e),"skip"!==m&&(n=c.splitInputNameIntoKeysArray(l),j=c.parseValue(i,h,m,e),o=!j&&c.shouldSkipFalsy(d,h,l,m,e),o||c.deepSet(g,n,j,e))}),g},a.serializeJSON={defaultOptions:{checkboxUncheckedValue:void 0,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,skipFalsyValuesForTypes:[],skipFalsyValuesForFields:[],customTypes:{},defaultTypes:{string:function(a){return String(a)},number:function(a){return Number(a)},boolean:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1},null:function(a){var b=["false","null","undefined","","0"];return b.indexOf(a)===-1?a:null},array:function(a){return JSON.parse(a)},object:function(a){return JSON.parse(a)},auto:function(b){return a.serializeJSON.parseValue(b,null,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})},skip:null},useIntKeysAsArrayIndex:!1},setupOpts:function(b){var c,d,e,f,g,h;h=a.serializeJSON,null==b&&(b={}),e=h.defaultOptions||{},d=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","skipFalsyValuesForTypes","skipFalsyValuesForFields","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(c in b)if(d.indexOf(c)===-1)throw new Error("serializeJSON ERROR: invalid option '"+c+"'. Please use one of "+d.join(", "));return f=function(a){return b[a]!==!1&&""!==b[a]&&(b[a]||e[a])},g=f("parseAll"),{checkboxUncheckedValue:f("checkboxUncheckedValue"),parseNumbers:g||f("parseNumbers"),parseBooleans:g||f("parseBooleans"),parseNulls:g||f("parseNulls"),parseWithFunction:f("parseWithFunction"),skipFalsyValuesForTypes:f("skipFalsyValuesForTypes"),skipFalsyValuesForFields:f("skipFalsyValuesForFields"),typeFunctions:a.extend({},f("defaultTypes"),f("customTypes")),useIntKeysAsArrayIndex:f("useIntKeysAsArrayIndex")}},parseValue:function(b,c,d,e){var f,g;return f=a.serializeJSON,g=b,e.typeFunctions&&d&&e.typeFunctions[d]?g=e.typeFunctions[d](b):e.parseNumbers&&f.isNumeric(b)?g=Number(b):!e.parseBooleans||"true"!==b&&"false"!==b?e.parseNulls&&"null"==b&&(g=null):g="true"===b,e.parseWithFunction&&!d&&(g=e.parseWithFunction(g,c)),g},isObject:function(a){return a===Object(a)},isUndefined:function(a){return void 0===a},isValidArrayIndex:function(a){return/^[0-9]+$/.test(String(a))},isNumeric:function(a){return a-parseFloat(a)>=0},optionKeys:function(a){if(Object.keys)return Object.keys(a);var b,c=[];for(b in a)c.push(b);return c},readCheckboxUncheckedValues:function(b,c,d){var e,f,g,h,i;null==c&&(c={}),i=a.serializeJSON,e="input[type=checkbox][name]:not(:checked):not([disabled])",f=d.find(e).add(d.filter(e)),f.each(function(d,e){if(g=a(e),h=g.attr("data-unchecked-value"),null==h&&(h=c.checkboxUncheckedValue),null!=h){if(e.name&&e.name.indexOf("[][")!==-1)throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+e.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");b.push({name:e.name,value:h})}})},extractTypeAndNameWithNoType:function(a){var b;return(b=a.match(/(.*):([^:]+)$/))?{nameWithNoType:b[1],type:b[2]}:{nameWithNoType:a,type:null}},shouldSkipFalsy:function(b,c,d,e,f){var g=a.serializeJSON,h=g.attrFromInputWithName(b,c,"data-skip-falsy");if(null!=h)return"false"!==h;var i=f.skipFalsyValuesForFields;if(i&&(i.indexOf(d)!==-1||i.indexOf(c)!==-1))return!0;var j=f.skipFalsyValuesForTypes;return null==e&&(e="string"),!(!j||j.indexOf(e)===-1)},attrFromInputWithName:function(a,b,c){var d,e,f;return d=b.replace(/(:|\.|\[|\]|\s)/g,"\\$1"),e='[name="'+d+'"]',f=a.find(e).add(a.filter(e)),f.attr(c)},validateType:function(b,c,d){var e,f;if(f=a.serializeJSON,e=f.optionKeys(d?d.typeFunctions:f.defaultOptions.defaultTypes),c&&e.indexOf(c)===-1)throw new Error("serializeJSON ERROR: Invalid type "+c+" found in input name '"+b+"', please use one of "+e.join(", "));return!0},splitInputNameIntoKeysArray:function(b){var c,d;return d=a.serializeJSON,c=b.split("["),c=a.map(c,function(a){return a.replace(/\]/g,"")}),""===c[0]&&c.shift(),c},deepSet:function(b,c,d,e){var f,g,h,i,j,k;if(null==e&&(e={}),k=a.serializeJSON,k.isUndefined(b))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!c||0===c.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");f=c[0],1===c.length?""===f?b.push(d):b[f]=d:(g=c[1],""===f&&(i=b.length-1,j=b[i],f=k.isObject(j)&&(k.isUndefined(j[g])||c.length>2)?i:i+1),""===g?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):e.useIntKeysAsArrayIndex&&k.isValidArrayIndex(g)?!k.isUndefined(b[f])&&a.isArray(b[f])||(b[f]=[]):!k.isUndefined(b[f])&&k.isObject(b[f])||(b[f]={}),h=c.slice(1),k.deepSet(b[f],h,d,e))}}});
1
  /*!
2
  SerializeJSON jQuery plugin.
3
  https://github.com/marioizquierdo/jquery.serializeJSON
4
+ version 2.9.0 (Jan, 2018)
5
 
6
+ Copyright (c) 2012-2018 Mario Izquierdo
7
  Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
8
  and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
9
  */
10
+ !function(e){if("function"==typeof define&&define.amd)define(["jquery"],e);else if("object"==typeof exports){var n=require("jquery");module.exports=e(n)}else e(window.jQuery||window.Zepto||window.$)}(function(e){"use strict";e.fn.serializeJSON=function(n){var r,s,t,i,a,u,l,o,p,c,d,f,y;return r=e.serializeJSON,s=this,t=r.setupOpts(n),i=s.serializeArray(),r.readCheckboxUncheckedValues(i,t,s),a={},e.each(i,function(e,n){u=n.name,l=n.value,p=r.extractTypeAndNameWithNoType(u),c=p.nameWithNoType,(d=p.type)||(d=r.attrFromInputWithName(s,u,"data-value-type")),r.validateType(u,d,t),"skip"!==d&&(f=r.splitInputNameIntoKeysArray(c),o=r.parseValue(l,u,d,t),(y=!o&&r.shouldSkipFalsy(s,u,c,d,t))||r.deepSet(a,f,o,t))}),a},e.serializeJSON={defaultOptions:{checkboxUncheckedValue:void 0,parseNumbers:!1,parseBooleans:!1,parseNulls:!1,parseAll:!1,parseWithFunction:null,skipFalsyValuesForTypes:[],skipFalsyValuesForFields:[],customTypes:{},defaultTypes:{string:function(e){return String(e)},number:function(e){return Number(e)},boolean:function(e){return-1===["false","null","undefined","","0"].indexOf(e)},null:function(e){return-1===["false","null","undefined","","0"].indexOf(e)?e:null},array:function(e){return JSON.parse(e)},object:function(e){return JSON.parse(e)},auto:function(n){return e.serializeJSON.parseValue(n,null,null,{parseNumbers:!0,parseBooleans:!0,parseNulls:!0})},skip:null},useIntKeysAsArrayIndex:!1},setupOpts:function(n){var r,s,t,i,a,u;u=e.serializeJSON,null==n&&(n={}),t=u.defaultOptions||{},s=["checkboxUncheckedValue","parseNumbers","parseBooleans","parseNulls","parseAll","parseWithFunction","skipFalsyValuesForTypes","skipFalsyValuesForFields","customTypes","defaultTypes","useIntKeysAsArrayIndex"];for(r in n)if(-1===s.indexOf(r))throw new Error("serializeJSON ERROR: invalid option '"+r+"'. Please use one of "+s.join(", "));return i=function(e){return!1!==n[e]&&""!==n[e]&&(n[e]||t[e])},a=i("parseAll"),{checkboxUncheckedValue:i("checkboxUncheckedValue"),parseNumbers:a||i("parseNumbers"),parseBooleans:a||i("parseBooleans"),parseNulls:a||i("parseNulls"),parseWithFunction:i("parseWithFunction"),skipFalsyValuesForTypes:i("skipFalsyValuesForTypes"),skipFalsyValuesForFields:i("skipFalsyValuesForFields"),typeFunctions:e.extend({},i("defaultTypes"),i("customTypes")),useIntKeysAsArrayIndex:i("useIntKeysAsArrayIndex")}},parseValue:function(n,r,s,t){var i,a;return i=e.serializeJSON,a=n,t.typeFunctions&&s&&t.typeFunctions[s]?a=t.typeFunctions[s](n):t.parseNumbers&&i.isNumeric(n)?a=Number(n):!t.parseBooleans||"true"!==n&&"false"!==n?t.parseNulls&&"null"==n?a=null:t.typeFunctions&&t.typeFunctions.string&&(a=t.typeFunctions.string(n)):a="true"===n,t.parseWithFunction&&!s&&(a=t.parseWithFunction(a,r)),a},isObject:function(e){return e===Object(e)},isUndefined:function(e){return void 0===e},isValidArrayIndex:function(e){return/^[0-9]+$/.test(String(e))},isNumeric:function(e){return e-parseFloat(e)>=0},optionKeys:function(e){if(Object.keys)return Object.keys(e);var n,r=[];for(n in e)r.push(n);return r},readCheckboxUncheckedValues:function(n,r,s){var t,i,a;null==r&&(r={}),e.serializeJSON,t="input[type=checkbox][name]:not(:checked):not([disabled])",s.find(t).add(s.filter(t)).each(function(s,t){if(i=e(t),null==(a=i.attr("data-unchecked-value"))&&(a=r.checkboxUncheckedValue),null!=a){if(t.name&&-1!==t.name.indexOf("[]["))throw new Error("serializeJSON ERROR: checkbox unchecked values are not supported on nested arrays of objects like '"+t.name+"'. See https://github.com/marioizquierdo/jquery.serializeJSON/issues/67");n.push({name:t.name,value:a})}})},extractTypeAndNameWithNoType:function(e){var n;return(n=e.match(/(.*):([^:]+)$/))?{nameWithNoType:n[1],type:n[2]}:{nameWithNoType:e,type:null}},shouldSkipFalsy:function(n,r,s,t,i){var a=e.serializeJSON.attrFromInputWithName(n,r,"data-skip-falsy");if(null!=a)return"false"!==a;var u=i.skipFalsyValuesForFields;if(u&&(-1!==u.indexOf(s)||-1!==u.indexOf(r)))return!0;var l=i.skipFalsyValuesForTypes;return null==t&&(t="string"),!(!l||-1===l.indexOf(t))},attrFromInputWithName:function(e,n,r){var s,t;return s=n.replace(/(:|\.|\[|\]|\s)/g,"\\$1"),t='[name="'+s+'"]',e.find(t).add(e.filter(t)).attr(r)},validateType:function(n,r,s){var t,i;if(i=e.serializeJSON,t=i.optionKeys(s?s.typeFunctions:i.defaultOptions.defaultTypes),r&&-1===t.indexOf(r))throw new Error("serializeJSON ERROR: Invalid type "+r+" found in input name '"+n+"', please use one of "+t.join(", "));return!0},splitInputNameIntoKeysArray:function(n){var r;return e.serializeJSON,r=n.split("["),""===(r=e.map(r,function(e){return e.replace(/\]/g,"")}))[0]&&r.shift(),r},deepSet:function(n,r,s,t){var i,a,u,l,o,p;if(null==t&&(t={}),(p=e.serializeJSON).isUndefined(n))throw new Error("ArgumentError: param 'o' expected to be an object or array, found undefined");if(!r||0===r.length)throw new Error("ArgumentError: param 'keys' expected to be an array with least one element");i=r[0],1===r.length?""===i?n.push(s):n[i]=s:(a=r[1],""===i&&(o=n[l=n.length-1],i=p.isObject(o)&&(p.isUndefined(o[a])||r.length>2)?l:l+1),""===a?!p.isUndefined(n[i])&&e.isArray(n[i])||(n[i]=[]):t.useIntKeysAsArrayIndex&&p.isValidArrayIndex(a)?!p.isUndefined(n[i])&&e.isArray(n[i])||(n[i]=[]):!p.isUndefined(n[i])&&p.isObject(n[i])||(n[i]={}),u=r.slice(1),p.deepSet(n[i],u,s,t))}}});
js/tablesorter/jquery.tablesorter.js CHANGED
@@ -1,2914 +1,2916 @@
1
- (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery){
2
- /*! TableSorter (FORK) v2.31.0 *//*
3
- * Client-side table sorting with ease!
4
- * @requires jQuery v1.2.6+
5
- *
6
- * Copyright (c) 2007 Christian Bach
7
- * fork maintained by Rob Garrison
8
- *
9
- * Examples and original docs at: http://tablesorter.com
10
- * Dual licensed under the MIT and GPL licenses:
11
- * http://www.opensource.org/licenses/mit-license.php
12
- * http://www.gnu.org/licenses/gpl.html
13
- *
14
- * @type jQuery
15
- * @name tablesorter (FORK)
16
- * @cat Plugins/Tablesorter
17
- * @author Christian Bach - christian.bach@polyester.se
18
- * @contributor Rob Garrison - https://github.com/Mottie/tablesorter
19
- * @docs (fork) - https://mottie.github.io/tablesorter/docs/
20
- */
21
- /*jshint browser:true, jquery:true, unused:false, expr: true */
22
- ;( function( $ ) {
23
- 'use strict';
24
- var ts = $.tablesorter = {
25
-
26
- version : '2.31.0',
27
-
28
- parsers : [],
29
- widgets : [],
30
- defaults : {
31
-
32
- // *** appearance
33
- theme : 'default', // adds tablesorter-{theme} to the table for styling
34
- widthFixed : false, // adds colgroup to fix widths of columns
35
- showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered.
36
-
37
- headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcon
38
- onRenderTemplate : null, // function( index, template ) { return template; }, // template is a string
39
- onRenderHeader : null, // function( index ) {}, // nothing to return
40
-
41
- // *** functionality
42
- cancelSelection : true, // prevent text selection in the header
43
- tabIndex : true, // add tabindex to header for keyboard accessibility
44
- dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd'
45
- sortMultiSortKey : 'shiftKey', // key used to select additional columns
46
- sortResetKey : 'ctrlKey', // key used to remove sorting on a column
47
- usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89'
48
- delayInit : false, // if false, the parsed table contents will not update until the first sort
49
- serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
50
- resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
51
-
52
- // *** sort options
53
- headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
54
- ignoreCase : true, // ignore case while sorting
55
- sortForce : null, // column(s) first sorted; always applied
56
- sortList : [], // Initial sort order; applied initially; updated when manually sorted
57
- sortAppend : null, // column(s) sorted last; always applied
58
- sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained
59
-
60
- sortInitialOrder : 'asc', // sort direction on first click
61
- sortLocaleCompare: false, // replace equivalent character (accented characters)
62
- sortReset : false, // third click on the header will reset column to default - unsorted
63
- sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
64
-
65
- emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
66
- stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero
67
- duplicateSpan : true, // colspan cells in the tbody will have duplicated content in the cache for each spanned column
68
- textExtraction : 'basic', // text extraction method/function - function( node, table, cellIndex ) {}
69
- textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function)
70
- textSorter : null, // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
71
- numberSorter : null, // choose overall numeric sorter function( a, b, direction, maxColumnValue )
72
-
73
- // *** widget options
74
- initWidgets : true, // apply widgets on tablesorter initialization
75
- widgetClass : 'widget-{name}', // table class name template to match to include a widget
76
- widgets : [], // method to add widgets, e.g. widgets: ['zebra']
77
- widgetOptions : {
78
- zebra : [ 'even', 'odd' ] // zebra widget alternating row class names
79
- },
80
-
81
- // *** callbacks
82
- initialized : null, // function( table ) {},
83
-
84
- // *** extra css class names
85
- tableClass : '',
86
- cssAsc : '',
87
- cssDesc : '',
88
- cssNone : '',
89
- cssHeader : '',
90
- cssHeaderRow : '',
91
- cssProcessing : '', // processing icon applied to header during sort/filter
92
-
93
- cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to its parent
94
- cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!)
95
- cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort
96
- cssIgnoreRow : 'tablesorter-ignoreRow',// header row to ignore; cells within this row will not be added to c.$headers
97
-
98
- cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate
99
- cssIconNone : '', // class name added to the icon when there is no column sort
100
- cssIconAsc : '', // class name added to the icon when the column has an ascending sort
101
- cssIconDesc : '', // class name added to the icon when the column has a descending sort
102
- cssIconDisabled : '', // class name added to the icon when the column has a disabled sort
103
-
104
- // *** events
105
- pointerClick : 'click',
106
- pointerDown : 'mousedown',
107
- pointerUp : 'mouseup',
108
-
109
- // *** selectors
110
- selectorHeaders : '> thead th, > thead td',
111
- selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
112
- selectorRemove : '.remove-me',
113
-
114
- // *** advanced
115
- debug : false,
116
-
117
- // *** Internal variables
118
- headerList: [],
119
- empties: {},
120
- strings: {},
121
- parsers: [],
122
-
123
- // *** parser options for validator; values must be falsy!
124
- globalize: 0,
125
- imgAttr: 0
126
-
127
- // removed: widgetZebra: { css: ['even', 'odd'] }
128
-
129
- },
130
-
131
- // internal css classes - these will ALWAYS be added to
132
- // the table and MUST only contain one class name - fixes #381
133
- css : {
134
- table : 'tablesorter',
135
- cssHasChild: 'tablesorter-hasChildRow',
136
- childRow : 'tablesorter-childRow',
137
- colgroup : 'tablesorter-colgroup',
138
- header : 'tablesorter-header',
139
- headerRow : 'tablesorter-headerRow',
140
- headerIn : 'tablesorter-header-inner',
141
- icon : 'tablesorter-icon',
142
- processing : 'tablesorter-processing',
143
- sortAsc : 'tablesorter-headerAsc',
144
- sortDesc : 'tablesorter-headerDesc',
145
- sortNone : 'tablesorter-headerUnSorted'
146
- },
147
-
148
- // labels applied to sortable headers for accessibility (aria) support
149
- language : {
150
- sortAsc : 'Ascending sort applied, ',
151
- sortDesc : 'Descending sort applied, ',
152
- sortNone : 'No sort applied, ',
153
- sortDisabled : 'sorting is disabled',
154
- nextAsc : 'activate to apply an ascending sort',
155
- nextDesc : 'activate to apply a descending sort',
156
- nextNone : 'activate to remove the sort'
157
- },
158
-
159
- regex : {
160
- templateContent : /\{content\}/g,
161
- templateIcon : /\{icon\}/g,
162
- templateName : /\{name\}/i,
163
- spaces : /\s+/g,
164
- nonWord : /\W/g,
165
- formElements : /(input|select|button|textarea)/i,
166
-
167
- // *** sort functions ***
168
- // regex used in natural sort
169
- // chunk/tokenize numbers & letters
170
- chunk : /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
171
- // replace chunks @ ends
172
- chunks : /(^\\0|\\0$)/,
173
- hex : /^0x[0-9a-f]+$/i,
174
-
175
- // *** formatFloat ***
176
- comma : /,/g,
177
- digitNonUS : /[\s|\.]/g,
178
- digitNegativeTest : /^\s*\([.\d]+\)/,
179
- digitNegativeReplace : /^\s*\(([.\d]+)\)/,
180
-
181
- // *** isDigit ***
182
- digitTest : /^[\-+(]?\d+[)]?$/,
183
- digitReplace : /[,.'"\s]/g
184
-
185
- },
186
-
187
- // digit sort, text location
188
- string : {
189
- max : 1,
190
- min : -1,
191
- emptymin : 1,
192
- emptymax : -1,
193
- zero : 0,
194
- none : 0,
195
- 'null' : 0,
196
- top : true,
197
- bottom : false
198
- },
199
-
200
- keyCodes : {
201
- enter : 13
202
- },
203
-
204
- // placeholder date parser data (globalize)
205
- dates : {},
206
-
207
- // These methods can be applied on table.config instance
208
- instanceMethods : {},
209
-
210
- /*
211
- ▄█████ ██████ ██████ ██ ██ █████▄
212
- ▀█▄ ██▄▄ ██ ██ ██ ██▄▄██
213
- ▀█▄ ██▀▀ ██ ██ ██ ██▀▀▀
214
- █████▀ ██████ ██ ▀████▀ ██
215
- */
216
-
217
- setup : function( table, c ) {
218
- // if no thead or tbody, or tablesorter is already present, quit
219
- if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
220
- if ( ts.debug(c, 'core') ) {
221
- if ( table.hasInitialized ) {
222
- console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
223
- } else {
224
- console.error( 'Stopping initialization! No table, thead or tbody', table );
225
- }
226
- }
227
- return;
228
- }
229
-
230
- var tmp = '',
231
- $table = $( table ),
232
- meta = $.metadata;
233
- // initialization flag
234
- table.hasInitialized = false;
235
- // table is being processed flag
236
- table.isProcessing = true;
237
- // make sure to store the config object
238
- table.config = c;
239
- // save the settings where they read
240
- $.data( table, 'tablesorter', c );
241
- if ( ts.debug(c, 'core') ) {
242
- console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter v' + ts.version );
243
- $.data( table, 'startoveralltimer', new Date() );
244
- }
245
-
246
- // removing this in version 3 (only supports jQuery 1.7+)
247
- c.supportsDataObject = ( function( version ) {
248
- version[ 0 ] = parseInt( version[ 0 ], 10 );
249
- return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
250
- })( $.fn.jquery.split( '.' ) );
251
- // ensure case insensitivity
252
- c.emptyTo = c.emptyTo.toLowerCase();
253
- c.stringTo = c.stringTo.toLowerCase();
254
- c.last = { sortList : [], clickedIndex : -1 };
255
- // add table theme class only if there isn't already one there
256
- if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
257
- tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
258
- }
259
-
260
- // give the table a unique id, which will be used in namespace binding
261
- if ( !c.namespace ) {
262
- c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
263
- } else {
264
- // make sure namespace starts with a period & doesn't have weird characters
265
- c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
266
- }
267
-
268
- c.table = table;
269
- c.$table = $table
270
- // add namespace to table to allow bindings on extra elements to target
271
- // the parent table (e.g. parser-input-select)
272
- .addClass( ts.css.table + ' ' + c.tableClass + tmp + ' ' + c.namespace.slice(1) )
273
- .attr( 'role', 'grid' );
274
- c.$headers = $table.find( c.selectorHeaders );
275
-
276
- c.$table.children().children( 'tr' ).attr( 'role', 'row' );
277
- c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
278
- 'aria-live' : 'polite',
279
- 'aria-relevant' : 'all'
280
- });
281
- if ( c.$table.children( 'caption' ).length ) {
282
- tmp = c.$table.children( 'caption' )[ 0 ];
283
- if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
284
- c.$table.attr( 'aria-labelledby', tmp.id );
285
- }
286
- c.widgetInit = {}; // keep a list of initialized widgets
287
- // change textExtraction via data-attribute
288
- c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
289
- // build headers
290
- ts.buildHeaders( c );
291
- // fixate columns if the users supplies the fixedWidth option
292
- // do this after theme has been applied
293
- ts.fixColumnWidth( table );
294
- // add widgets from class name
295
- ts.addWidgetFromClass( table );
296
- // add widget options before parsing (e.g. grouping widget has parser settings)
297
- ts.applyWidgetOptions( table );
298
- // try to auto detect column type, and store in tables config
299
- ts.setupParsers( c );
300
- // start total row count at zero
301
- c.totalRows = 0;
302
- // only validate options while debugging. See #1528
303
- if (c.debug) {
304
- ts.validateOptions( c );
305
- }
306
- // build the cache for the tbody cells
307
- // delayInit will delay building the cache until the user starts a sort
308
- if ( !c.delayInit ) { ts.buildCache( c ); }
309
- // bind all header events and methods
310
- ts.bindEvents( table, c.$headers, true );
311
- ts.bindMethods( c );
312
- // get sort list from jQuery data or metadata
313
- // in jQuery < 1.4, an error occurs when calling $table.data()
314
- if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
315
- c.sortList = $table.data().sortlist;
316
- } else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
317
- c.sortList = $table.metadata().sortlist;
318
- }
319
- // apply widget init code
320
- ts.applyWidget( table, true );
321
- // if user has supplied a sort list to constructor
322
- if ( c.sortList.length > 0 ) {
323
- ts.sortOn( c, c.sortList, {}, !c.initWidgets );
324
- } else {
325
- ts.setHeadersCss( c );
326
- if ( c.initWidgets ) {
327
- // apply widget format
328
- ts.applyWidget( table, false );
329
- }
330
- }
331
-
332
- // show processesing icon
333
- if ( c.showProcessing ) {
334
- $table
335
- .unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
336
- .bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
337
- clearTimeout( c.timerProcessing );
338
- ts.isProcessing( table );
339
- if ( e.type === 'sortBegin' ) {
340
- c.timerProcessing = setTimeout( function() {
341
- ts.isProcessing( table, true );
342
- }, 500 );
343
- }
344
- });
345
- }
346
-
347
- // initialized
348
- table.hasInitialized = true;
349
- table.isProcessing = false;
350
- if ( ts.debug(c, 'core') ) {
351
- console.log( 'Overall initialization time:' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
352
- if ( ts.debug(c, 'core') && console.groupEnd ) { console.groupEnd(); }
353
- }
354
- $table.triggerHandler( 'tablesorter-initialized', table );
355
- if ( typeof c.initialized === 'function' ) {
356
- c.initialized( table );
357
- }
358
- },
359
-
360
- bindMethods : function( c ) {
361
- var $table = c.$table,
362
- namespace = c.namespace,
363
- events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
364
- 'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
365
- 'mouseleave ' ).split( ' ' )
366
- .join( namespace + ' ' );
367
- // apply easy methods that trigger bound events
368
- $table
369
- .unbind( events.replace( ts.regex.spaces, ' ' ) )
370
- .bind( 'sortReset' + namespace, function( e, callback ) {
371
- e.stopPropagation();
372
- // using this.config to ensure functions are getting a non-cached version of the config
373
- ts.sortReset( this.config, function( table ) {
374
- if (table.isApplyingWidgets) {
375
- // multiple triggers in a row... filterReset, then sortReset - see #1361
376
- // wait to update widgets
377
- setTimeout( function() {
378
- ts.applyWidget( table, '', callback );
379
- }, 100 );
380
- } else {
381
- ts.applyWidget( table, '', callback );
382
- }
383
- });
384
- })
385
- .bind( 'updateAll' + namespace, function( e, resort, callback ) {
386
- e.stopPropagation();
387
- ts.updateAll( this.config, resort, callback );
388
- })
389
- .bind( 'update' + namespace + ' updateRows' + namespace, function( e, resort, callback ) {
390
- e.stopPropagation();
391
- ts.update( this.config, resort, callback );
392
- })
393
- .bind( 'updateHeaders' + namespace, function( e, callback ) {
394
- e.stopPropagation();
395
- ts.updateHeaders( this.config, callback );
396
- })
397
- .bind( 'updateCell' + namespace, function( e, cell, resort, callback ) {
398
- e.stopPropagation();
399
- ts.updateCell( this.config, cell, resort, callback );
400
- })
401
- .bind( 'addRows' + namespace, function( e, $row, resort, callback ) {
402
- e.stopPropagation();
403
- ts.addRows( this.config, $row, resort, callback );
404
- })
405
- .bind( 'updateComplete' + namespace, function() {
406
- this.isUpdating = false;
407
- })
408
- .bind( 'sorton' + namespace, function( e, list, callback, init ) {
409
- e.stopPropagation();
410
- ts.sortOn( this.config, list, callback, init );
411
- })
412
- .bind( 'appendCache' + namespace, function( e, callback, init ) {
413
- e.stopPropagation();
414
- ts.appendCache( this.config, init );
415
- if ( $.isFunction( callback ) ) {
416
- callback( this );
417
- }
418
- })
419
- // $tbodies variable is used by the tbody sorting widget
420
- .bind( 'updateCache' + namespace, function( e, callback, $tbodies ) {
421
- e.stopPropagation();
422
- ts.updateCache( this.config, callback, $tbodies );
423
- })
424
- .bind( 'applyWidgetId' + namespace, function( e, id ) {
425
- e.stopPropagation();
426
- ts.applyWidgetId( this, id );
427
- })
428
- .bind( 'applyWidgets' + namespace, function( e, callback ) {
429
- e.stopPropagation();
430
- // apply widgets (false = not initializing)
431
- ts.applyWidget( this, false, callback );
432
- })
433
- .bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
434
- e.stopPropagation();
435
- ts.refreshWidgets( this, all, dontapply );
436
- })
437
- .bind( 'removeWidget' + namespace, function( e, name, refreshing ) {
438
- e.stopPropagation();
439
- ts.removeWidget( this, name, refreshing );
440
- })
441
- .bind( 'destroy' + namespace, function( e, removeClasses, callback ) {
442
- e.stopPropagation();
443
- ts.destroy( this, removeClasses, callback );
444
- })
445
- .bind( 'resetToLoadState' + namespace, function( e ) {
446
- e.stopPropagation();
447
- // remove all widgets
448
- ts.removeWidget( this, true, false );
449
- var tmp = $.extend( true, {}, c.originalSettings );
450
- // restore original settings; this clears out current settings, but does not clear
451
- // values saved to storage.
452
- c = $.extend( true, {}, ts.defaults, tmp );
453
- c.originalSettings = tmp;
454
- this.hasInitialized = false;
455
- // setup the entire table again
456
- ts.setup( this, c );
457
- });
458
- },
459
-
460
- bindEvents : function( table, $headers, core ) {
461
- table = $( table )[ 0 ];
462
- var tmp,
463
- c = table.config,
464
- namespace = c.namespace,
465
- downTarget = null;
466
- if ( core !== true ) {
467
- $headers.addClass( namespace.slice( 1 ) + '_extra_headers' );
468
- tmp = ts.getClosest( $headers, 'table' );
469
- if ( tmp.length && tmp[ 0 ].nodeName === 'TABLE' && tmp[ 0 ] !== table ) {
470
- $( tmp[ 0 ] ).addClass( namespace.slice( 1 ) + '_extra_table' );
471
- }
472
- }
473
- tmp = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
474
- .replace( ts.regex.spaces, ' ' )
475
- .split( ' ' )
476
- .join( namespace + ' ' );
477
- // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
478
- $headers
479
- // http://stackoverflow.com/questions/5312849/jquery-find-self;
480
- .find( c.selectorSort )
481
- .add( $headers.filter( c.selectorSort ) )
482
- .unbind( tmp )
483
- .bind( tmp, function( e, external ) {
484
- var $cell, cell, temp,
485
- $target = $( e.target ),
486
- // wrap event type in spaces, so the match doesn't trigger on inner words
487
- type = ' ' + e.type + ' ';
488
- // only recognize left clicks
489
- if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
490
- // allow pressing enter
491
- ( type === ' keyup ' && e.which !== ts.keyCodes.enter ) ||
492
- // allow triggering a click event (e.which is undefined) & ignore physical clicks
493
- ( type.match( ' ' + c.pointerClick + ' ' ) && typeof e.which !== 'undefined' ) ) {
494
- return;
495
- }
496
- // ignore mouseup if mousedown wasn't on the same target
497
- if ( type.match( ' ' + c.pointerUp + ' ' ) && downTarget !== e.target && external !== true ) {
498
- return;
499
- }
500
- // set target on mousedown
501
- if ( type.match( ' ' + c.pointerDown + ' ' ) ) {
502
- downTarget = e.target;
503
- // preventDefault needed or jQuery v1.3.2 and older throws an
504
- // "Uncaught TypeError: handler.apply is not a function" error
505
- temp = $target.jquery.split( '.' );
506
- if ( temp[ 0 ] === '1' && temp[ 1 ] < 4 ) { e.preventDefault(); }
507
- return;
508
- }
509
- downTarget = null;
510
- $cell = ts.getClosest( $( this ), '.' + ts.css.header );
511
- // prevent sort being triggered on form elements
512
- if ( ts.regex.formElements.test( e.target.nodeName ) ||
513
- // nosort class name, or elements within a nosort container
514
- $target.hasClass( c.cssNoSort ) || $target.parents( '.' + c.cssNoSort ).length > 0 ||
515
- // disabled cell directly clicked
516
- $cell.hasClass( 'sorter-false' ) ||
517
- // elements within a button
518
- $target.parents( 'button' ).length > 0 ) {
519
- return !c.cancelSelection;
520
- }
521
- if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
522
- ts.buildCache( c );
523
- }
524
- // use column index from data-attribute or index of current row; fixes #1116
525
- c.last.clickedIndex = $cell.attr( 'data-column' ) || $cell.index();
526
- cell = c.$headerIndexed[ c.last.clickedIndex ][0];
527
- if ( cell && !cell.sortDisabled ) {
528
- ts.initSort( c, cell, e );
529
- }
530
- });
531
- if ( c.cancelSelection ) {
532
- // cancel selection
533
- $headers
534
- .attr( 'unselectable', 'on' )
535
- .bind( 'selectstart', false )
536
- .css({
537
- 'user-select' : 'none',
538
- 'MozUserSelect' : 'none' // not needed for jQuery 1.8+
539
- });
540
- }
541
- },
542
-
543
- buildHeaders : function( c ) {
544
- var $temp, icon, timer, indx;
545
- c.headerList = [];
546
- c.headerContent = [];
547
- c.sortVars = [];
548
- if ( ts.debug(c, 'core') ) {
549
- timer = new Date();
550
- }
551
- // children tr in tfoot - see issue #196 & #547
552
- // don't pass table.config to computeColumnIndex here - widgets (math) pass it to "quickly" index tbody cells
553
- c.columns = ts.computeColumnIndex( c.$table.children( 'thead, tfoot' ).children( 'tr' ) );
554
- // add icon if cssIcon option exists
555
- icon = c.cssIcon ?
556
- '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' :
557
- '';
558
- // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
559
- c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {
560
- var configHeaders, header, column, template, tmp,
561
- $elem = $( elem );
562
- // ignore cell (don't add it to c.$headers) if row has ignoreRow class
563
- if ( ts.getClosest( $elem, 'tr' ).hasClass( c.cssIgnoreRow ) ) { return; }
564
- // transfer data-column to element if not th/td - #1459
565
- if ( !/(th|td)/i.test( elem.nodeName ) ) {
566
- tmp = ts.getClosest( $elem, 'th, td' );
567
- $elem.attr( 'data-column', tmp.attr( 'data-column' ) );
568
- }
569
- // make sure to get header cell & not column indexed cell
570
- configHeaders = ts.getColumnData( c.table, c.headers, index, true );
571
- // save original header content
572
- c.headerContent[ index ] = $elem.html();
573
- // if headerTemplate is empty, don't reformat the header cell
574
- if ( c.headerTemplate !== '' && !$elem.find( '.' + ts.css.headerIn ).length ) {
575
- // set up header template
576
- template = c.headerTemplate
577
- .replace( ts.regex.templateContent, $elem.html() )
578
- .replace( ts.regex.templateIcon, $elem.find( '.' + ts.css.icon ).length ? '' : icon );
579
- if ( c.onRenderTemplate ) {
580
- header = c.onRenderTemplate.apply( $elem, [ index, template ] );
581
- // only change t if something is returned
582
- if ( header && typeof header === 'string' ) {
583
- template = header;
584
- }
585
- }
586
- $elem.html( '<div class="' + ts.css.headerIn + '">' + template + '</div>' ); // faster than wrapInner
587
- }
588
- if ( c.onRenderHeader ) {
589
- c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );
590
- }
591
- column = parseInt( $elem.attr( 'data-column' ), 10 );
592
- elem.column = column;
593
- tmp = ts.getOrder( ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder );
594
- // this may get updated numerous times if there are multiple rows
595
- c.sortVars[ column ] = {
596
- count : -1, // set to -1 because clicking on the header automatically adds one
597
- order : tmp ?
598
- ( c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ] ) : // desc, asc, unsorted
599
- ( c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ] ), // asc, desc, unsorted
600
- lockedOrder : false,
601
- sortedBy : ''
602
- };
603
- tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
604
- if ( typeof tmp !== 'undefined' && tmp !== false ) {
605
- c.sortVars[ column ].lockedOrder = true;
606
- c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1 ] : [ 0, 0 ];
607
- }
608
- // add cell to headerList
609
- c.headerList[ index ] = elem;
610
- $elem.addClass( ts.css.header + ' ' + c.cssHeader );
611
- // add to parent in case there are multiple rows
612
- ts.getClosest( $elem, 'tr' )
613
- .addClass( ts.css.headerRow + ' ' + c.cssHeaderRow )
614
- .attr( 'role', 'row' );
615
- // allow keyboard cursor to focus on element
616
- if ( c.tabIndex ) {
617
- $elem.attr( 'tabindex', 0 );
618
- }
619
- return elem;
620
- }) );
621
- // cache headers per column
622
- c.$headerIndexed = [];
623
- for ( indx = 0; indx < c.columns; indx++ ) {
624
- // colspan in header making a column undefined
625
- if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {
626
- c.sortVars[ indx ] = {};
627
- }
628
- // Use c.$headers.parent() in case selectorHeaders doesn't point to the th/td
629
- $temp = c.$headers.filter( '[data-column="' + indx + '"]' );
630
- // target sortable column cells, unless there are none, then use non-sortable cells
631
- // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
632
- c.$headerIndexed[ indx ] = $temp.length ?
633
- $temp.not( '.sorter-false' ).length ?
634
- $temp.not( '.sorter-false' ).filter( ':last' ) :
635
- $temp.filter( ':last' ) :
636
- $();
637
- }
638
- c.$table.find( c.selectorHeaders ).attr({
639
- scope: 'col',
640
- role : 'columnheader'
641
- });
642
- // enable/disable sorting
643
- ts.updateHeader( c );
644
- if ( ts.debug(c, 'core') ) {
645
- console.log( 'Built headers:' + ts.benchmark( timer ) );
646
- console.log( c.$headers );
647
- }
648
- },
649
-
650
- // Use it to add a set of methods to table.config which will be available for all tables.
651
- // This should be done before table initialization
652
- addInstanceMethods : function( methods ) {
653
- $.extend( ts.instanceMethods, methods );
654
- },
655
-
656
- /*
657
- █████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄█████
658
- ██▄▄██ ██▄▄██ ██▄▄██ ▀█▄ ██▄▄ ██▄▄██ ▀█▄
659
- ██▀▀▀ ██▀▀██ ██▀██ ▀█▄ ██▀▀ ██▀██ ▀█▄
660
- ██ ██ ██ ██ ██ █████▀ ██████ ██ ██ █████▀
661
- */
662
- setupParsers : function( c, $tbodies ) {
663
- var rows, list, span, max, colIndex, indx, header, configHeaders,
664
- noParser, parser, extractor, time, tbody, len,
665
- table = c.table,
666
- tbodyIndex = 0,
667
- debug = ts.debug(c, 'core'),
668
- debugOutput = {};
669
- // update table bodies in case we start with an empty table
670
- c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
671
- tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
672
- len = tbody.length;
673
- if ( len === 0 ) {
674
- return debug ? console.warn( 'Warning: *Empty table!* Not building a parser cache' ) : '';
675
- } else if ( debug ) {
676
- time = new Date();
677
- console[ console.group ? 'group' : 'log' ]( 'Detecting parsers for each column' );
678
- }
679
- list = {
680
- extractors: [],
681
- parsers: []
682
- };
683
- while ( tbodyIndex < len ) {
684
- rows = tbody[ tbodyIndex ].rows;
685
- if ( rows.length ) {
686
- colIndex = 0;
687
- max = c.columns;
688
- for ( indx = 0; indx < max; indx++ ) {
689
- header = c.$headerIndexed[ colIndex ];
690
- if ( header && header.length ) {
691
- // get column indexed table cell; adding true parameter fixes #1362 but
692
- // it would break backwards compatibility...
693
- configHeaders = ts.getColumnData( table, c.headers, colIndex ); // , true );
694
- // get column parser/extractor
695
- extractor = ts.getParserById( ts.getData( header, configHeaders, 'extractor' ) );
696
- parser = ts.getParserById( ts.getData( header, configHeaders, 'sorter' ) );
697
- noParser = ts.getData( header, configHeaders, 'parser' ) === 'false';
698
- // empty cells behaviour - keeping emptyToBottom for backwards compatibility
699
- c.empties[colIndex] = (
700
- ts.getData( header, configHeaders, 'empty' ) ||
701
- c.emptyTo || ( c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
702
- // text strings behaviour in numerical sorts
703
- c.strings[colIndex] = (
704
- ts.getData( header, configHeaders, 'string' ) ||
705
- c.stringTo ||
706
- 'max' ).toLowerCase();
707
- if ( noParser ) {
708
- parser = ts.getParserById( 'no-parser' );
709
- }
710
- if ( !extractor ) {
711
- // For now, maybe detect someday
712
- extractor = false;
713
- }
714
- if ( !parser ) {
715
- parser = ts.detectParserForColumn( c, rows, -1, colIndex );
716
- }
717
- if ( debug ) {
718
- debugOutput[ '(' + colIndex + ') ' + header.text() ] = {
719
- parser : parser.id,
720
- extractor : extractor ? extractor.id : 'none',
721
- string : c.strings[ colIndex ],
722
- empty : c.empties[ colIndex ]
723
- };
724
- }
725
- list.parsers[ colIndex ] = parser;
726
- list.extractors[ colIndex ] = extractor;
727
- span = header[ 0 ].colSpan - 1;
728
- if ( span > 0 ) {
729
- colIndex += span;
730
- max += span;
731
- while ( span + 1 > 0 ) {
732
- // set colspan columns to use the same parsers & extractors
733
- list.parsers[ colIndex - span ] = parser;
734
- list.extractors[ colIndex - span ] = extractor;
735
- span--;
736
- }
737
- }
738
- }
739
- colIndex++;
740
- }
741
- }
742
- tbodyIndex += ( list.parsers.length ) ? len : 1;
743
- }
744
- if ( debug ) {
745
- if ( !ts.isEmptyObject( debugOutput ) ) {
746
- console[ console.table ? 'table' : 'log' ]( debugOutput );
747
- } else {
748
- console.warn( ' No parsers detected!' );
749
- }
750
- console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
751
- if ( console.groupEnd ) { console.groupEnd(); }
752
- }
753
- c.parsers = list.parsers;
754
- c.extractors = list.extractors;
755
- },
756
-
757
- addParser : function( parser ) {
758
- var indx,
759
- len = ts.parsers.length,
760
- add = true;
761
- for ( indx = 0; indx < len; indx++ ) {
762
- if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {
763
- add = false;
764
- }
765
- }
766
- if ( add ) {
767
- ts.parsers[ ts.parsers.length ] = parser;
768
- }
769
- },
770
-
771
- getParserById : function( name ) {
772
- /*jshint eqeqeq:false */ // eslint-disable-next-line eqeqeq
773
- if ( name == 'false' ) { return false; }
774
- var indx,
775
- len = ts.parsers.length;
776
- for ( indx = 0; indx < len; indx++ ) {
777
- if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {
778
- return ts.parsers[ indx ];
779
- }
780
- }
781
- return false;
782
- },
783
-
784
- detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {
785
- var cur, $node, row,
786
- indx = ts.parsers.length,
787
- node = false,
788
- nodeValue = '',
789
- debug = ts.debug(c, 'core'),
790
- keepLooking = true;
791
- while ( nodeValue === '' && keepLooking ) {
792
- rowIndex++;
793
- row = rows[ rowIndex ];
794
- // stop looking after 50 empty rows
795
- if ( row && rowIndex < 50 ) {
796
- if ( row.className.indexOf( ts.cssIgnoreRow ) < 0 ) {
797
- node = rows[ rowIndex ].cells[ cellIndex ];
798
- nodeValue = ts.getElementText( c, node, cellIndex );
799
- $node = $( node );
800
- if ( debug ) {
801
- console.log( 'Checking if value was empty on row ' + rowIndex + ', column: ' +
802
- cellIndex + ': "' + nodeValue + '"' );
803
- }
804
- }
805
- } else {
806
- keepLooking = false;
807
- }
808
- }
809
- while ( --indx >= 0 ) {
810
- cur = ts.parsers[ indx ];
811
- // ignore the default text parser because it will always be true
812
- if ( cur && cur.id !== 'text' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {
813
- return cur;
814
- }
815
- }
816
- // nothing found, return the generic parser (text)
817
- return ts.getParserById( 'text' );
818
- },
819
-
820
- getElementText : function( c, node, cellIndex ) {
821
- if ( !node ) { return ''; }
822
- var tmp,
823
- extract = c.textExtraction || '',
824
- // node could be a jquery object
825
- // http://jsperf.com/jquery-vs-instanceof-jquery/2
826
- $node = node.jquery ? node : $( node );
827
- if ( typeof extract === 'string' ) {
828
- // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
829
- // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
830
- if ( extract === 'basic' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== 'undefined' ) {
831
- return $.trim( tmp );
832
- }
833
- return $.trim( node.textContent || $node.text() );
834
- } else {
835
- if ( typeof extract === 'function' ) {
836
- return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );
837
- } else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === 'function' ) {
838
- return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );
839
- }
840
- }
841
- // fallback
842
- return $.trim( $node[ 0 ].textContent || $node.text() );
843
- },
844
-
845
- // centralized function to extract/parse cell contents
846
- getParsedText : function( c, cell, colIndex, txt ) {
847
- if ( typeof txt === 'undefined' ) {
848
- txt = ts.getElementText( c, cell, colIndex );
849
- }
850
- // if no parser, make sure to return the txt
851
- var val = '' + txt,
852
- parser = c.parsers[ colIndex ],
853
- extractor = c.extractors[ colIndex ];
854
- if ( parser ) {
855
- // do extract before parsing, if there is one
856
- if ( extractor && typeof extractor.format === 'function' ) {
857
- txt = extractor.format( txt, c.table, cell, colIndex );
858
- }
859
- // allow parsing if the string is empty, previously parsing would change it to zero,
860
- // in case the parser needs to extract data from the table cell attributes
861
- val = parser.id === 'no-parser' ? '' :
862
- // make sure txt is a string (extractor may have converted it)
863
- parser.format( '' + txt, c.table, cell, colIndex );
864
- if ( c.ignoreCase && typeof val === 'string' ) {
865
- val = val.toLowerCase();
866
- }
867
- }
868
- return val;
869
- },
870
-
871
- /*
872
- ▄████▄ ▄████▄ ▄████▄ ██ ██ ██████
873
- ██ ▀▀ ██▄▄██ ██ ▀▀ ██▄▄██ ██▄▄
874
- ██ ▄▄ ██▀▀██ ██ ▄▄ ██▀▀██ ██▀▀
875
- ▀████▀ ██ ██ ▀████▀ ██ ██ ██████
876
- */
877
- buildCache : function( c, callback, $tbodies ) {
878
- var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
879
- cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
880
- colMax, span, cacheIndex, hasParser, max, len, index,
881
- table = c.table,
882
- parsers = c.parsers,
883
- debug = ts.debug(c, 'core');
884
- // update tbody variable
885
- c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
886
- $tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
887
- c.cache = {};
888
- c.totalRows = 0;
889
- // if no parsers found, return - it's an empty table.
890
- if ( !parsers ) {
891
- return debug ? console.warn( 'Warning: *Empty table!* Not building a cache' ) : '';
892
- }
893
- if ( debug ) {
894
- cacheTime = new Date();
895
- }
896
- // processing icon
897
- if ( c.showProcessing ) {
898
- ts.isProcessing( table, true );
899
- }
900
- for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {
901
- colMax = []; // column max value per tbody
902
- cache = c.cache[ tbodyIndex ] = {
903
- normalized: [] // array of normalized row data; last entry contains 'rowData' above
904
- // colMax: # // added at the end
905
- };
906
-
907
- totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;
908
- for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {
909
- rowData = {
910
- // order: original row order #
911
- // $row : jQuery Object[]
912
- child: [], // child row text (filter widget)
913
- raw: [] // original row text
914
- };
915
- /** Add the table data to main data array */
916
- $row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );
917
- cols = [];
918
- // ignore "remove-me" rows
919
- if ( $row.hasClass( c.selectorRemove.slice(1) ) ) {
920
- continue;
921
- }
922
- // if this is a child row, add it to the last row's children and continue to the next row
923
- // ignore child row class, if it is the first row
924
- if ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {
925
- len = cache.normalized.length - 1;
926
- prevRowData = cache.normalized[ len ][ c.columns ];
927
- prevRowData.$row = prevRowData.$row.add( $row );
928
- // add 'hasChild' class name to parent row
929
- if ( !$row.prev().hasClass( c.cssChildRow ) ) {
930
- $row.prev().addClass( ts.css.cssHasChild );
931
- }
932
- // save child row content (un-parsed!)
933
- $cells = $row.children( 'th, td' );
934
- len = prevRowData.child.length;
935
- prevRowData.child[ len ] = [];
936
- // child row content does not account for colspans/rowspans; so indexing may be off
937
- cacheIndex = 0;
938
- max = c.columns;
939
- for ( colIndex = 0; colIndex < max; colIndex++ ) {
940
- cell = $cells[ colIndex ];
941
- if ( cell ) {
942
- prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );
943
- span = $cells[ colIndex ].colSpan - 1;
944
- if ( span > 0 ) {
945
- cacheIndex += span;
946
- max += span;
947
- }
948
- }
949
- cacheIndex++;
950
- }
951
- // go to the next for loop
952
- continue;
953
- }
954
- rowData.$row = $row;
955
- rowData.order = rowIndex; // add original row position to rowCache
956
- cacheIndex = 0;
957
- max = c.columns;
958
- for ( colIndex = 0; colIndex < max; ++colIndex ) {
959
- cell = $row[ 0 ].cells[ colIndex ];
960
- if ( cell && cacheIndex < c.columns ) {
961
- hasParser = typeof parsers[ cacheIndex ] !== 'undefined';
962
- if ( !hasParser && debug ) {
963
- console.warn( 'No parser found for row: ' + rowIndex + ', column: ' + colIndex +
964
- '; cell containing: "' + $(cell).text() + '"; does it have a header?' );
965
- }
966
- val = ts.getElementText( c, cell, cacheIndex );
967
- rowData.raw[ cacheIndex ] = val; // save original row text
968
- // save raw column text even if there is no parser set
969
- txt = ts.getParsedText( c, cell, cacheIndex, val );
970
- cols[ cacheIndex ] = txt;
971
- if ( hasParser && ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
972
- // determine column max value (ignore sign)
973
- colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
974
- }
975
- // allow colSpan in tbody
976
- span = cell.colSpan - 1;
977
- if ( span > 0 ) {
978
- index = 0;
979
- while ( index <= span ) {
980
- // duplicate text (or not) to spanned columns
981
- // instead of setting duplicate span to empty string, use textExtraction to try to get a value
982
- // see http://stackoverflow.com/q/36449711/145346
983
- txt = c.duplicateSpan || index === 0 ?
984
- val :
985
- typeof c.textExtraction !== 'string' ?
986
- ts.getElementText( c, cell, cacheIndex + index ) || '' :
987
- '';
988
- rowData.raw[ cacheIndex + index ] = txt;
989
- cols[ cacheIndex + index ] = txt;
990
- index++;
991
- }
992
- cacheIndex += span;
993
- max += span;
994
- }
995
- }
996
- cacheIndex++;
997
- }
998
- // ensure rowData is always in the same location (after the last column)
999
- cols[ c.columns ] = rowData;
1000
- cache.normalized[ cache.normalized.length ] = cols;
1001
- }
1002
- cache.colMax = colMax;
1003
- // total up rows, not including child rows
1004
- c.totalRows += cache.normalized.length;
1005
-
1006
- }
1007
- if ( c.showProcessing ) {
1008
- ts.isProcessing( table ); // remove processing icon
1009
- }
1010
- if ( debug ) {
1011
- len = Math.min( 5, c.cache[ 0 ].normalized.length );
1012
- console[ console.group ? 'group' : 'log' ]( 'Building cache for ' + c.totalRows +
1013
- ' rows (showing ' + len + ' rows in log) and ' + c.columns + ' columns' +
1014
- ts.benchmark( cacheTime ) );
1015
- val = {};
1016
- for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {
1017
- for ( cacheIndex = 0; cacheIndex < len; cacheIndex++ ) {
1018
- if ( !val[ 'row: ' + cacheIndex ] ) {
1019
- val[ 'row: ' + cacheIndex ] = {};
1020
- }
1021
- val[ 'row: ' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =
1022
- c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];
1023
- }
1024
- }
1025
- console[ console.table ? 'table' : 'log' ]( val );
1026
- if ( console.groupEnd ) { console.groupEnd(); }
1027
- }
1028
- if ( $.isFunction( callback ) ) {
1029
- callback( table );
1030
- }
1031
- },
1032
-
1033
- getColumnText : function( table, column, callback, rowFilter ) {
1034
- table = $( table )[0];
1035
- var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,
1036
- hasCallback = typeof callback === 'function',
1037
- allColumns = column === 'all',
1038
- data = { raw : [], parsed: [], $cell: [] },
1039
- c = table.config;
1040
- if ( ts.isEmptyObject( c ) ) {
1041
- if ( ts.debug(c, 'core') ) {
1042
- console.warn( 'No cache found - aborting getColumnText function!' );
1043
- }
1044
- } else {
1045
- tbodyLen = c.$tbodies.length;
1046
- for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {
1047
- cache = c.cache[ tbodyIndex ].normalized;
1048
- rowLen = cache.length;
1049
- for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {
1050
- row = cache[ rowIndex ];
1051
- if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {
1052
- continue;
1053
- }
1054
- result = true;
1055
- parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];
1056
- row = row[ c.columns ];
1057
- raw = ( allColumns ) ? row.raw : row.raw[ column ];
1058
- $cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
1059
- if ( hasCallback ) {
1060
- result = callback({
1061
- tbodyIndex : tbodyIndex,
1062
- rowIndex : rowIndex,
1063
- parsed : parsed,
1064
- raw : raw,
1065
- $row : row.$row,
1066
- $cell : $cell
1067
- });
1068
- }
1069
- if ( result !== false ) {
1070
- data.parsed[ data.parsed.length ] = parsed;
1071
- data.raw[ data.raw.length ] = raw;
1072
- data.$cell[ data.$cell.length ] = $cell;
1073
- }
1074
- }
1075
- }
1076
- // return everything
1077
- return data;
1078
- }
1079
- },
1080
-
1081
- /*
1082
- ██ ██ █████▄ █████▄ ▄████▄ ██████ ██████
1083
- ██ ██ ██▄▄██ ██ ██ ██▄▄██ ██ ██▄▄
1084
- ██ ██ ██▀▀▀ ██ ██ ██▀▀██ ██ ██▀▀
1085
- ▀████▀ ██ █████▀ ██ ██ ██ ██████
1086
- */
1087
- setHeadersCss : function( c ) {
1088
- var indx, column,
1089
- list = c.sortList,
1090
- len = list.length,
1091
- none = ts.css.sortNone + ' ' + c.cssNone,
1092
- css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ],
1093
- cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
1094
- aria = [ 'ascending', 'descending' ],
1095
- updateColumnSort = function($el, index) {
1096
- $el
1097
- .removeClass( none )
1098
- .addClass( css[ index ] )
1099
- .attr( 'aria-sort', aria[ index ] )
1100
- .find( '.' + ts.css.icon )
1101
- .removeClass( cssIcon[ 2 ] )
1102
- .addClass( cssIcon[ index ] );
1103
- },
1104
- // find the footer
1105
- $extras = c.$table
1106
- .find( 'tfoot tr' )
1107
- .children( 'td, th' )
1108
- .add( $( c.namespace + '_extra_headers' ) )
1109
- .removeClass( css.join( ' ' ) ),
1110
- // remove all header information
1111
- $sorted = c.$headers
1112
- .add( $( 'thead ' + c.namespace + '_extra_headers' ) )
1113
- .removeClass( css.join( ' ' ) )
1114
- .addClass( none )
1115
- .attr( 'aria-sort', 'none' )
1116
- .find( '.' + ts.css.icon )
1117
- .removeClass( cssIcon.join( ' ' ) )
1118
- .end();
1119
- // add css none to all sortable headers
1120
- $sorted
1121
- .not( '.sorter-false' )
1122
- .find( '.' + ts.css.icon )
1123
- .addClass( cssIcon[ 2 ] );
1124
- // add disabled css icon class
1125
- if ( c.cssIconDisabled ) {
1126
- $sorted
1127
- .filter( '.sorter-false' )
1128
- .find( '.' + ts.css.icon )
1129
- .addClass( c.cssIconDisabled );
1130
- }
1131
- for ( indx = 0; indx < len; indx++ ) {
1132
- // direction = 2 means reset!
1133
- if ( list[ indx ][ 1 ] !== 2 ) {
1134
- // multicolumn sorting updating - see #1005
1135
- // .not(function() {}) needs jQuery 1.4
1136
- // filter(function(i, el) {}) <- el is undefined in jQuery v1.2.6
1137
- $sorted = c.$headers.filter( function( i ) {
1138
- // only include headers that are in the sortList (this includes colspans)
1139
- var include = true,
1140
- $el = c.$headers.eq( i ),
1141
- col = parseInt( $el.attr( 'data-column' ), 10 ),
1142
- end = col + ts.getClosest( $el, 'th, td' )[0].colSpan;
1143
- for ( ; col < end; col++ ) {
1144
- include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;
1145
- }
1146
- return include;
1147
- });
1148
-
1149
- // choose the :last in case there are nested columns
1150
- $sorted = $sorted
1151
- .not( '.sorter-false' )
1152
- .filter( '[data-column="' + list[ indx ][ 0 ] + '"]' + ( len === 1 ? ':last' : '' ) );
1153
- if ( $sorted.length ) {
1154
- for ( column = 0; column < $sorted.length; column++ ) {
1155
- if ( !$sorted[ column ].sortDisabled ) {
1156
- updateColumnSort( $sorted.eq( column ), list[ indx ][ 1 ] );
1157
- }
1158
- }
1159
- }
1160
- // add sorted class to footer & extra headers, if they exist
1161
- if ( $extras.length ) {
1162
- updateColumnSort( $extras.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' ), list[ indx ][ 1 ] );
1163
- }
1164
- }
1165
- }
1166
- // add verbose aria labels
1167
- len = c.$headers.length;
1168
- for ( indx = 0; indx < len; indx++ ) {
1169
- ts.setColumnAriaLabel( c, c.$headers.eq( indx ) );
1170
- }
1171
- },
1172
-
1173
- getClosest : function( $el, selector ) {
1174
- // jQuery v1.2.6 doesn't have closest()
1175
- if ( $.fn.closest ) {
1176
- return $el.closest( selector );
1177
- }
1178
- return $el.is( selector ) ?
1179
- $el :
1180
- $el.parents( selector ).filter( ':first' );
1181
- },
1182
-
1183
- // nextSort (optional), lets you disable next sort text
1184
- setColumnAriaLabel : function( c, $header, nextSort ) {
1185
- if ( $header.length ) {
1186
- var column = parseInt( $header.attr( 'data-column' ), 10 ),
1187
- vars = c.sortVars[ column ],
1188
- tmp = $header.hasClass( ts.css.sortAsc ) ?
1189
- 'sortAsc' :
1190
- $header.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone',
1191
- txt = $.trim( $header.text() ) + ': ' + ts.language[ tmp ];
1192
- if ( $header.hasClass( 'sorter-false' ) || nextSort === false ) {
1193
- txt += ts.language.sortDisabled;
1194
- } else {
1195
- tmp = ( vars.count + 1 ) % vars.order.length;
1196
- nextSort = vars.order[ tmp ];
1197
- // if nextSort
1198
- txt += ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
1199
- }
1200
- $header.attr( 'aria-label', txt );
1201
- if (vars.sortedBy) {
1202
- $header.attr( 'data-sortedBy', vars.sortedBy );
1203
- } else {
1204
- $header.removeAttr('data-sortedBy');
1205
- }
1206
- }
1207
- },
1208
-
1209
- updateHeader : function( c ) {
1210
- var index, isDisabled, $header, col,
1211
- table = c.table,
1212
- len = c.$headers.length;
1213
- for ( index = 0; index < len; index++ ) {
1214
- $header = c.$headers.eq( index );
1215
- col = ts.getColumnData( table, c.headers, index, true );
1216
- // add 'sorter-false' class if 'parser-false' is set
1217
- isDisabled = ts.getData( $header, col, 'sorter' ) === 'false' || ts.getData( $header, col, 'parser' ) === 'false';
1218
- ts.setColumnSort( c, $header, isDisabled );
1219
- }
1220
- },
1221
-
1222
- setColumnSort : function( c, $header, isDisabled ) {
1223
- var id = c.table.id;
1224
- $header[ 0 ].sortDisabled = isDisabled;
1225
- $header[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' )
1226
- .attr( 'aria-disabled', '' + isDisabled );
1227
- // disable tab index on disabled cells
1228
- if ( c.tabIndex ) {
1229
- if ( isDisabled ) {
1230
- $header.removeAttr( 'tabindex' );
1231
- } else {
1232
- $header.attr( 'tabindex', '0' );
1233
- }
1234
- }
1235
- // aria-controls - requires table ID
1236
- if ( id ) {
1237
- if ( isDisabled ) {
1238
- $header.removeAttr( 'aria-controls' );
1239
- } else {
1240
- $header.attr( 'aria-controls', id );
1241
- }
1242
- }
1243
- },
1244
-
1245
- updateHeaderSortCount : function( c, list ) {
1246
- var col, dir, group, indx, primary, temp, val, order,
1247
- sortList = list || c.sortList,
1248
- len = sortList.length;
1249
- c.sortList = [];
1250
- for ( indx = 0; indx < len; indx++ ) {
1251
- val = sortList[ indx ];
1252
- // ensure all sortList values are numeric - fixes #127
1253
- col = parseInt( val[ 0 ], 10 );
1254
- // prevents error if sorton array is wrong
1255
- if ( col < c.columns ) {
1256
-
1257
- // set order if not already defined - due to colspan header without associated header cell
1258
- // adding this check prevents a javascript error
1259
- if ( !c.sortVars[ col ].order ) {
1260
- if ( ts.getOrder( c.sortInitialOrder ) ) {
1261
- order = c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ];
1262
- } else {
1263
- order = c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ];
1264
- }
1265
- c.sortVars[ col ].order = order;
1266
- c.sortVars[ col ].count = 0;
1267
- }
1268
-
1269
- order = c.sortVars[ col ].order;
1270
- dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
1271
- dir = dir ? dir[ 0 ] : '';
1272
- // 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
1273
- switch ( dir ) {
1274
- case '1' : case 'd' : // descending
1275
- dir = 1;
1276
- break;
1277
- case 's' : // same direction (as primary column)
1278
- // if primary sort is set to 's', make it ascending
1279
- dir = primary || 0;
1280
- break;
1281
- case 'o' :
1282
- temp = order[ ( primary || 0 ) % order.length ];
1283
- // opposite of primary column; but resets if primary resets
1284
- dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
1285
- break;
1286
- case 'n' :
1287
- dir = order[ ( ++c.sortVars[ col ].count ) % order.length ];
1288
- break;
1289
- default : // ascending
1290
- dir = 0;
1291
- break;
1292
- }
1293
- primary = indx === 0 ? dir : primary;
1294
- group = [ col, parseInt( dir, 10 ) || 0 ];
1295
- c.sortList[ c.sortList.length ] = group;
1296
- dir = $.inArray( group[ 1 ], order ); // fixes issue #167
1297
- c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % order.length;
1298
- }
1299
- }
1300
- },
1301
-
1302
- updateAll : function( c, resort, callback ) {
1303
- var table = c.table;
1304
- table.isUpdating = true;
1305
- ts.refreshWidgets( table, true, true );
1306
- ts.buildHeaders( c );
1307
- ts.bindEvents( table, c.$headers, true );
1308
- ts.bindMethods( c );
1309
- ts.commonUpdate( c, resort, callback );
1310
- },
1311
-
1312
- update : function( c, resort, callback ) {
1313
- var table = c.table;
1314
- table.isUpdating = true;
1315
- // update sorting (if enabled/disabled)
1316
- ts.updateHeader( c );
1317
- ts.commonUpdate( c, resort, callback );
1318
- },
1319
-
1320
- // simple header update - see #989
1321
- updateHeaders : function( c, callback ) {
1322
- c.table.isUpdating = true;
1323
- ts.buildHeaders( c );
1324
- ts.bindEvents( c.table, c.$headers, true );
1325
- ts.resortComplete( c, callback );
1326
- },
1327
-
1328
- updateCell : function( c, cell, resort, callback ) {
1329
- // updateCell for child rows is a mess - we'll ignore them for now
1330
- // eventually I'll break out the "update" row cache code to make everything consistent
1331
- if ( $( cell ).closest( 'tr' ).hasClass( c.cssChildRow ) ) {
1332
- console.warn('Tablesorter Warning! "updateCell" for child row content has been disabled, use "update" instead');
1333
- return;
1334
- }
1335
- if ( ts.isEmptyObject( c.cache ) ) {
1336
- // empty table, do an update instead - fixes #1099
1337
- ts.updateHeader( c );
1338
- ts.commonUpdate( c, resort, callback );
1339
- return;
1340
- }
1341
- c.table.isUpdating = true;
1342
- c.$table.find( c.selectorRemove ).remove();
1343
- // get position from the dom
1344
- var tmp, indx, row, icell, cache, len,
1345
- $tbodies = c.$tbodies,
1346
- $cell = $( cell ),
1347
- // update cache - format: function( s, table, cell, cellIndex )
1348
- // no closest in jQuery v1.2.6
1349
- tbodyIndex = $tbodies.index( ts.getClosest( $cell, 'tbody' ) ),
1350
- tbcache = c.cache[ tbodyIndex ],
1351
- $row = ts.getClosest( $cell, 'tr' );
1352
- cell = $cell[ 0 ]; // in case cell is a jQuery object
1353
- // tbody may not exist if update is initialized while tbody is removed for processing
1354
- if ( $tbodies.length && tbodyIndex >= 0 ) {
1355
- row = $tbodies.eq( tbodyIndex ).find( 'tr' ).not( '.' + c.cssChildRow ).index( $row );
1356
- cache = tbcache.normalized[ row ];
1357
- len = $row[ 0 ].cells.length;
1358
- if ( len !== c.columns ) {
1359
- // colspan in here somewhere!
1360
- icell = 0;
1361
- tmp = false;
1362
- for ( indx = 0; indx < len; indx++ ) {
1363
- if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {
1364
- icell += $row[ 0 ].cells[ indx ].colSpan;
1365
- } else {
1366
- tmp = true;
1367
- }
1368
- }
1369
- } else {
1370
- icell = $cell.index();
1371
- }
1372
- tmp = ts.getElementText( c, cell, icell ); // raw
1373
- cache[ c.columns ].raw[ icell ] = tmp;
1374
- tmp = ts.getParsedText( c, cell, icell, tmp );
1375
- cache[ icell ] = tmp; // parsed
1376
- if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
1377
- // update column max value (ignore sign)
1378
- tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );
1379
- }
1380
- tmp = resort !== 'undefined' ? resort : c.resort;
1381
- if ( tmp !== false ) {
1382
- // widgets will be reapplied
1383
- ts.checkResort( c, tmp, callback );
1384
- } else {
1385
- // don't reapply widgets is resort is false, just in case it causes
1386
- // problems with element focus
1387
- ts.resortComplete( c, callback );
1388
- }
1389
- } else {
1390
- if ( ts.debug(c, 'core') ) {
1391
- console.error( 'updateCell aborted, tbody missing or not within the indicated table' );
1392
- }
1393
- c.table.isUpdating = false;
1394
- }
1395
- },
1396
-
1397
- addRows : function( c, $row, resort, callback ) {
1398
- var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len, order,
1399
- cacheIndex, rowData, cells, cell, span,
1400
- // allow passing a row string if only one non-info tbody exists in the table
1401
- valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
1402
- table = c.table;
1403
- if ( valid ) {
1404
- $row = $( $row );
1405
- c.$tbodies.append( $row );
1406
- } else if (
1407
- !$row ||
1408
- // row is a jQuery object?
1409
- !( $row instanceof $ ) ||
1410
- // row contained in the table?
1411
- ( ts.getClosest( $row, 'table' )[ 0 ] !== c.table )
1412
- ) {
1413
- if ( ts.debug(c, 'core') ) {
1414
- console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
1415
- 'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
1416
- }
1417
- return false;
1418
- }
1419
- table.isUpdating = true;
1420
- if ( ts.isEmptyObject( c.cache ) ) {
1421
- // empty table, do an update instead - fixes #450
1422
- ts.updateHeader( c );
1423
- ts.commonUpdate( c, resort, callback );
1424
- } else {
1425
- rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
1426
- tbodyIndex = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
1427
- // fixes adding rows to an empty table - see issue #179
1428
- if ( !( c.parsers && c.parsers.length ) ) {
1429
- ts.setupParsers( c );
1430
- }
1431
- // add each row
1432
- for ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {
1433
- cacheIndex = 0;
1434
- len = $row[ rowIndex ].cells.length;
1435
- order = c.cache[ tbodyIndex ].normalized.length;
1436
- cells = [];
1437
- rowData = {
1438
- child : [],
1439
- raw : [],
1440
- $row : $row.eq( rowIndex ),
1441
- order : order
1442
- };
1443
- // add each cell
1444
- for ( cellIndex = 0; cellIndex < len; cellIndex++ ) {
1445
- cell = $row[ rowIndex ].cells[ cellIndex ];
1446
- txt = ts.getElementText( c, cell, cacheIndex );
1447
- rowData.raw[ cacheIndex ] = txt;
1448
- val = ts.getParsedText( c, cell, cacheIndex, txt );
1449
- cells[ cacheIndex ] = val;
1450
- if ( ( c.parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
1451
- // update column max value (ignore sign)
1452
- c.cache[ tbodyIndex ].colMax[ cacheIndex ] =
1453
- Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );
1454
- }
1455
- span = cell.colSpan - 1;
1456
- if ( span > 0 ) {
1457
- cacheIndex += span;
1458
- }
1459
- cacheIndex++;
1460
- }
1461
- // add the row data to the end
1462
- cells[ c.columns ] = rowData;
1463
- // update cache
1464
- c.cache[ tbodyIndex ].normalized[ order ] = cells;
1465
- }
1466
- // resort using current settings
1467
- ts.checkResort( c, resort, callback );
1468
- }
1469
- },
1470
-
1471
- updateCache : function( c, callback, $tbodies ) {
1472
- // rebuild parsers
1473
- if ( !( c.parsers && c.parsers.length ) ) {
1474
- ts.setupParsers( c, $tbodies );
1475
- }
1476
- // rebuild the cache map
1477
- ts.buildCache( c, callback, $tbodies );
1478
- },
1479
-
1480
- // init flag (true) used by pager plugin to prevent widget application
1481
- // renamed from appendToTable
1482
- appendCache : function( c, init ) {
1483
- var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,
1484
- table = c.table,
1485
- $tbodies = c.$tbodies,
1486
- rows = [],
1487
- cache = c.cache;
1488
- // empty table - fixes #206/#346
1489
- if ( ts.isEmptyObject( cache ) ) {
1490
- // run pager appender in case the table was just emptied
1491
- return c.appender ? c.appender( table, rows ) :
1492
- table.isUpdating ? c.$table.triggerHandler( 'updateComplete', table ) : ''; // Fixes #532
1493
- }
1494
- if ( ts.debug(c, 'core') ) {
1495
- appendTime = new Date();
1496
- }
1497
- for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
1498
- $tbody = $tbodies.eq( tbodyIndex );
1499
- if ( $tbody.length ) {
1500
- // detach tbody for manipulation
1501
- $curTbody = ts.processTbody( table, $tbody, true );
1502
- parsed = cache[ tbodyIndex ].normalized;
1503
- totalRows = parsed.length;
1504
- for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
1505
- rows[rows.length] = parsed[ rowIndex ][ c.columns ].$row;
1506
- // removeRows used by the pager plugin; don't render if using ajax - fixes #411
1507
- if ( !c.appender || ( c.pager && !c.pager.removeRows && !c.pager.ajax ) ) {
1508
- $curTbody.append( parsed[ rowIndex ][ c.columns ].$row );
1509
- }
1510
- }
1511
- // restore tbody
1512
- ts.processTbody( table, $curTbody, false );
1513
- }
1514
- }
1515
- if ( c.appender ) {
1516
- c.appender( table, rows );
1517
- }
1518
- if ( ts.debug(c, 'core') ) {
1519
- console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
1520
- }
1521
- // apply table widgets; but not before ajax completes
1522
- if ( !init && !c.appender ) {
1523
- ts.applyWidget( table );
1524
- }
1525
- if ( table.isUpdating ) {
1526
- c.$table.triggerHandler( 'updateComplete', table );
1527
- }
1528
- },
1529
-
1530
- commonUpdate : function( c, resort, callback ) {
1531
- // remove rows/elements before update
1532
- c.$table.find( c.selectorRemove ).remove();
1533
- // rebuild parsers
1534
- ts.setupParsers( c );
1535
- // rebuild the cache map
1536
- ts.buildCache( c );
1537
- ts.checkResort( c, resort, callback );
1538
- },
1539
-
1540
- /*
1541
- ▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄
1542
- ▀█▄ ██ ██ ██▄▄██ ██ ██ ██ ██ ██ ▄▄▄
1543
- ▀█▄ ██ ██ ██▀██ ██ ██ ██ ██ ██ ▀██
1544
- █████▀ ▀████▀ ██ ██ ██ ██ ██ ██ ▀████▀
1545
- */
1546
- initSort : function( c, cell, event ) {
1547
- if ( c.table.isUpdating ) {
1548
- // let any updates complete before initializing a sort
1549
- return setTimeout( function() {
1550
- ts.initSort( c, cell, event );
1551
- }, 50 );
1552
- }
1553
-
1554
- var arry, indx, headerIndx, dir, temp, tmp, $header,
1555
- notMultiSort = !event[ c.sortMultiSortKey ],
1556
- table = c.table,
1557
- len = c.$headers.length,
1558
- th = ts.getClosest( $( cell ), 'th, td' ),
1559
- col = parseInt( th.attr( 'data-column' ), 10 ),
1560
- sortedBy = event.type === 'mouseup' ? 'user' : event.type,
1561
- order = c.sortVars[ col ].order;
1562
- th = th[0];
1563
- // Only call sortStart if sorting is enabled
1564
- c.$table.triggerHandler( 'sortStart', table );
1565
- // get current column sort order
1566
- tmp = ( c.sortVars[ col ].count + 1 ) % order.length;
1567
- c.sortVars[ col ].count = event[ c.sortResetKey ] ? 2 : tmp;
1568
- // reset all sorts on non-current column - issue #30
1569
- if ( c.sortRestart ) {
1570
- for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {
1571
- $header = c.$headers.eq( headerIndx );
1572
- tmp = parseInt( $header.attr( 'data-column' ), 10 );
1573
- // only reset counts on columns that weren't just clicked on and if not included in a multisort
1574
- if ( col !== tmp && ( notMultiSort || $header.hasClass( ts.css.sortNone ) ) ) {
1575
- c.sortVars[ tmp ].count = -1;
1576
- }
1577
- }
1578
- }
1579
- // user only wants to sort on one column
1580
- if ( notMultiSort ) {
1581
- $.each( c.sortVars, function( i ) {
1582
- c.sortVars[ i ].sortedBy = '';
1583
- });
1584
- // flush the sort list
1585
- c.sortList = [];
1586
- c.last.sortList = [];
1587
- if ( c.sortForce !== null ) {
1588
- arry = c.sortForce;
1589
- for ( indx = 0; indx < arry.length; indx++ ) {
1590
- if ( arry[ indx ][ 0 ] !== col ) {
1591
- c.sortList[ c.sortList.length ] = arry[ indx ];
1592
- c.sortVars[ arry[ indx ][ 0 ] ].sortedBy = 'sortForce';
1593
- }
1594
- }
1595
- }
1596
- // add column to sort list
1597
- dir = order[ c.sortVars[ col ].count ];
1598
- if ( dir < 2 ) {
1599
- c.sortList[ c.sortList.length ] = [ col, dir ];
1600
- c.sortVars[ col ].sortedBy = sortedBy;
1601
- // add other columns if header spans across multiple
1602
- if ( th.colSpan > 1 ) {
1603
- for ( indx = 1; indx < th.colSpan; indx++ ) {
1604
- c.sortList[ c.sortList.length ] = [ col + indx, dir ];
1605
- // update count on columns in colSpan
1606
- c.sortVars[ col + indx ].count = $.inArray( dir, order );
1607
- c.sortVars[ col + indx ].sortedBy = sortedBy;
1608
- }
1609
- }
1610
- }
1611
- // multi column sorting
1612
- } else {
1613
- // get rid of the sortAppend before adding more - fixes issue #115 & #523
1614
- c.sortList = $.extend( [], c.last.sortList );
1615
-
1616
- // the user has clicked on an already sorted column
1617
- if ( ts.isValueInArray( col, c.sortList ) >= 0 ) {
1618
- // reverse the sorting direction
1619
- c.sortVars[ col ].sortedBy = sortedBy;
1620
- for ( indx = 0; indx < c.sortList.length; indx++ ) {
1621
- tmp = c.sortList[ indx ];
1622
- if ( tmp[ 0 ] === col ) {
1623
- // order.count seems to be incorrect when compared to cell.count
1624
- tmp[ 1 ] = order[ c.sortVars[ col ].count ];
1625
- if ( tmp[1] === 2 ) {
1626
- c.sortList.splice( indx, 1 );
1627
- c.sortVars[ col ].count = -1;
1628
- }
1629
- }
1630
- }
1631
- } else {
1632
- // add column to sort list array
1633
- dir = order[ c.sortVars[ col ].count ];
1634
- c.sortVars[ col ].sortedBy = sortedBy;
1635
- if ( dir < 2 ) {
1636
- c.sortList[ c.sortList.length ] = [ col, dir ];
1637
- // add other columns if header spans across multiple
1638
- if ( th.colSpan > 1 ) {
1639
- for ( indx = 1; indx < th.colSpan; indx++ ) {
1640
- c.sortList[ c.sortList.length ] = [ col + indx, dir ];
1641
- // update count on columns in colSpan
1642
- c.sortVars[ col + indx ].count = $.inArray( dir, order );
1643
- c.sortVars[ col + indx ].sortedBy = sortedBy;
1644
- }
1645
- }
1646
- }
1647
- }
1648
- }
1649
- // save sort before applying sortAppend
1650
- c.last.sortList = $.extend( [], c.sortList );
1651
- if ( c.sortList.length && c.sortAppend ) {
1652
- arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];
1653
- if ( !ts.isEmptyObject( arry ) ) {
1654
- for ( indx = 0; indx < arry.length; indx++ ) {
1655
- if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {
1656
- dir = arry[ indx ][ 1 ];
1657
- temp = ( '' + dir ).match( /^(a|d|s|o|n)/ );
1658
- if ( temp ) {
1659
- tmp = c.sortList[ 0 ][ 1 ];
1660
- switch ( temp[ 0 ] ) {
1661
- case 'd' :
1662
- dir = 1;
1663
- break;
1664
- case 's' :
1665
- dir = tmp;
1666
- break;
1667
- case 'o' :
1668
- dir = tmp === 0 ? 1 : 0;
1669
- break;
1670
- case 'n' :
1671
- dir = ( tmp + 1 ) % order.length;
1672
- break;
1673
- default:
1674
- dir = 0;
1675
- break;
1676
- }
1677
- }
1678
- c.sortList[ c.sortList.length ] = [ arry[ indx ][ 0 ], dir ];
1679
- c.sortVars[ arry[ indx ][ 0 ] ].sortedBy = 'sortAppend';
1680
- }
1681
- }
1682
- }
1683
- }
1684
- // sortBegin event triggered immediately before the sort
1685
- c.$table.triggerHandler( 'sortBegin', table );
1686
- // setTimeout needed so the processing icon shows up
1687
- setTimeout( function() {
1688
- // set css for headers
1689
- ts.setHeadersCss( c );
1690
- ts.multisort( c );
1691
- ts.appendCache( c );
1692
- c.$table.triggerHandler( 'sortBeforeEnd', table );
1693
- c.$table.triggerHandler( 'sortEnd', table );
1694
- }, 1 );
1695
- },
1696
-
1697
- // sort multiple columns
1698
- multisort : function( c ) { /*jshint loopfunc:true */
1699
- var tbodyIndex, sortTime, colMax, rows, tmp,
1700
- table = c.table,
1701
- sorter = [],
1702
- dir = 0,
1703
- textSorter = c.textSorter || '',
1704
- sortList = c.sortList,
1705
- sortLen = sortList.length,
1706
- len = c.$tbodies.length;
1707
- if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {
1708
- // empty table - fixes #206/#346
1709
- return;
1710
- }
1711
- if ( ts.debug(c, 'core') ) { sortTime = new Date(); }
1712
- // cache textSorter to optimize speed
1713
- if ( typeof textSorter === 'object' ) {
1714
- colMax = c.columns;
1715
- while ( colMax-- ) {
1716
- tmp = ts.getColumnData( table, textSorter, colMax );
1717
- if ( typeof tmp === 'function' ) {
1718
- sorter[ colMax ] = tmp;
1719
- }
1720
- }
1721
- }
1722
- for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {
1723
- colMax = c.cache[ tbodyIndex ].colMax;
1724
- rows = c.cache[ tbodyIndex ].normalized;
1725
-
1726
- rows.sort( function( a, b ) {
1727
- var sortIndex, num, col, order, sort, x, y;
1728
- // rows is undefined here in IE, so don't use it!
1729
- for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {
1730
- col = sortList[ sortIndex ][ 0 ];
1731
- order = sortList[ sortIndex ][ 1 ];
1732
- // sort direction, true = asc, false = desc
1733
- dir = order === 0;
1734
-
1735
- if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {
1736
- return a[ c.columns ].order - b[ c.columns ].order;
1737
- }
1738
-
1739
- // fallback to natural sort since it is more robust
1740
- num = /n/i.test( ts.getSortType( c.parsers, col ) );
1741
- if ( num && c.strings[ col ] ) {
1742
- // sort strings in numerical columns
1743
- if ( typeof ( ts.string[ c.strings[ col ] ] ) === 'boolean' ) {
1744
- num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );
1745
- } else {
1746
- num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;
1747
- }
1748
- // fall back to built-in numeric sort
1749
- // var sort = $.tablesorter['sort' + s]( a[col], b[col], dir, colMax[col], table );
1750
- sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :
1751
- ts[ 'sortNumeric' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );
1752
- } else {
1753
- // set a & b depending on sort direction
1754
- x = dir ? a : b;
1755
- y = dir ? b : a;
1756
- // text sort function
1757
- if ( typeof textSorter === 'function' ) {
1758
- // custom OVERALL text sorter
1759
- sort = textSorter( x[ col ], y[ col ], dir, col, table );
1760
- } else if ( typeof sorter[ col ] === 'function' ) {
1761
- // custom text sorter for a SPECIFIC COLUMN
1762
- sort = sorter[ col ]( x[ col ], y[ col ], dir, col, table );
1763
- } else {
1764
- // fall back to natural sort
1765
- sort = ts[ 'sortNatural' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ] || '', b[ col ] || '', col, c );
1766
- }
1767
- }
1768
- if ( sort ) { return sort; }
1769
- }
1770
- return a[ c.columns ].order - b[ c.columns ].order;
1771
- });
1772
- }
1773
- if ( ts.debug(c, 'core') ) {
1774
- console.log( 'Applying sort ' + sortList.toString() + ts.benchmark( sortTime ) );
1775
- }
1776
- },
1777
-
1778
- resortComplete : function( c, callback ) {
1779
- if ( c.table.isUpdating ) {
1780
- c.$table.triggerHandler( 'updateComplete', c.table );
1781
- }
1782
- if ( $.isFunction( callback ) ) {
1783
- callback( c.table );
1784
- }
1785
- },
1786
-
1787
- checkResort : function( c, resort, callback ) {
1788
- var sortList = $.isArray( resort ) ? resort : c.sortList,
1789
- // if no resort parameter is passed, fallback to config.resort (true by default)
1790
- resrt = typeof resort === 'undefined' ? c.resort : resort;
1791
- // don't try to resort if the table is still processing
1792
- // this will catch spamming of the updateCell method
1793
- if ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {
1794
- if ( sortList.length ) {
1795
- ts.sortOn( c, sortList, function() {
1796
- ts.resortComplete( c, callback );
1797
- }, true );
1798
- } else {
1799
- ts.sortReset( c, function() {
1800
- ts.resortComplete( c, callback );
1801
- ts.applyWidget( c.table, false );
1802
- } );
1803
- }
1804
- } else {
1805
- ts.resortComplete( c, callback );
1806
- ts.applyWidget( c.table, false );
1807
- }
1808
- },
1809
-
1810
- sortOn : function( c, list, callback, init ) {
1811
- var indx,
1812
- table = c.table;
1813
- c.$table.triggerHandler( 'sortStart', table );
1814
- for (indx = 0; indx < c.columns; indx++) {
1815
- c.sortVars[ indx ].sortedBy = ts.isValueInArray( indx, list ) > -1 ? 'sorton' : '';
1816
- }
1817
- // update header count index
1818
- ts.updateHeaderSortCount( c, list );
1819
- // set css for headers
1820
- ts.setHeadersCss( c );
1821
- // fixes #346
1822
- if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
1823
- ts.buildCache( c );
1824
- }
1825
- c.$table.triggerHandler( 'sortBegin', table );
1826
- // sort the table and append it to the dom
1827
- ts.multisort( c );
1828
- ts.appendCache( c, init );
1829
- c.$table.triggerHandler( 'sortBeforeEnd', table );
1830
- c.$table.triggerHandler( 'sortEnd', table );
1831
- ts.applyWidget( table );
1832
- if ( $.isFunction( callback ) ) {
1833
- callback( table );
1834
- }
1835
- },
1836
-
1837
- sortReset : function( c, callback ) {
1838
- c.sortList = [];
1839
- var indx;
1840
- for (indx = 0; indx < c.columns; indx++) {
1841
- c.sortVars[ indx ].count = -1;
1842
- c.sortVars[ indx ].sortedBy = '';
1843
- }
1844
- ts.setHeadersCss( c );
1845
- ts.multisort( c );
1846
- ts.appendCache( c );
1847
- if ( $.isFunction( callback ) ) {
1848
- callback( c.table );
1849
- }
1850
- },
1851
-
1852
- getSortType : function( parsers, column ) {
1853
- return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
1854
- },
1855
-
1856
- getOrder : function( val ) {
1857
- // look for 'd' in 'desc' order; return true
1858
- return ( /^d/i.test( val ) || val === 1 );
1859
- },
1860
-
1861
- // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
1862
- sortNatural : function( a, b ) {
1863
- if ( a === b ) { return 0; }
1864
- a = ( a || '' ).toString();
1865
- b = ( b || '' ).toString();
1866
- var aNum, bNum, aFloat, bFloat, indx, max,
1867
- regex = ts.regex;
1868
- // first try and sort Hex codes
1869
- if ( regex.hex.test( b ) ) {
1870
- aNum = parseInt( a.match( regex.hex ), 16 );
1871
- bNum = parseInt( b.match( regex.hex ), 16 );
1872
- if ( aNum < bNum ) { return -1; }
1873
- if ( aNum > bNum ) { return 1; }
1874
- }
1875
- // chunk/tokenize
1876
- aNum = a.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
1877
- bNum = b.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
1878
- max = Math.max( aNum.length, bNum.length );
1879
- // natural sorting through split numeric strings and default strings
1880
- for ( indx = 0; indx < max; indx++ ) {
1881
- // find floats not starting with '0', string or 0 if not defined
1882
- aFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;
1883
- bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;
1884
- // handle numeric vs string comparison - number < string - (Kyle Adams)
1885
- if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }
1886
- // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
1887
- if ( typeof aFloat !== typeof bFloat ) {
1888
- aFloat += '';
1889
- bFloat += '';
1890
- }
1891
- if ( aFloat < bFloat ) { return -1; }
1892
- if ( aFloat > bFloat ) { return 1; }
1893
- }
1894
- return 0;
1895
- },
1896
-
1897
- sortNaturalAsc : function( a, b, col, c ) {
1898
- if ( a === b ) { return 0; }
1899
- var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1900
- if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
1901
- if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
1902
- return ts.sortNatural( a, b );
1903
- },
1904
-
1905
- sortNaturalDesc : function( a, b, col, c ) {
1906
- if ( a === b ) { return 0; }
1907
- var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1908
- if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
1909
- if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
1910
- return ts.sortNatural( b, a );
1911
- },
1912
-
1913
- // basic alphabetical sort
1914
- sortText : function( a, b ) {
1915
- return a > b ? 1 : ( a < b ? -1 : 0 );
1916
- },
1917
-
1918
- // return text string value by adding up ascii value
1919
- // so the text is somewhat sorted when using a digital sort
1920
- // this is NOT an alphanumeric sort
1921
- getTextValue : function( val, num, max ) {
1922
- if ( max ) {
1923
- // make sure the text value is greater than the max numerical value (max)
1924
- var indx,
1925
- len = val ? val.length : 0,
1926
- n = max + num;
1927
- for ( indx = 0; indx < len; indx++ ) {
1928
- n += val.charCodeAt( indx );
1929
- }
1930
- return num * n;
1931
- }
1932
- return 0;
1933
- },
1934
-
1935
- sortNumericAsc : function( a, b, num, max, col, c ) {
1936
- if ( a === b ) { return 0; }
1937
- var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1938
- if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
1939
- if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
1940
- if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
1941
- if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
1942
- return a - b;
1943
- },
1944
-
1945
- sortNumericDesc : function( a, b, num, max, col, c ) {
1946
- if ( a === b ) { return 0; }
1947
- var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1948
- if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
1949
- if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
1950
- if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
1951
- if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
1952
- return b - a;
1953
- },
1954
-
1955
- sortNumeric : function( a, b ) {
1956
- return a - b;
1957
- },
1958
-
1959
- /*
1960
- ██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄█████
1961
- ██ ██ ██ ██ ██ ██ ██ ▄▄▄ ██▄▄ ██ ▀█▄
1962
- ██ ██ ██ ██ ██ ██ ██ ▀██ ██▀▀ ██ ▀█▄
1963
- ███████▀ ██ █████▀ ▀████▀ ██████ ██ █████▀
1964
- */
1965
- addWidget : function( widget ) {
1966
- if ( widget.id && !ts.isEmptyObject( ts.getWidgetById( widget.id ) ) ) {
1967
- console.warn( '"' + widget.id + '" widget was loaded more than once!' );
1968
- }
1969
- ts.widgets[ ts.widgets.length ] = widget;
1970
- },
1971
-
1972
- hasWidget : function( $table, name ) {
1973
- $table = $( $table );
1974
- return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;
1975
- },
1976
-
1977
- getWidgetById : function( name ) {
1978
- var indx, widget,
1979
- len = ts.widgets.length;
1980
- for ( indx = 0; indx < len; indx++ ) {
1981
- widget = ts.widgets[ indx ];
1982
- if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {
1983
- return widget;
1984
- }
1985
- }
1986
- },
1987
-
1988
- applyWidgetOptions : function( table ) {
1989
- var indx, widget, wo,
1990
- c = table.config,
1991
- len = c.widgets.length;
1992
- if ( len ) {
1993
- for ( indx = 0; indx < len; indx++ ) {
1994
- widget = ts.getWidgetById( c.widgets[ indx ] );
1995
- if ( widget && widget.options ) {
1996
- wo = $.extend( true, {}, widget.options );
1997
- c.widgetOptions = $.extend( true, wo, c.widgetOptions );
1998
- // add widgetOptions to defaults for option validator
1999
- $.extend( true, ts.defaults.widgetOptions, widget.options );
2000
- }
2001
- }
2002
- }
2003
- },
2004
-
2005
- addWidgetFromClass : function( table ) {
2006
- var len, indx,
2007
- c = table.config,
2008
- // look for widgets to apply from table class
2009
- // don't match from 'ui-widget-content'; use \S instead of \w to include widgets
2010
- // with dashes in the name, e.g. "widget-test-2" extracts out "test-2"
2011
- regex = '^' + c.widgetClass.replace( ts.regex.templateName, '(\\S+)+' ) + '$',
2012
- widgetClass = new RegExp( regex, 'g' ),
2013
- // split up table class (widget id's can include dashes) - stop using match
2014
- // otherwise only one widget gets extracted, see #1109
2015
- widgets = ( table.className || '' ).split( ts.regex.spaces );
2016
- if ( widgets.length ) {
2017
- len = widgets.length;
2018
- for ( indx = 0; indx < len; indx++ ) {
2019
- if ( widgets[ indx ].match( widgetClass ) ) {
2020
- c.widgets[ c.widgets.length ] = widgets[ indx ].replace( widgetClass, '$1' );
2021
- }
2022
- }
2023
- }
2024
- },
2025
-
2026
- applyWidgetId : function( table, id, init ) {
2027
- table = $(table)[0];
2028
- var applied, time, name,
2029
- c = table.config,
2030
- wo = c.widgetOptions,
2031
- debug = ts.debug(c, 'core'),
2032
- widget = ts.getWidgetById( id );
2033
- if ( widget ) {
2034
- name = widget.id;
2035
- applied = false;
2036
- // add widget name to option list so it gets reapplied after sorting, filtering, etc
2037
- if ( $.inArray( name, c.widgets ) < 0 ) {
2038
- c.widgets[ c.widgets.length ] = name;
2039
- }
2040
- if ( debug ) { time = new Date(); }
2041
-
2042
- if ( init || !( c.widgetInit[ name ] ) ) {
2043
- // set init flag first to prevent calling init more than once (e.g. pager)
2044
- c.widgetInit[ name ] = true;
2045
- if ( table.hasInitialized ) {
2046
- // don't reapply widget options on tablesorter init
2047
- ts.applyWidgetOptions( table );
2048
- }
2049
- if ( typeof widget.init === 'function' ) {
2050
- applied = true;
2051
- if ( debug ) {
2052
- console[ console.group ? 'group' : 'log' ]( 'Initializing ' + name + ' widget' );
2053
- }
2054
- widget.init( table, widget, c, wo );
2055
- }
2056
- }
2057
- if ( !init && typeof widget.format === 'function' ) {
2058
- applied = true;
2059
- if ( debug ) {
2060
- console[ console.group ? 'group' : 'log' ]( 'Updating ' + name + ' widget' );
2061
- }
2062
- widget.format( table, c, wo, false );
2063
- }
2064
- if ( debug ) {
2065
- if ( applied ) {
2066
- console.log( 'Completed ' + ( init ? 'initializing ' : 'applying ' ) + name + ' widget' + ts.benchmark( time ) );
2067
- if ( console.groupEnd ) { console.groupEnd(); }
2068
- }
2069
- }
2070
- }
2071
- },
2072
-
2073
- applyWidget : function( table, init, callback ) {
2074
- table = $( table )[ 0 ]; // in case this is called externally
2075
- var indx, len, names, widget, time,
2076
- c = table.config,
2077
- debug = ts.debug(c, 'core'),
2078
- widgets = [];
2079
- // prevent numerous consecutive widget applications
2080
- if ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {
2081
- return;
2082
- }
2083
- if ( debug ) { time = new Date(); }
2084
- ts.addWidgetFromClass( table );
2085
- // prevent "tablesorter-ready" from firing multiple times in a row
2086
- clearTimeout( c.timerReady );
2087
- if ( c.widgets.length ) {
2088
- table.isApplyingWidgets = true;
2089
- // ensure unique widget ids
2090
- c.widgets = $.grep( c.widgets, function( val, index ) {
2091
- return $.inArray( val, c.widgets ) === index;
2092
- });
2093
- names = c.widgets || [];
2094
- len = names.length;
2095
- // build widget array & add priority as needed
2096
- for ( indx = 0; indx < len; indx++ ) {
2097
- widget = ts.getWidgetById( names[ indx ] );
2098
- if ( widget && widget.id ) {
2099
- // set priority to 10 if not defined
2100
- if ( !widget.priority ) { widget.priority = 10; }
2101
- widgets[ indx ] = widget;
2102
- } else if ( debug ) {
2103
- console.warn( '"' + names[ indx ] + '" was enabled, but the widget code has not been loaded!' );
2104
- }
2105
- }
2106
- // sort widgets by priority
2107
- widgets.sort( function( a, b ) {
2108
- return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
2109
- });
2110
- // add/update selected widgets
2111
- len = widgets.length;
2112
- if ( debug ) {
2113
- console[ console.group ? 'group' : 'log' ]( 'Start ' + ( init ? 'initializing' : 'applying' ) + ' widgets' );
2114
- }
2115
- for ( indx = 0; indx < len; indx++ ) {
2116
- widget = widgets[ indx ];
2117
- if ( widget && widget.id ) {
2118
- ts.applyWidgetId( table, widget.id, init );
2119
- }
2120
- }
2121
- if ( debug && console.groupEnd ) { console.groupEnd(); }
2122
- }
2123
- c.timerReady = setTimeout( function() {
2124
- table.isApplyingWidgets = false;
2125
- $.data( table, 'lastWidgetApplication', new Date() );
2126
- c.$table.triggerHandler( 'tablesorter-ready' );
2127
- // callback executed on init only
2128
- if ( !init && typeof callback === 'function' ) {
2129
- callback( table );
2130
- }
2131
- if ( debug ) {
2132
- widget = c.widgets.length;
2133
- console.log( 'Completed ' +
2134
- ( init === true ? 'initializing ' : 'applying ' ) + widget +
2135
- ' widget' + ( widget !== 1 ? 's' : '' ) + ts.benchmark( time ) );
2136
- }
2137
- }, 10 );
2138
- },
2139
-
2140
- removeWidget : function( table, name, refreshing ) {
2141
- table = $( table )[ 0 ];
2142
- var index, widget, indx, len,
2143
- c = table.config;
2144
- // if name === true, add all widgets from $.tablesorter.widgets
2145
- if ( name === true ) {
2146
- name = [];
2147
- len = ts.widgets.length;
2148
- for ( indx = 0; indx < len; indx++ ) {
2149
- widget = ts.widgets[ indx ];
2150
- if ( widget && widget.id ) {
2151
- name[ name.length ] = widget.id;
2152
- }
2153
- }
2154
- } else {
2155
- // name can be either an array of widgets names,
2156
- // or a space/comma separated list of widget names
2157
- name = ( $.isArray( name ) ? name.join( ',' ) : name || '' ).toLowerCase().split( /[\s,]+/ );
2158
- }
2159
- len = name.length;
2160
- for ( index = 0; index < len; index++ ) {
2161
- widget = ts.getWidgetById( name[ index ] );
2162
- indx = $.inArray( name[ index ], c.widgets );
2163
- // don't remove the widget from config.widget if refreshing
2164
- if ( indx >= 0 && refreshing !== true ) {
2165
- c.widgets.splice( indx, 1 );
2166
- }
2167
- if ( widget && widget.remove ) {
2168
- if ( ts.debug(c, 'core') ) {
2169
- console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[ index ] + '" widget' );
2170
- }
2171
- widget.remove( table, c, c.widgetOptions, refreshing );
2172
- c.widgetInit[ name[ index ] ] = false;
2173
- }
2174
- }
2175
- c.$table.triggerHandler( 'widgetRemoveEnd', table );
2176
- },
2177
-
2178
- refreshWidgets : function( table, doAll, dontapply ) {
2179
- table = $( table )[ 0 ]; // see issue #243
2180
- var indx, widget,
2181
- c = table.config,
2182
- curWidgets = c.widgets,
2183
- widgets = ts.widgets,
2184
- len = widgets.length,
2185
- list = [],
2186
- callback = function( table ) {
2187
- $( table ).triggerHandler( 'refreshComplete' );
2188
- };
2189
- // remove widgets not defined in config.widgets, unless doAll is true
2190
- for ( indx = 0; indx < len; indx++ ) {
2191
- widget = widgets[ indx ];
2192
- if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {
2193
- list[ list.length ] = widget.id;
2194
- }
2195
- }
2196
- ts.removeWidget( table, list.join( ',' ), true );
2197
- if ( dontapply !== true ) {
2198
- // call widget init if
2199
- ts.applyWidget( table, doAll || false, callback );
2200
- if ( doAll ) {
2201
- // apply widget format
2202
- ts.applyWidget( table, false, callback );
2203
- }
2204
- } else {
2205
- callback( table );
2206
- }
2207
- },
2208
-
2209
- /*
2210
- ██ ██ ██████ ██ ██ ██ ██████ ██ ██████ ▄█████
2211
- ██ ██ ██ ██ ██ ██ ██ ██ ██▄▄ ▀█▄
2212
- ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀█▄
2213
- ▀████▀ ██ ██ ██████ ██ ██ ██ ██████ █████▀
2214
- */
2215
- benchmark : function( diff ) {
2216
- return ( ' (' + ( new Date().getTime() - diff.getTime() ) + ' ms)' );
2217
- },
2218
- // deprecated ts.log
2219
- log : function() {
2220
- console.log( arguments );
2221
- },
2222
- debug : function(c, name) {
2223
- return c && (
2224
- c.debug === true ||
2225
- typeof c.debug === 'string' && c.debug.indexOf(name) > -1
2226
- );
2227
- },
2228
-
2229
- // $.isEmptyObject from jQuery v1.4
2230
- isEmptyObject : function( obj ) {
2231
- /*jshint forin: false */
2232
- for ( var name in obj ) {
2233
- return false;
2234
- }
2235
- return true;
2236
- },
2237
-
2238
- isValueInArray : function( column, arry ) {
2239
- var indx,
2240
- len = arry && arry.length || 0;
2241
- for ( indx = 0; indx < len; indx++ ) {
2242
- if ( arry[ indx ][ 0 ] === column ) {
2243
- return indx;
2244
- }
2245
- }
2246
- return -1;
2247
- },
2248
-
2249
- formatFloat : function( str, table ) {
2250
- if ( typeof str !== 'string' || str === '' ) { return str; }
2251
- // allow using formatFloat without a table; defaults to US number format
2252
- var num,
2253
- usFormat = table && table.config ? table.config.usNumberFormat !== false :
2254
- typeof table !== 'undefined' ? table : true;
2255
- if ( usFormat ) {
2256
- // US Format - 1,234,567.89 -> 1234567.89
2257
- str = str.replace( ts.regex.comma, '' );
2258
- } else {
2259
- // German Format = 1.234.567,89 -> 1234567.89
2260
- // French Format = 1 234 567,89 -> 1234567.89
2261
- str = str.replace( ts.regex.digitNonUS, '' ).replace( ts.regex.comma, '.' );
2262
- }
2263
- if ( ts.regex.digitNegativeTest.test( str ) ) {
2264
- // make (#) into a negative number -> (10) = -10
2265
- str = str.replace( ts.regex.digitNegativeReplace, '-$1' );
2266
- }
2267
- num = parseFloat( str );
2268
- // return the text instead of zero
2269
- return isNaN( num ) ? $.trim( str ) : num;
2270
- },
2271
-
2272
- isDigit : function( str ) {
2273
- // replace all unwanted chars and match
2274
- return isNaN( str ) ?
2275
- ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, '' ) ) :
2276
- str !== '';
2277
- },
2278
-
2279
- // computeTableHeaderCellIndexes from:
2280
- // http://www.javascripttoolbox.com/lib/table/examples.php
2281
- // http://www.javascripttoolbox.com/temp/table_cellindex.html
2282
- computeColumnIndex : function( $rows, c ) {
2283
- var i, j, k, l, cell, cells, rowIndex, rowSpan, colSpan, firstAvailCol,
2284
- // total columns has been calculated, use it to set the matrixrow
2285
- columns = c && c.columns || 0,
2286
- matrix = [],
2287
- matrixrow = new Array( columns );
2288
- for ( i = 0; i < $rows.length; i++ ) {
2289
- cells = $rows[ i ].cells;
2290
- for ( j = 0; j < cells.length; j++ ) {
2291
- cell = cells[ j ];
2292
- rowIndex = i;
2293
- rowSpan = cell.rowSpan || 1;
2294
- colSpan = cell.colSpan || 1;
2295
- if ( typeof matrix[ rowIndex ] === 'undefined' ) {
2296
- matrix[ rowIndex ] = [];
2297
- }
2298
- // Find first available column in the first row
2299
- for ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {
2300
- if ( typeof matrix[ rowIndex ][ k ] === 'undefined' ) {
2301
- firstAvailCol = k;
2302
- break;
2303
- }
2304
- }
2305
- // jscs:disable disallowEmptyBlocks
2306
- if ( columns && cell.cellIndex === firstAvailCol ) {
2307
- // don't to anything
2308
- } else if ( cell.setAttribute ) {
2309
- // jscs:enable disallowEmptyBlocks
2310
- // add data-column (setAttribute = IE8+)
2311
- cell.setAttribute( 'data-column', firstAvailCol );
2312
- } else {
2313
- // remove once we drop support for IE7 - 1/12/2016
2314
- $( cell ).attr( 'data-column', firstAvailCol );
2315
- }
2316
- for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {
2317
- if ( typeof matrix[ k ] === 'undefined' ) {
2318
- matrix[ k ] = [];
2319
- }
2320
- matrixrow = matrix[ k ];
2321
- for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
2322
- matrixrow[ l ] = 'x';
2323
- }
2324
- }
2325
- }
2326
- }
2327
- ts.checkColumnCount($rows, matrix, matrixrow.length);
2328
- return matrixrow.length;
2329
- },
2330
-
2331
- checkColumnCount : function($rows, matrix, columns) {
2332
- // this DOES NOT report any tbody column issues, except for the math and
2333
- // and column selector widgets
2334
- var i, len,
2335
- valid = true,
2336
- cells = [];
2337
- for ( i = 0; i < matrix.length; i++ ) {
2338
- // some matrix entries are undefined when testing the footer because
2339
- // it is using the rowIndex property
2340
- if ( matrix[i] ) {
2341
- len = matrix[i].length;
2342
- if ( matrix[i].length !== columns ) {
2343
- valid = false;
2344
- break;
2345
- }
2346
- }
2347
- }
2348
- if ( !valid ) {
2349
- $rows.each( function( indx, el ) {
2350
- var cell = el.parentElement.nodeName;
2351
- if ( cells.indexOf( cell ) < 0 ) {
2352
- cells.push( cell );
2353
- }
2354
- });
2355
- console.error(
2356
- 'Invalid or incorrect number of columns in the ' +
2357
- cells.join( ' or ' ) + '; expected ' + columns +
2358
- ', but found ' + len + ' columns'
2359
- );
2360
- }
2361
- },
2362
-
2363
- // automatically add a colgroup with col elements set to a percentage width
2364
- fixColumnWidth : function( table ) {
2365
- table = $( table )[ 0 ];
2366
- var overallWidth, percent, $tbodies, len, index,
2367
- c = table.config,
2368
- $colgroup = c.$table.children( 'colgroup' );
2369
- // remove plugin-added colgroup, in case we need to refresh the widths
2370
- if ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {
2371
- $colgroup.remove();
2372
- }
2373
- if ( c.widthFixed && c.$table.children( 'colgroup' ).length === 0 ) {
2374
- $colgroup = $( '<colgroup class="' + ts.css.colgroup + '">' );
2375
- overallWidth = c.$table.width();
2376
- // only add col for visible columns - fixes #371
2377
- $tbodies = c.$tbodies.find( 'tr:first' ).children( ':visible' );
2378
- len = $tbodies.length;
2379
- for ( index = 0; index < len; index++ ) {
2380
- percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
2381
- $colgroup.append( $( '<col>' ).css( 'width', percent ) );
2382
- }
2383
- c.$table.prepend( $colgroup );
2384
- }
2385
- },
2386
-
2387
- // get sorter, string, empty, etc options for each column from
2388
- // jQuery data, metadata, header option or header class name ('sorter-false')
2389
- // priority = jQuery data > meta > headers option > header class name
2390
- getData : function( header, configHeader, key ) {
2391
- var meta, cl4ss,
2392
- val = '',
2393
- $header = $( header );
2394
- if ( !$header.length ) { return ''; }
2395
- meta = $.metadata ? $header.metadata() : false;
2396
- cl4ss = ' ' + ( $header.attr( 'class' ) || '' );
2397
- if ( typeof $header.data( key ) !== 'undefined' ||
2398
- typeof $header.data( key.toLowerCase() ) !== 'undefined' ) {
2399
- // 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
2400
- // 'data-sort-initial-order' is assigned to 'sortInitialOrder'
2401
- val += $header.data( key ) || $header.data( key.toLowerCase() );
2402
- } else if ( meta && typeof meta[ key ] !== 'undefined' ) {
2403
- val += meta[ key ];
2404
- } else if ( configHeader && typeof configHeader[ key ] !== 'undefined' ) {
2405
- val += configHeader[ key ];
2406
- } else if ( cl4ss !== ' ' && cl4ss.match( ' ' + key + '-' ) ) {
2407
- // include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
2408
- val = cl4ss.match( new RegExp( '\\s' + key + '-([\\w-]+)' ) )[ 1 ] || '';
2409
- }
2410
- return $.trim( val );
2411
- },
2412
-
2413
- getColumnData : function( table, obj, indx, getCell, $headers ) {
2414
- if ( typeof obj !== 'object' || obj === null ) {
2415
- return obj;
2416
- }
2417
- table = $( table )[ 0 ];
2418
- var $header, key,
2419
- c = table.config,
2420
- $cells = ( $headers || c.$headers ),
2421
- // c.$headerIndexed is not defined initially
2422
- $cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||
2423
- $cells.find( '[data-column="' + indx + '"]:last' );
2424
- if ( typeof obj[ indx ] !== 'undefined' ) {
2425
- return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];
2426
- }
2427
- for ( key in obj ) {
2428
- if ( typeof key === 'string' ) {
2429
- $header = $cell
2430
- // header cell with class/id
2431
- .filter( key )
2432
- // find elements within the header cell with cell/id
2433
- .add( $cell.find( key ) );
2434
- if ( $header.length ) {
2435
- return obj[ key ];
2436
- }
2437
- }
2438
- }
2439
- return;
2440
- },
2441
-
2442
- // *** Process table ***
2443
- // add processing indicator
2444
- isProcessing : function( $table, toggle, $headers ) {
2445
- $table = $( $table );
2446
- var c = $table[ 0 ].config,
2447
- // default to all headers
2448
- $header = $headers || $table.find( '.' + ts.css.header );
2449
- if ( toggle ) {
2450
- // don't use sortList if custom $headers used
2451
- if ( typeof $headers !== 'undefined' && c.sortList.length > 0 ) {
2452
- // get headers from the sortList
2453
- $header = $header.filter( function() {
2454
- // get data-column from attr to keep compatibility with jQuery 1.2.6
2455
- return this.sortDisabled ?
2456
- false :
2457
- ts.isValueInArray( parseFloat( $( this ).attr( 'data-column' ) ), c.sortList ) >= 0;
2458
- });
2459
- }
2460
- $table.add( $header ).addClass( ts.css.processing + ' ' + c.cssProcessing );
2461
- } else {
2462
- $table.add( $header ).removeClass( ts.css.processing + ' ' + c.cssProcessing );
2463
- }
2464
- },
2465
-
2466
- // detach tbody but save the position
2467
- // don't use tbody because there are portions that look for a tbody index (updateCell)
2468
- processTbody : function( table, $tb, getIt ) {
2469
- table = $( table )[ 0 ];
2470
- if ( getIt ) {
2471
- table.isProcessing = true;
2472
- $tb.before( '<colgroup class="tablesorter-savemyplace"/>' );
2473
- return $.fn.detach ? $tb.detach() : $tb.remove();
2474
- }
2475
- var holdr = $( table ).find( 'colgroup.tablesorter-savemyplace' );
2476
- $tb.insertAfter( holdr );
2477
- holdr.remove();
2478
- table.isProcessing = false;
2479
- },
2480
-
2481
- clearTableBody : function( table ) {
2482
- $( table )[ 0 ].config.$tbodies.children().detach();
2483
- },
2484
-
2485
- // used when replacing accented characters during sorting
2486
- characterEquivalents : {
2487
- 'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
2488
- 'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
2489
- 'c' : '\u00e7\u0107\u010d', // çćč
2490
- 'C' : '\u00c7\u0106\u010c', // ÇĆČ
2491
- 'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
2492
- 'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
2493
- 'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
2494
- 'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
2495
- 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
2496
- 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
2497
- 'ss': '\u00df', // ß (s sharp)
2498
- 'SS': '\u1e9e', // ẞ (Capital sharp s)
2499
- 'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
2500
- 'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
2501
- },
2502
-
2503
- replaceAccents : function( str ) {
2504
- var chr,
2505
- acc = '[',
2506
- eq = ts.characterEquivalents;
2507
- if ( !ts.characterRegex ) {
2508
- ts.characterRegexArray = {};
2509
- for ( chr in eq ) {
2510
- if ( typeof chr === 'string' ) {
2511
- acc += eq[ chr ];
2512
- ts.characterRegexArray[ chr ] = new RegExp( '[' + eq[ chr ] + ']', 'g' );
2513
- }
2514
- }
2515
- ts.characterRegex = new RegExp( acc + ']' );
2516
- }
2517
- if ( ts.characterRegex.test( str ) ) {
2518
- for ( chr in eq ) {
2519
- if ( typeof chr === 'string' ) {
2520
- str = str.replace( ts.characterRegexArray[ chr ], chr );
2521
- }
2522
- }
2523
- }
2524
- return str;
2525
- },
2526
-
2527
- validateOptions : function( c ) {
2528
- var setting, setting2, typ, timer,
2529
- // ignore options containing an array
2530
- ignore = 'headers sortForce sortList sortAppend widgets'.split( ' ' ),
2531
- orig = c.originalSettings;
2532
- if ( orig ) {
2533
- if ( ts.debug(c, 'core') ) {
2534
- timer = new Date();
2535
- }
2536
- for ( setting in orig ) {
2537
- typ = typeof ts.defaults[setting];
2538
- if ( typ === 'undefined' ) {
2539
- console.warn( 'Tablesorter Warning! "table.config.' + setting + '" option not recognized' );
2540
- } else if ( typ === 'object' ) {
2541
- for ( setting2 in orig[setting] ) {
2542
- typ = ts.defaults[setting] && typeof ts.defaults[setting][setting2];
2543
- if ( $.inArray( setting, ignore ) < 0 && typ === 'undefined' ) {
2544
- console.warn( 'Tablesorter Warning! "table.config.' + setting + '.' + setting2 + '" option not recognized' );
2545
- }
2546
- }
2547
- }
2548
- }
2549
- if ( ts.debug(c, 'core') ) {
2550
- console.log( 'validate options time:' + ts.benchmark( timer ) );
2551
- }
2552
- }
2553
- },
2554
-
2555
- // restore headers
2556
- restoreHeaders : function( table ) {
2557
- var index, $cell,
2558
- c = $( table )[ 0 ].config,
2559
- $headers = c.$table.find( c.selectorHeaders ),
2560
- len = $headers.length;
2561
- // don't use c.$headers here in case header cells were swapped
2562
- for ( index = 0; index < len; index++ ) {
2563
- $cell = $headers.eq( index );
2564
- // only restore header cells if it is wrapped
2565
- // because this is also used by the updateAll method
2566
- if ( $cell.find( '.' + ts.css.headerIn ).length ) {
2567
- $cell.html( c.headerContent[ index ] );
2568
- }
2569
- }
2570
- },
2571
-
2572
- destroy : function( table, removeClasses, callback ) {
2573
- table = $( table )[ 0 ];
2574
- if ( !table.hasInitialized ) { return; }
2575
- // remove all widgets
2576
- ts.removeWidget( table, true, false );
2577
- var events,
2578
- $t = $( table ),
2579
- c = table.config,
2580
- $h = $t.find( 'thead:first' ),
2581
- $r = $h.find( 'tr.' + ts.css.headerRow ).removeClass( ts.css.headerRow + ' ' + c.cssHeaderRow ),
2582
- $f = $t.find( 'tfoot:first > tr' ).children( 'th, td' );
2583
- if ( removeClasses === false && $.inArray( 'uitheme', c.widgets ) >= 0 ) {
2584
- // reapply uitheme classes, in case we want to maintain appearance
2585
- $t.triggerHandler( 'applyWidgetId', [ 'uitheme' ] );
2586
- $t.triggerHandler( 'applyWidgetId', [ 'zebra' ] );
2587
- }
2588
- // remove widget added rows, just in case
2589
- $h.find( 'tr' ).not( $r ).remove();
2590
- // disable tablesorter - not using .unbind( namespace ) because namespacing was
2591
- // added in jQuery v1.4.3 - see http://api.jquery.com/event.namespace/
2592
- events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
2593
- 'appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave ' +
2594
- 'keypress sortBegin sortEnd resetToLoadState '.split( ' ' )
2595
- .join( c.namespace + ' ' );
2596
- $t
2597
- .removeData( 'tablesorter' )
2598
- .unbind( events.replace( ts.regex.spaces, ' ' ) );
2599
- c.$headers
2600
- .add( $f )
2601
- .removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( ' ' ) )
2602
- .removeAttr( 'data-column' )
2603
- .removeAttr( 'aria-label' )
2604
- .attr( 'aria-disabled', 'true' );
2605
- $r
2606
- .find( c.selectorSort )
2607
- .unbind( ( 'mousedown mouseup keypress '.split( ' ' ).join( c.namespace + ' ' ) ).replace( ts.regex.spaces, ' ' ) );
2608
- ts.restoreHeaders( table );
2609
- $t.toggleClass( ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false );
2610
- $t.removeClass(c.namespace.slice(1));
2611
- // clear flag in case the plugin is initialized again
2612
- table.hasInitialized = false;
2613
- delete table.config.cache;
2614
- if ( typeof callback === 'function' ) {
2615
- callback( table );
2616
- }
2617
- if ( ts.debug(c, 'core') ) {
2618
- console.log( 'tablesorter has been removed' );
2619
- }
2620
- }
2621
-
2622
- };
2623
-
2624
- $.fn.tablesorter = function( settings ) {
2625
- return this.each( function() {
2626
- var table = this,
2627
- // merge & extend config options
2628
- c = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );
2629
- // save initial settings
2630
- c.originalSettings = settings;
2631
- // create a table from data (build table widget)
2632
- if ( !table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE' ) {
2633
- // return the table (in case the original target is the table's container)
2634
- ts.buildTable( table, c );
2635
- } else {
2636
- ts.setup( table, c );
2637
- }
2638
- });
2639
- };
2640
-
2641
- // set up debug logs
2642
- if ( !( window.console && window.console.log ) ) {
2643
- // access $.tablesorter.logs for browsers that don't have a console...
2644
- ts.logs = [];
2645
- /*jshint -W020 */
2646
- console = {};
2647
- console.log = console.warn = console.error = console.table = function() {
2648
- var arg = arguments.length > 1 ? arguments : arguments[0];
2649
- ts.logs[ ts.logs.length ] = { date: Date.now(), log: arg };
2650
- };
2651
- }
2652
-
2653
- // add default parsers
2654
- ts.addParser({
2655
- id : 'no-parser',
2656
- is : function() {
2657
- return false;
2658
- },
2659
- format : function() {
2660
- return '';
2661
- },
2662
- type : 'text'
2663
- });
2664
-
2665
- ts.addParser({
2666
- id : 'text',
2667
- is : function() {
2668
- return true;
2669
- },
2670
- format : function( str, table ) {
2671
- var c = table.config;
2672
- if ( str ) {
2673
- str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );
2674
- str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;
2675
- }
2676
- return str;
2677
- },
2678
- type : 'text'
2679
- });
2680
-
2681
- ts.regex.nondigit = /[^\w,. \-()]/g;
2682
- ts.addParser({
2683
- id : 'digit',
2684
- is : function( str ) {
2685
- return ts.isDigit( str );
2686
- },
2687
- format : function( str, table ) {
2688
- var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
2689
- return str && typeof num === 'number' ? num :
2690
- str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
2691
- },
2692
- type : 'numeric'
2693
- });
2694
-
2695
- ts.regex.currencyReplace = /[+\-,. ]/g;
2696
- ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
2697
- ts.addParser({
2698
- id : 'currency',
2699
- is : function( str ) {
2700
- str = ( str || '' ).replace( ts.regex.currencyReplace, '' );
2701
- // test for £$€¤¥¢
2702
- return ts.regex.currencyTest.test( str );
2703
- },
2704
- format : function( str, table ) {
2705
- var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
2706
- return str && typeof num === 'number' ? num :
2707
- str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
2708
- },
2709
- type : 'numeric'
2710
- });
2711
-
2712
- // too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
2713
- // now, this regex can be updated before initialization
2714
- ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
2715
- ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\/(www\.)?/;
2716
- ts.addParser({
2717
- id : 'url',
2718
- is : function( str ) {
2719
- return ts.regex.urlProtocolTest.test( str );
2720
- },
2721
- format : function( str ) {
2722
- return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, '' ) ) : str;
2723
- },
2724
- type : 'text'
2725
- });
2726
-
2727
- ts.regex.dash = /-/g;
2728
- ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
2729
- ts.addParser({
2730
- id : 'isoDate',
2731
- is : function( str ) {
2732
- return ts.regex.isoDate.test( str );
2733
- },
2734
- format : function( str ) {
2735
- var date = str ? new Date( str.replace( ts.regex.dash, '/' ) ) : str;
2736
- return date instanceof Date && isFinite( date ) ? date.getTime() : str;
2737
- },
2738
- type : 'numeric'
2739
- });
2740
-
2741
- ts.regex.percent = /%/g;
2742
- ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
2743
- ts.addParser({
2744
- id : 'percent',
2745
- is : function( str ) {
2746
- return ts.regex.percentTest.test( str ) && str.length < 15;
2747
- },
2748
- format : function( str, table ) {
2749
- return str ? ts.formatFloat( str.replace( ts.regex.percent, '' ), table ) : str;
2750
- },
2751
- type : 'numeric'
2752
- });
2753
-
2754
- // added image parser to core v2.17.9
2755
- ts.addParser({
2756
- id : 'image',
2757
- is : function( str, table, node, $node ) {
2758
- return $node.find( 'img' ).length > 0;
2759
- },
2760
- format : function( str, table, cell ) {
2761
- return $( cell ).find( 'img' ).attr( table.config.imgAttr || 'alt' ) || str;
2762
- },
2763
- parsed : true, // filter widget flag
2764
- type : 'text'
2765
- });
2766
-
2767
- ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
2768
- ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
2769
- ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
2770
- ts.addParser({
2771
- id : 'usLongDate',
2772
- is : function( str ) {
2773
- // two digit years are not allowed cross-browser
2774
- // Jan 01, 2013 12:34:56 PM or 01 Jan 2013
2775
- return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );
2776
- },
2777
- format : function( str ) {
2778
- var date = str ? new Date( str.replace( ts.regex.dateReplace, '$1 $2' ) ) : str;
2779
- return date instanceof Date && isFinite( date ) ? date.getTime() : str;
2780
- },
2781
- type : 'numeric'
2782
- });
2783
-
2784
- // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
2785
- ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
2786
- // escaped "-" because JSHint in Firefox was showing it as an error
2787
- ts.regex.shortDateReplace = /[\-.,]/g;
2788
- // XXY covers MDY & DMY formats
2789
- ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
2790
- ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
2791
- ts.convertFormat = function( dateString, format ) {
2792
- dateString = ( dateString || '' )
2793
- .replace( ts.regex.spaces, ' ' )
2794
- .replace( ts.regex.shortDateReplace, '/' );
2795
- if ( format === 'mmddyyyy' ) {
2796
- dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$1/$2' );
2797
- } else if ( format === 'ddmmyyyy' ) {
2798
- dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$2/$1' );
2799
- } else if ( format === 'yyyymmdd' ) {
2800
- dateString = dateString.replace( ts.regex.shortDateYMD, '$1/$2/$3' );
2801
- }
2802
- var date = new Date( dateString );
2803
- return date instanceof Date && isFinite( date ) ? date.getTime() : '';
2804
- };
2805
-
2806
- ts.addParser({
2807
- id : 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
2808
- is : function( str ) {
2809
- str = ( str || '' ).replace( ts.regex.spaces, ' ' ).replace( ts.regex.shortDateReplace, '/' );
2810
- return ts.regex.shortDateTest.test( str );
2811
- },
2812
- format : function( str, table, cell, cellIndex ) {
2813
- if ( str ) {
2814
- var c = table.config,
2815
- $header = c.$headerIndexed[ cellIndex ],
2816
- format = $header.length && $header.data( 'dateFormat' ) ||
2817
- ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat' ) ||
2818
- c.dateFormat;
2819
- // save format because getData can be slow...
2820
- if ( $header.length ) {
2821
- $header.data( 'dateFormat', format );
2822
- }
2823
- return ts.convertFormat( str, format ) || str;
2824
- }
2825
- return str;
2826
- },
2827
- type : 'numeric'
2828
- });
2829
-
2830
- // match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
2831
- ts.regex.timeTest = /^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i;
2832
- ts.regex.timeMatch = /(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;
2833
- ts.addParser({
2834
- id : 'time',
2835
- is : function( str ) {
2836
- return ts.regex.timeTest.test( str );
2837
- },
2838
- format : function( str ) {
2839
- // isolate time... ignore month, day and year
2840
- var temp,
2841
- timePart = ( str || '' ).match( ts.regex.timeMatch ),
2842
- orig = new Date( str ),
2843
- // no time component? default to 00:00 by leaving it out, but only if str is defined
2844
- time = str && ( timePart !== null ? timePart[ 0 ] : '00:00 AM' ),
2845
- date = time ? new Date( '2000/01/01 ' + time.replace( ts.regex.dateReplace, '$1 $2' ) ) : time;
2846
- if ( date instanceof Date && isFinite( date ) ) {
2847
- temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;
2848
- // if original string was a valid date, add it to the decimal so the column sorts in some kind of order
2849
- // luckily new Date() ignores the decimals
2850
- return temp ? parseFloat( date.getTime() + '.' + orig.getTime() ) : date.getTime();
2851
- }
2852
- return str;
2853
- },
2854
- type : 'numeric'
2855
- });
2856
-
2857
- ts.addParser({
2858
- id : 'metadata',
2859
- is : function() {
2860
- return false;
2861
- },
2862
- format : function( str, table, cell ) {
2863
- var c = table.config,
2864
- p = ( !c.parserMetadataName ) ? 'sortValue' : c.parserMetadataName;
2865
- return $( cell ).metadata()[ p ];
2866
- },
2867
- type : 'numeric'
2868
- });
2869
-
2870
- /*
2871
- ██████ ██████ █████▄ █████▄ ▄████▄
2872
- ▄█▀ ██▄▄ ██▄▄██ ██▄▄██ ██▄▄██
2873
- ▄█▀ ██▀▀ ██▀▀██ ██▀▀█ ██▀▀██
2874
- ██████ ██████ █████▀ ██ ██ ██ ██
2875
- */
2876
- // add default widgets
2877
- ts.addWidget({
2878
- id : 'zebra',
2879
- priority : 90,
2880
- format : function( table, c, wo ) {
2881
- var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,
2882
- child = new RegExp( c.cssChildRow, 'i' ),
2883
- $tbodies = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
2884
- for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
2885
- // loop through the visible rows
2886
- count = 0;
2887
- $visibleRows = $tbodies.eq( tbodyIndex ).children( 'tr:visible' ).not( c.selectorRemove );
2888
- len = $visibleRows.length;
2889
- for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
2890
- $row = $visibleRows.eq( rowIndex );
2891
- // style child rows the same way the parent row was styled
2892
- if ( !child.test( $row[ 0 ].className ) ) { count++; }
2893
- isEven = ( count % 2 === 0 );
2894
- $row
2895
- .removeClass( wo.zebra[ isEven ? 1 : 0 ] )
2896
- .addClass( wo.zebra[ isEven ? 0 : 1 ] );
2897
- }
2898
- }
2899
- },
2900
- remove : function( table, c, wo, refreshing ) {
2901
- if ( refreshing ) { return; }
2902
- var tbodyIndex, $tbody,
2903
- $tbodies = c.$tbodies,
2904
- toRemove = ( wo.zebra || [ 'even', 'odd' ] ).join( ' ' );
2905
- for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
2906
- $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
2907
- $tbody.children().removeClass( toRemove );
2908
- ts.processTbody( table, $tbody, false ); // restore tbody
2909
- }
2910
- }
2911
- });
2912
-
2913
- })( jQuery );
2914
- return jQuery.tablesorter;}));
 
 
1
+ (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery){
2
+ /*! TableSorter (FORK) v2.31.1 *//*
3
+ * Client-side table sorting with ease!
4
+ * @requires jQuery v1.2.6+
5
+ *
6
+ * Copyright (c) 2007 Christian Bach
7
+ * fork maintained by Rob Garrison
8
+ *
9
+ * Examples and original docs at: http://tablesorter.com
10
+ * Dual licensed under the MIT and GPL licenses:
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ * http://www.gnu.org/licenses/gpl.html
13
+ *
14
+ * @type jQuery
15
+ * @name tablesorter (FORK)
16
+ * @cat Plugins/Tablesorter
17
+ * @author Christian Bach - christian.bach@polyester.se
18
+ * @contributor Rob Garrison - https://github.com/Mottie/tablesorter
19
+ * @docs (fork) - https://mottie.github.io/tablesorter/docs/
20
+ */
21
+ /*jshint browser:true, jquery:true, unused:false, expr: true */
22
+ ;( function( $ ) {
23
+ 'use strict';
24
+ var ts = $.tablesorter = {
25
+
26
+ version : '2.31.1',
27
+
28
+ parsers : [],
29
+ widgets : [],
30
+ defaults : {
31
+
32
+ // *** appearance
33
+ theme : 'default', // adds tablesorter-{theme} to the table for styling
34
+ widthFixed : false, // adds colgroup to fix widths of columns
35
+ showProcessing : false, // show an indeterminate timer icon in the header when the table is sorted or filtered.
36
+
37
+ headerTemplate : '{content}',// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcon
38
+ onRenderTemplate : null, // function( index, template ) { return template; }, // template is a string
39
+ onRenderHeader : null, // function( index ) {}, // nothing to return
40
+
41
+ // *** functionality
42
+ cancelSelection : true, // prevent text selection in the header
43
+ tabIndex : true, // add tabindex to header for keyboard accessibility
44
+ dateFormat : 'mmddyyyy', // other options: 'ddmmyyy' or 'yyyymmdd'
45
+ sortMultiSortKey : 'shiftKey', // key used to select additional columns
46
+ sortResetKey : 'ctrlKey', // key used to remove sorting on a column
47
+ usNumberFormat : true, // false for German '1.234.567,89' or French '1 234 567,89'
48
+ delayInit : false, // if false, the parsed table contents will not update until the first sort
49
+ serverSideSorting: false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
50
+ resort : true, // default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
51
+
52
+ // *** sort options
53
+ headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
54
+ ignoreCase : true, // ignore case while sorting
55
+ sortForce : null, // column(s) first sorted; always applied
56
+ sortList : [], // Initial sort order; applied initially; updated when manually sorted
57
+ sortAppend : null, // column(s) sorted last; always applied
58
+ sortStable : false, // when sorting two rows with exactly the same content, the original sort order is maintained
59
+
60
+ sortInitialOrder : 'asc', // sort direction on first click
61
+ sortLocaleCompare: false, // replace equivalent character (accented characters)
62
+ sortReset : false, // third click on the header will reset column to default - unsorted
63
+ sortRestart : false, // restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
64
+
65
+ emptyTo : 'bottom', // sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
66
+ stringTo : 'max', // sort strings in numerical column as max, min, top, bottom, zero
67
+ duplicateSpan : true, // colspan cells in the tbody will have duplicated content in the cache for each spanned column
68
+ textExtraction : 'basic', // text extraction method/function - function( node, table, cellIndex ) {}
69
+ textAttribute : 'data-text',// data-attribute that contains alternate cell text (used in default textExtraction function)
70
+ textSorter : null, // choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
71
+ numberSorter : null, // choose overall numeric sorter function( a, b, direction, maxColumnValue )
72
+
73
+ // *** widget options
74
+ initWidgets : true, // apply widgets on tablesorter initialization
75
+ widgetClass : 'widget-{name}', // table class name template to match to include a widget
76
+ widgets : [], // method to add widgets, e.g. widgets: ['zebra']
77
+ widgetOptions : {
78
+ zebra : [ 'even', 'odd' ] // zebra widget alternating row class names
79
+ },
80
+
81
+ // *** callbacks
82
+ initialized : null, // function( table ) {},
83
+
84
+ // *** extra css class names
85
+ tableClass : '',
86
+ cssAsc : '',
87
+ cssDesc : '',
88
+ cssNone : '',
89
+ cssHeader : '',
90
+ cssHeaderRow : '',
91
+ cssProcessing : '', // processing icon applied to header during sort/filter
92
+
93
+ cssChildRow : 'tablesorter-childRow', // class name indiciating that a row is to be attached to its parent
94
+ cssInfoBlock : 'tablesorter-infoOnly', // don't sort tbody with this class name (only one class name allowed here!)
95
+ cssNoSort : 'tablesorter-noSort', // class name added to element inside header; clicking on it won't cause a sort
96
+ cssIgnoreRow : 'tablesorter-ignoreRow',// header row to ignore; cells within this row will not be added to c.$headers
97
+
98
+ cssIcon : 'tablesorter-icon', // if this class does not exist, the {icon} will not be added from the headerTemplate
99
+ cssIconNone : '', // class name added to the icon when there is no column sort
100
+ cssIconAsc : '', // class name added to the icon when the column has an ascending sort
101
+ cssIconDesc : '', // class name added to the icon when the column has a descending sort
102
+ cssIconDisabled : '', // class name added to the icon when the column has a disabled sort
103
+
104
+ // *** events
105
+ pointerClick : 'click',
106
+ pointerDown : 'mousedown',
107
+ pointerUp : 'mouseup',
108
+
109
+ // *** selectors
110
+ selectorHeaders : '> thead th, > thead td',
111
+ selectorSort : 'th, td', // jQuery selector of content within selectorHeaders that is clickable to trigger a sort
112
+ selectorRemove : '.remove-me',
113
+
114
+ // *** advanced
115
+ debug : false,
116
+
117
+ // *** Internal variables
118
+ headerList: [],
119
+ empties: {},
120
+ strings: {},
121
+ parsers: [],
122
+
123
+ // *** parser options for validator; values must be falsy!
124
+ globalize: 0,
125
+ imgAttr: 0
126
+
127
+ // removed: widgetZebra: { css: ['even', 'odd'] }
128
+
129
+ },
130
+
131
+ // internal css classes - these will ALWAYS be added to
132
+ // the table and MUST only contain one class name - fixes #381
133
+ css : {
134
+ table : 'tablesorter',
135
+ cssHasChild: 'tablesorter-hasChildRow',
136
+ childRow : 'tablesorter-childRow',
137
+ colgroup : 'tablesorter-colgroup',
138
+ header : 'tablesorter-header',
139
+ headerRow : 'tablesorter-headerRow',
140
+ headerIn : 'tablesorter-header-inner',
141
+ icon : 'tablesorter-icon',
142
+ processing : 'tablesorter-processing',
143
+ sortAsc : 'tablesorter-headerAsc',
144
+ sortDesc : 'tablesorter-headerDesc',
145
+ sortNone : 'tablesorter-headerUnSorted'
146
+ },
147
+
148
+ // labels applied to sortable headers for accessibility (aria) support
149
+ language : {
150
+ sortAsc : 'Ascending sort applied, ',
151
+ sortDesc : 'Descending sort applied, ',
152
+ sortNone : 'No sort applied, ',
153
+ sortDisabled : 'sorting is disabled',
154
+ nextAsc : 'activate to apply an ascending sort',
155
+ nextDesc : 'activate to apply a descending sort',
156
+ nextNone : 'activate to remove the sort'
157
+ },
158
+
159
+ regex : {
160
+ templateContent : /\{content\}/g,
161
+ templateIcon : /\{icon\}/g,
162
+ templateName : /\{name\}/i,
163
+ spaces : /\s+/g,
164
+ nonWord : /\W/g,
165
+ formElements : /(input|select|button|textarea)/i,
166
+
167
+ // *** sort functions ***
168
+ // regex used in natural sort
169
+ // chunk/tokenize numbers & letters
170
+ chunk : /(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
171
+ // replace chunks @ ends
172
+ chunks : /(^\\0|\\0$)/,
173
+ hex : /^0x[0-9a-f]+$/i,
174
+
175
+ // *** formatFloat ***
176
+ comma : /,/g,
177
+ digitNonUS : /[\s|\.]/g,
178
+ digitNegativeTest : /^\s*\([.\d]+\)/,
179
+ digitNegativeReplace : /^\s*\(([.\d]+)\)/,
180
+
181
+ // *** isDigit ***
182
+ digitTest : /^[\-+(]?\d+[)]?$/,
183
+ digitReplace : /[,.'"\s]/g
184
+
185
+ },
186
+
187
+ // digit sort, text location
188
+ string : {
189
+ max : 1,
190
+ min : -1,
191
+ emptymin : 1,
192
+ emptymax : -1,
193
+ zero : 0,
194
+ none : 0,
195
+ 'null' : 0,
196
+ top : true,
197
+ bottom : false
198
+ },
199
+
200
+ keyCodes : {
201
+ enter : 13
202
+ },
203
+
204
+ // placeholder date parser data (globalize)
205
+ dates : {},
206
+
207
+ // These methods can be applied on table.config instance
208
+ instanceMethods : {},
209
+
210
+ /*
211
+ ▄█████ ██████ ██████ ██ ██ █████▄
212
+ ▀█▄ ██▄▄ ██ ██ ██ ██▄▄██
213
+ ▀█▄ ██▀▀ ██ ██ ██ ██▀▀▀
214
+ █████▀ ██████ ██ ▀████▀ ██
215
+ */
216
+
217
+ setup : function( table, c ) {
218
+ // if no thead or tbody, or tablesorter is already present, quit
219
+ if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
220
+ if ( ts.debug(c, 'core') ) {
221
+ if ( table.hasInitialized ) {
222
+ console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
223
+ } else {
224
+ console.error( 'Stopping initialization! No table, thead or tbody', table );
225
+ }
226
+ }
227
+ return;
228
+ }
229
+
230
+ var tmp = '',
231
+ $table = $( table ),
232
+ meta = $.metadata;
233
+ // initialization flag
234
+ table.hasInitialized = false;
235
+ // table is being processed flag
236
+ table.isProcessing = true;
237
+ // make sure to store the config object
238
+ table.config = c;
239
+ // save the settings where they read
240
+ $.data( table, 'tablesorter', c );
241
+ if ( ts.debug(c, 'core') ) {
242
+ console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter v' + ts.version );
243
+ $.data( table, 'startoveralltimer', new Date() );
244
+ }
245
+
246
+ // removing this in version 3 (only supports jQuery 1.7+)
247
+ c.supportsDataObject = ( function( version ) {
248
+ version[ 0 ] = parseInt( version[ 0 ], 10 );
249
+ return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
250
+ })( $.fn.jquery.split( '.' ) );
251
+ // ensure case insensitivity
252
+ c.emptyTo = c.emptyTo.toLowerCase();
253
+ c.stringTo = c.stringTo.toLowerCase();
254
+ c.last = { sortList : [], clickedIndex : -1 };
255
+ // add table theme class only if there isn't already one there
256
+ if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
257
+ tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
258
+ }
259
+
260
+ // give the table a unique id, which will be used in namespace binding
261
+ if ( !c.namespace ) {
262
+ c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
263
+ } else {
264
+ // make sure namespace starts with a period & doesn't have weird characters
265
+ c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
266
+ }
267
+
268
+ c.table = table;
269
+ c.$table = $table
270
+ // add namespace to table to allow bindings on extra elements to target
271
+ // the parent table (e.g. parser-input-select)
272
+ .addClass( ts.css.table + ' ' + c.tableClass + tmp + ' ' + c.namespace.slice(1) )
273
+ .attr( 'role', 'grid' );
274
+ c.$headers = $table.find( c.selectorHeaders );
275
+
276
+ c.$table.children().children( 'tr' ).attr( 'role', 'row' );
277
+ c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
278
+ 'aria-live' : 'polite',
279
+ 'aria-relevant' : 'all'
280
+ });
281
+ if ( c.$table.children( 'caption' ).length ) {
282
+ tmp = c.$table.children( 'caption' )[ 0 ];
283
+ if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
284
+ c.$table.attr( 'aria-labelledby', tmp.id );
285
+ }
286
+ c.widgetInit = {}; // keep a list of initialized widgets
287
+ // change textExtraction via data-attribute
288
+ c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
289
+ // build headers
290
+ ts.buildHeaders( c );
291
+ // fixate columns if the users supplies the fixedWidth option
292
+ // do this after theme has been applied
293
+ ts.fixColumnWidth( table );
294
+ // add widgets from class name
295
+ ts.addWidgetFromClass( table );
296
+ // add widget options before parsing (e.g. grouping widget has parser settings)
297
+ ts.applyWidgetOptions( table );
298
+ // try to auto detect column type, and store in tables config
299
+ ts.setupParsers( c );
300
+ // start total row count at zero
301
+ c.totalRows = 0;
302
+ // only validate options while debugging. See #1528
303
+ if (c.debug) {
304
+ ts.validateOptions( c );
305
+ }
306
+ // build the cache for the tbody cells
307
+ // delayInit will delay building the cache until the user starts a sort
308
+ if ( !c.delayInit ) { ts.buildCache( c ); }
309
+ // bind all header events and methods
310
+ ts.bindEvents( table, c.$headers, true );
311
+ ts.bindMethods( c );
312
+ // get sort list from jQuery data or metadata
313
+ // in jQuery < 1.4, an error occurs when calling $table.data()
314
+ if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
315
+ c.sortList = $table.data().sortlist;
316
+ } else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
317
+ c.sortList = $table.metadata().sortlist;
318
+ }
319
+ // apply widget init code
320
+ ts.applyWidget( table, true );
321
+ // if user has supplied a sort list to constructor
322
+ if ( c.sortList.length > 0 ) {
323
+ // save sortList before any sortAppend is added
324
+ c.last.sortList = c.sortList;
325
+ ts.sortOn( c, c.sortList, {}, !c.initWidgets );
326
+ } else {
327
+ ts.setHeadersCss( c );
328
+ if ( c.initWidgets ) {
329
+ // apply widget format
330
+ ts.applyWidget( table, false );
331
+ }
332
+ }
333
+
334
+ // show processesing icon
335
+ if ( c.showProcessing ) {
336
+ $table
337
+ .unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
338
+ .bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
339
+ clearTimeout( c.timerProcessing );
340
+ ts.isProcessing( table );
341
+ if ( e.type === 'sortBegin' ) {
342
+ c.timerProcessing = setTimeout( function() {
343
+ ts.isProcessing( table, true );
344
+ }, 500 );
345
+ }
346
+ });
347
+ }
348
+
349
+ // initialized
350
+ table.hasInitialized = true;
351
+ table.isProcessing = false;
352
+ if ( ts.debug(c, 'core') ) {
353
+ console.log( 'Overall initialization time:' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
354
+ if ( ts.debug(c, 'core') && console.groupEnd ) { console.groupEnd(); }
355
+ }
356
+ $table.triggerHandler( 'tablesorter-initialized', table );
357
+ if ( typeof c.initialized === 'function' ) {
358
+ c.initialized( table );
359
+ }
360
+ },
361
+
362
+ bindMethods : function( c ) {
363
+ var $table = c.$table,
364
+ namespace = c.namespace,
365
+ events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
366
+ 'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
367
+ 'mouseleave ' ).split( ' ' )
368
+ .join( namespace + ' ' );
369
+ // apply easy methods that trigger bound events
370
+ $table
371
+ .unbind( events.replace( ts.regex.spaces, ' ' ) )
372
+ .bind( 'sortReset' + namespace, function( e, callback ) {
373
+ e.stopPropagation();
374
+ // using this.config to ensure functions are getting a non-cached version of the config
375
+ ts.sortReset( this.config, function( table ) {
376
+ if (table.isApplyingWidgets) {
377
+ // multiple triggers in a row... filterReset, then sortReset - see #1361
378
+ // wait to update widgets
379
+ setTimeout( function() {
380
+ ts.applyWidget( table, '', callback );
381
+ }, 100 );
382
+ } else {
383
+ ts.applyWidget( table, '', callback );
384
+ }
385
+ });
386
+ })
387
+ .bind( 'updateAll' + namespace, function( e, resort, callback ) {
388
+ e.stopPropagation();
389
+ ts.updateAll( this.config, resort, callback );
390
+ })
391
+ .bind( 'update' + namespace + ' updateRows' + namespace, function( e, resort, callback ) {
392
+ e.stopPropagation();
393
+ ts.update( this.config, resort, callback );
394
+ })
395
+ .bind( 'updateHeaders' + namespace, function( e, callback ) {
396
+ e.stopPropagation();
397
+ ts.updateHeaders( this.config, callback );
398
+ })
399
+ .bind( 'updateCell' + namespace, function( e, cell, resort, callback ) {
400
+ e.stopPropagation();
401
+ ts.updateCell( this.config, cell, resort, callback );
402
+ })
403
+ .bind( 'addRows' + namespace, function( e, $row, resort, callback ) {
404
+ e.stopPropagation();
405
+ ts.addRows( this.config, $row, resort, callback );
406
+ })
407
+ .bind( 'updateComplete' + namespace, function() {
408
+ this.isUpdating = false;
409
+ })
410
+ .bind( 'sorton' + namespace, function( e, list, callback, init ) {
411
+ e.stopPropagation();
412
+ ts.sortOn( this.config, list, callback, init );
413
+ })
414
+ .bind( 'appendCache' + namespace, function( e, callback, init ) {
415
+ e.stopPropagation();
416
+ ts.appendCache( this.config, init );
417
+ if ( $.isFunction( callback ) ) {
418
+ callback( this );
419
+ }
420
+ })
421
+ // $tbodies variable is used by the tbody sorting widget
422
+ .bind( 'updateCache' + namespace, function( e, callback, $tbodies ) {
423
+ e.stopPropagation();
424
+ ts.updateCache( this.config, callback, $tbodies );
425
+ })
426
+ .bind( 'applyWidgetId' + namespace, function( e, id ) {
427
+ e.stopPropagation();
428
+ ts.applyWidgetId( this, id );
429
+ })
430
+ .bind( 'applyWidgets' + namespace, function( e, callback ) {
431
+ e.stopPropagation();
432
+ // apply widgets (false = not initializing)
433
+ ts.applyWidget( this, false, callback );
434
+ })
435
+ .bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
436
+ e.stopPropagation();
437
+ ts.refreshWidgets( this, all, dontapply );
438
+ })
439
+ .bind( 'removeWidget' + namespace, function( e, name, refreshing ) {
440
+ e.stopPropagation();
441
+ ts.removeWidget( this, name, refreshing );
442
+ })
443
+ .bind( 'destroy' + namespace, function( e, removeClasses, callback ) {
444
+ e.stopPropagation();
445
+ ts.destroy( this, removeClasses, callback );
446
+ })
447
+ .bind( 'resetToLoadState' + namespace, function( e ) {
448
+ e.stopPropagation();
449
+ // remove all widgets
450
+ ts.removeWidget( this, true, false );
451
+ var tmp = $.extend( true, {}, c.originalSettings );
452
+ // restore original settings; this clears out current settings, but does not clear
453
+ // values saved to storage.
454
+ c = $.extend( true, {}, ts.defaults, tmp );
455
+ c.originalSettings = tmp;
456
+ this.hasInitialized = false;
457
+ // setup the entire table again
458
+ ts.setup( this, c );
459
+ });
460
+ },
461
+
462
+ bindEvents : function( table, $headers, core ) {
463
+ table = $( table )[ 0 ];
464
+ var tmp,
465
+ c = table.config,
466
+ namespace = c.namespace,
467
+ downTarget = null;
468
+ if ( core !== true ) {
469
+ $headers.addClass( namespace.slice( 1 ) + '_extra_headers' );
470
+ tmp = ts.getClosest( $headers, 'table' );
471
+ if ( tmp.length && tmp[ 0 ].nodeName === 'TABLE' && tmp[ 0 ] !== table ) {
472
+ $( tmp[ 0 ] ).addClass( namespace.slice( 1 ) + '_extra_table' );
473
+ }
474
+ }
475
+ tmp = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
476
+ .replace( ts.regex.spaces, ' ' )
477
+ .split( ' ' )
478
+ .join( namespace + ' ' );
479
+ // apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
480
+ $headers
481
+ // http://stackoverflow.com/questions/5312849/jquery-find-self;
482
+ .find( c.selectorSort )
483
+ .add( $headers.filter( c.selectorSort ) )
484
+ .unbind( tmp )
485
+ .bind( tmp, function( e, external ) {
486
+ var $cell, cell, temp,
487
+ $target = $( e.target ),
488
+ // wrap event type in spaces, so the match doesn't trigger on inner words
489
+ type = ' ' + e.type + ' ';
490
+ // only recognize left clicks
491
+ if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
492
+ // allow pressing enter
493
+ ( type === ' keyup ' && e.which !== ts.keyCodes.enter ) ||
494
+ // allow triggering a click event (e.which is undefined) & ignore physical clicks
495
+ ( type.match( ' ' + c.pointerClick + ' ' ) && typeof e.which !== 'undefined' ) ) {
496
+ return;
497
+ }
498
+ // ignore mouseup if mousedown wasn't on the same target
499
+ if ( type.match( ' ' + c.pointerUp + ' ' ) && downTarget !== e.target && external !== true ) {
500
+ return;
501
+ }
502
+ // set target on mousedown
503
+ if ( type.match( ' ' + c.pointerDown + ' ' ) ) {
504
+ downTarget = e.target;
505
+ // preventDefault needed or jQuery v1.3.2 and older throws an
506
+ // "Uncaught TypeError: handler.apply is not a function" error
507
+ temp = $target.jquery.split( '.' );
508
+ if ( temp[ 0 ] === '1' && temp[ 1 ] < 4 ) { e.preventDefault(); }
509
+ return;
510
+ }
511
+ downTarget = null;
512
+ $cell = ts.getClosest( $( this ), '.' + ts.css.header );
513
+ // prevent sort being triggered on form elements
514
+ if ( ts.regex.formElements.test( e.target.nodeName ) ||
515
+ // nosort class name, or elements within a nosort container
516
+ $target.hasClass( c.cssNoSort ) || $target.parents( '.' + c.cssNoSort ).length > 0 ||
517
+ // disabled cell directly clicked
518
+ $cell.hasClass( 'sorter-false' ) ||
519
+ // elements within a button
520
+ $target.parents( 'button' ).length > 0 ) {
521
+ return !c.cancelSelection;
522
+ }
523
+ if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
524
+ ts.buildCache( c );
525
+ }
526
+ // use column index from data-attribute or index of current row; fixes #1116
527
+ c.last.clickedIndex = $cell.attr( 'data-column' ) || $cell.index();
528
+ cell = c.$headerIndexed[ c.last.clickedIndex ][0];
529
+ if ( cell && !cell.sortDisabled ) {
530
+ ts.initSort( c, cell, e );
531
+ }
532
+ });
533
+ if ( c.cancelSelection ) {
534
+ // cancel selection
535
+ $headers
536
+ .attr( 'unselectable', 'on' )
537
+ .bind( 'selectstart', false )
538
+ .css({
539
+ 'user-select' : 'none',
540
+ 'MozUserSelect' : 'none' // not needed for jQuery 1.8+
541
+ });
542
+ }
543
+ },
544
+
545
+ buildHeaders : function( c ) {
546
+ var $temp, icon, timer, indx;
547
+ c.headerList = [];
548
+ c.headerContent = [];
549
+ c.sortVars = [];
550
+ if ( ts.debug(c, 'core') ) {
551
+ timer = new Date();
552
+ }
553
+ // children tr in tfoot - see issue #196 & #547
554
+ // don't pass table.config to computeColumnIndex here - widgets (math) pass it to "quickly" index tbody cells
555
+ c.columns = ts.computeColumnIndex( c.$table.children( 'thead, tfoot' ).children( 'tr' ) );
556
+ // add icon if cssIcon option exists
557
+ icon = c.cssIcon ?
558
+ '<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' :
559
+ '';
560
+ // redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
561
+ c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {
562
+ var configHeaders, header, column, template, tmp,
563
+ $elem = $( elem );
564
+ // ignore cell (don't add it to c.$headers) if row has ignoreRow class
565
+ if ( ts.getClosest( $elem, 'tr' ).hasClass( c.cssIgnoreRow ) ) { return; }
566
+ // transfer data-column to element if not th/td - #1459
567
+ if ( !/(th|td)/i.test( elem.nodeName ) ) {
568
+ tmp = ts.getClosest( $elem, 'th, td' );
569
+ $elem.attr( 'data-column', tmp.attr( 'data-column' ) );
570
+ }
571
+ // make sure to get header cell & not column indexed cell
572
+ configHeaders = ts.getColumnData( c.table, c.headers, index, true );
573
+ // save original header content
574
+ c.headerContent[ index ] = $elem.html();
575
+ // if headerTemplate is empty, don't reformat the header cell
576
+ if ( c.headerTemplate !== '' && !$elem.find( '.' + ts.css.headerIn ).length ) {
577
+ // set up header template
578
+ template = c.headerTemplate
579
+ .replace( ts.regex.templateContent, $elem.html() )
580
+ .replace( ts.regex.templateIcon, $elem.find( '.' + ts.css.icon ).length ? '' : icon );
581
+ if ( c.onRenderTemplate ) {
582
+ header = c.onRenderTemplate.apply( $elem, [ index, template ] );
583
+ // only change t if something is returned
584
+ if ( header && typeof header === 'string' ) {
585
+ template = header;
586
+ }
587
+ }
588
+ $elem.html( '<div class="' + ts.css.headerIn + '">' + template + '</div>' ); // faster than wrapInner
589
+ }
590
+ if ( c.onRenderHeader ) {
591
+ c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );
592
+ }
593
+ column = parseInt( $elem.attr( 'data-column' ), 10 );
594
+ elem.column = column;
595
+ tmp = ts.getOrder( ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder );
596
+ // this may get updated numerous times if there are multiple rows
597
+ c.sortVars[ column ] = {
598
+ count : -1, // set to -1 because clicking on the header automatically adds one
599
+ order : tmp ?
600
+ ( c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ] ) : // desc, asc, unsorted
601
+ ( c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ] ), // asc, desc, unsorted
602
+ lockedOrder : false,
603
+ sortedBy : ''
604
+ };
605
+ tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
606
+ if ( typeof tmp !== 'undefined' && tmp !== false ) {
607
+ c.sortVars[ column ].lockedOrder = true;
608
+ c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1 ] : [ 0, 0 ];
609
+ }
610
+ // add cell to headerList
611
+ c.headerList[ index ] = elem;
612
+ $elem.addClass( ts.css.header + ' ' + c.cssHeader );
613
+ // add to parent in case there are multiple rows
614
+ ts.getClosest( $elem, 'tr' )
615
+ .addClass( ts.css.headerRow + ' ' + c.cssHeaderRow )
616
+ .attr( 'role', 'row' );
617
+ // allow keyboard cursor to focus on element
618
+ if ( c.tabIndex ) {
619
+ $elem.attr( 'tabindex', 0 );
620
+ }
621
+ return elem;
622
+ }) );
623
+ // cache headers per column
624
+ c.$headerIndexed = [];
625
+ for ( indx = 0; indx < c.columns; indx++ ) {
626
+ // colspan in header making a column undefined
627
+ if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {
628
+ c.sortVars[ indx ] = {};
629
+ }
630
+ // Use c.$headers.parent() in case selectorHeaders doesn't point to the th/td
631
+ $temp = c.$headers.filter( '[data-column="' + indx + '"]' );
632
+ // target sortable column cells, unless there are none, then use non-sortable cells
633
+ // .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
634
+ c.$headerIndexed[ indx ] = $temp.length ?
635
+ $temp.not( '.sorter-false' ).length ?
636
+ $temp.not( '.sorter-false' ).filter( ':last' ) :
637
+ $temp.filter( ':last' ) :
638
+ $();
639
+ }
640
+ c.$table.find( c.selectorHeaders ).attr({
641
+ scope: 'col',
642
+ role : 'columnheader'
643
+ });
644
+ // enable/disable sorting
645
+ ts.updateHeader( c );
646
+ if ( ts.debug(c, 'core') ) {
647
+ console.log( 'Built headers:' + ts.benchmark( timer ) );
648
+ console.log( c.$headers );
649
+ }
650
+ },
651
+
652
+ // Use it to add a set of methods to table.config which will be available for all tables.
653
+ // This should be done before table initialization
654
+ addInstanceMethods : function( methods ) {
655
+ $.extend( ts.instanceMethods, methods );
656
+ },
657
+
658
+ /*
659
+ █████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄█████
660
+ ██▄▄██ ██▄▄██ ██▄▄██ ▀█▄ ██▄▄ ██▄▄██ ▀█▄
661
+ ██▀▀▀ ██▀▀██ ██▀██ ▀█▄ ██▀▀ ██▀██ ▀█▄
662
+ ██ ██ ██ ██ ██ █████▀ ██████ ██ ██ █████▀
663
+ */
664
+ setupParsers : function( c, $tbodies ) {
665
+ var rows, list, span, max, colIndex, indx, header, configHeaders,
666
+ noParser, parser, extractor, time, tbody, len,
667
+ table = c.table,
668
+ tbodyIndex = 0,
669
+ debug = ts.debug(c, 'core'),
670
+ debugOutput = {};
671
+ // update table bodies in case we start with an empty table
672
+ c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
673
+ tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
674
+ len = tbody.length;
675
+ if ( len === 0 ) {
676
+ return debug ? console.warn( 'Warning: *Empty table!* Not building a parser cache' ) : '';
677
+ } else if ( debug ) {
678
+ time = new Date();
679
+ console[ console.group ? 'group' : 'log' ]( 'Detecting parsers for each column' );
680
+ }
681
+ list = {
682
+ extractors: [],
683
+ parsers: []
684
+ };
685
+ while ( tbodyIndex < len ) {
686
+ rows = tbody[ tbodyIndex ].rows;
687
+ if ( rows.length ) {
688
+ colIndex = 0;
689
+ max = c.columns;
690
+ for ( indx = 0; indx < max; indx++ ) {
691
+ header = c.$headerIndexed[ colIndex ];
692
+ if ( header && header.length ) {
693
+ // get column indexed table cell; adding true parameter fixes #1362 but
694
+ // it would break backwards compatibility...
695
+ configHeaders = ts.getColumnData( table, c.headers, colIndex ); // , true );
696
+ // get column parser/extractor
697
+ extractor = ts.getParserById( ts.getData( header, configHeaders, 'extractor' ) );
698
+ parser = ts.getParserById( ts.getData( header, configHeaders, 'sorter' ) );
699
+ noParser = ts.getData( header, configHeaders, 'parser' ) === 'false';
700
+ // empty cells behaviour - keeping emptyToBottom for backwards compatibility
701
+ c.empties[colIndex] = (
702
+ ts.getData( header, configHeaders, 'empty' ) ||
703
+ c.emptyTo || ( c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
704
+ // text strings behaviour in numerical sorts
705
+ c.strings[colIndex] = (
706
+ ts.getData( header, configHeaders, 'string' ) ||
707
+ c.stringTo ||
708
+ 'max' ).toLowerCase();
709
+ if ( noParser ) {
710
+ parser = ts.getParserById( 'no-parser' );
711
+ }
712
+ if ( !extractor ) {
713
+ // For now, maybe detect someday
714
+ extractor = false;
715
+ }
716
+ if ( !parser ) {
717
+ parser = ts.detectParserForColumn( c, rows, -1, colIndex );
718
+ }
719
+ if ( debug ) {
720
+ debugOutput[ '(' + colIndex + ') ' + header.text() ] = {
721
+ parser : parser.id,
722
+ extractor : extractor ? extractor.id : 'none',
723
+ string : c.strings[ colIndex ],
724
+ empty : c.empties[ colIndex ]
725
+ };
726
+ }
727
+ list.parsers[ colIndex ] = parser;
728
+ list.extractors[ colIndex ] = extractor;
729
+ span = header[ 0 ].colSpan - 1;
730
+ if ( span > 0 ) {
731
+ colIndex += span;
732
+ max += span;
733
+ while ( span + 1 > 0 ) {
734
+ // set colspan columns to use the same parsers & extractors
735
+ list.parsers[ colIndex - span ] = parser;
736
+ list.extractors[ colIndex - span ] = extractor;
737
+ span--;
738
+ }
739
+ }
740
+ }
741
+ colIndex++;
742
+ }
743
+ }
744
+ tbodyIndex += ( list.parsers.length ) ? len : 1;
745
+ }
746
+ if ( debug ) {
747
+ if ( !ts.isEmptyObject( debugOutput ) ) {
748
+ console[ console.table ? 'table' : 'log' ]( debugOutput );
749
+ } else {
750
+ console.warn( ' No parsers detected!' );
751
+ }
752
+ console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
753
+ if ( console.groupEnd ) { console.groupEnd(); }
754
+ }
755
+ c.parsers = list.parsers;
756
+ c.extractors = list.extractors;
757
+ },
758
+
759
+ addParser : function( parser ) {
760
+ var indx,
761
+ len = ts.parsers.length,
762
+ add = true;
763
+ for ( indx = 0; indx < len; indx++ ) {
764
+ if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {
765
+ add = false;
766
+ }
767
+ }
768
+ if ( add ) {
769
+ ts.parsers[ ts.parsers.length ] = parser;
770
+ }
771
+ },
772
+
773
+ getParserById : function( name ) {
774
+ /*jshint eqeqeq:false */ // eslint-disable-next-line eqeqeq
775
+ if ( name == 'false' ) { return false; }
776
+ var indx,
777
+ len = ts.parsers.length;
778
+ for ( indx = 0; indx < len; indx++ ) {
779
+ if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {
780
+ return ts.parsers[ indx ];
781
+ }
782
+ }
783
+ return false;
784
+ },
785
+
786
+ detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {
787
+ var cur, $node, row,
788
+ indx = ts.parsers.length,
789
+ node = false,
790
+ nodeValue = '',
791
+ debug = ts.debug(c, 'core'),
792
+ keepLooking = true;
793
+ while ( nodeValue === '' && keepLooking ) {
794
+ rowIndex++;
795
+ row = rows[ rowIndex ];
796
+ // stop looking after 50 empty rows
797
+ if ( row && rowIndex < 50 ) {
798
+ if ( row.className.indexOf( ts.cssIgnoreRow ) < 0 ) {
799
+ node = rows[ rowIndex ].cells[ cellIndex ];
800
+ nodeValue = ts.getElementText( c, node, cellIndex );
801
+ $node = $( node );
802
+ if ( debug ) {
803
+ console.log( 'Checking if value was empty on row ' + rowIndex + ', column: ' +
804
+ cellIndex + ': "' + nodeValue + '"' );
805
+ }
806
+ }
807
+ } else {
808
+ keepLooking = false;
809
+ }
810
+ }
811
+ while ( --indx >= 0 ) {
812
+ cur = ts.parsers[ indx ];
813
+ // ignore the default text parser because it will always be true
814
+ if ( cur && cur.id !== 'text' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {
815
+ return cur;
816
+ }
817
+ }
818
+ // nothing found, return the generic parser (text)
819
+ return ts.getParserById( 'text' );
820
+ },
821
+
822
+ getElementText : function( c, node, cellIndex ) {
823
+ if ( !node ) { return ''; }
824
+ var tmp,
825
+ extract = c.textExtraction || '',
826
+ // node could be a jquery object
827
+ // http://jsperf.com/jquery-vs-instanceof-jquery/2
828
+ $node = node.jquery ? node : $( node );
829
+ if ( typeof extract === 'string' ) {
830
+ // check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
831
+ // http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
832
+ if ( extract === 'basic' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== 'undefined' ) {
833
+ return $.trim( tmp );
834
+ }
835
+ return $.trim( node.textContent || $node.text() );
836
+ } else {
837
+ if ( typeof extract === 'function' ) {
838
+ return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );
839
+ } else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === 'function' ) {
840
+ return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );
841
+ }
842
+ }
843
+ // fallback
844
+ return $.trim( $node[ 0 ].textContent || $node.text() );
845
+ },
846
+
847
+ // centralized function to extract/parse cell contents
848
+ getParsedText : function( c, cell, colIndex, txt ) {
849
+ if ( typeof txt === 'undefined' ) {
850
+ txt = ts.getElementText( c, cell, colIndex );
851
+ }
852
+ // if no parser, make sure to return the txt
853
+ var val = '' + txt,
854
+ parser = c.parsers[ colIndex ],
855
+ extractor = c.extractors[ colIndex ];
856
+ if ( parser ) {
857
+ // do extract before parsing, if there is one
858
+ if ( extractor && typeof extractor.format === 'function' ) {
859
+ txt = extractor.format( txt, c.table, cell, colIndex );
860
+ }
861
+ // allow parsing if the string is empty, previously parsing would change it to zero,
862
+ // in case the parser needs to extract data from the table cell attributes
863
+ val = parser.id === 'no-parser' ? '' :
864
+ // make sure txt is a string (extractor may have converted it)
865
+ parser.format( '' + txt, c.table, cell, colIndex );
866
+ if ( c.ignoreCase && typeof val === 'string' ) {
867
+ val = val.toLowerCase();
868
+ }
869
+ }
870
+ return val;
871
+ },
872
+
873
+ /*
874
+ ▄████▄ ▄████▄ ▄████▄ ██ ██ ██████
875
+ ██ ▀▀ ██▄▄██ ██ ▀▀ ██▄▄██ ██▄▄
876
+ ██ ▄▄ ██▀▀██ ██ ▄▄ ██▀▀██ ██▀▀
877
+ ▀████▀ ██ ██ ▀████▀ ██ ██ ██████
878
+ */
879
+ buildCache : function( c, callback, $tbodies ) {
880
+ var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
881
+ cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
882
+ colMax, span, cacheIndex, hasParser, max, len, index,
883
+ table = c.table,
884
+ parsers = c.parsers,
885
+ debug = ts.debug(c, 'core');
886
+ // update tbody variable
887
+ c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
888
+ $tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
889
+ c.cache = {};
890
+ c.totalRows = 0;
891
+ // if no parsers found, return - it's an empty table.
892
+ if ( !parsers ) {
893
+ return debug ? console.warn( 'Warning: *Empty table!* Not building a cache' ) : '';
894
+ }
895
+ if ( debug ) {
896
+ cacheTime = new Date();
897
+ }
898
+ // processing icon
899
+ if ( c.showProcessing ) {
900
+ ts.isProcessing( table, true );
901
+ }
902
+ for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {
903
+ colMax = []; // column max value per tbody
904
+ cache = c.cache[ tbodyIndex ] = {
905
+ normalized: [] // array of normalized row data; last entry contains 'rowData' above
906
+ // colMax: # // added at the end
907
+ };
908
+
909
+ totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;
910
+ for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {
911
+ rowData = {
912
+ // order: original row order #
913
+ // $row : jQuery Object[]
914
+ child: [], // child row text (filter widget)
915
+ raw: [] // original row text
916
+ };
917
+ /** Add the table data to main data array */
918
+ $row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );
919
+ cols = [];
920
+ // ignore "remove-me" rows
921
+ if ( $row.hasClass( c.selectorRemove.slice(1) ) ) {
922
+ continue;
923
+ }
924
+ // if this is a child row, add it to the last row's children and continue to the next row
925
+ // ignore child row class, if it is the first row
926
+ if ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {
927
+ len = cache.normalized.length - 1;
928
+ prevRowData = cache.normalized[ len ][ c.columns ];
929
+ prevRowData.$row = prevRowData.$row.add( $row );
930
+ // add 'hasChild' class name to parent row
931
+ if ( !$row.prev().hasClass( c.cssChildRow ) ) {
932
+ $row.prev().addClass( ts.css.cssHasChild );
933
+ }
934
+ // save child row content (un-parsed!)
935
+ $cells = $row.children( 'th, td' );
936
+ len = prevRowData.child.length;
937
+ prevRowData.child[ len ] = [];
938
+ // child row content does not account for colspans/rowspans; so indexing may be off
939
+ cacheIndex = 0;
940
+ max = c.columns;
941
+ for ( colIndex = 0; colIndex < max; colIndex++ ) {
942
+ cell = $cells[ colIndex ];
943
+ if ( cell ) {
944
+ prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );
945
+ span = $cells[ colIndex ].colSpan - 1;
946
+ if ( span > 0 ) {
947
+ cacheIndex += span;
948
+ max += span;
949
+ }
950
+ }
951
+ cacheIndex++;
952
+ }
953
+ // go to the next for loop
954
+ continue;
955
+ }
956
+ rowData.$row = $row;
957
+ rowData.order = rowIndex; // add original row position to rowCache
958
+ cacheIndex = 0;
959
+ max = c.columns;
960
+ for ( colIndex = 0; colIndex < max; ++colIndex ) {
961
+ cell = $row[ 0 ].cells[ colIndex ];
962
+ if ( cell && cacheIndex < c.columns ) {
963
+ hasParser = typeof parsers[ cacheIndex ] !== 'undefined';
964
+ if ( !hasParser && debug ) {
965
+ console.warn( 'No parser found for row: ' + rowIndex + ', column: ' + colIndex +
966
+ '; cell containing: "' + $(cell).text() + '"; does it have a header?' );
967
+ }
968
+ val = ts.getElementText( c, cell, cacheIndex );
969
+ rowData.raw[ cacheIndex ] = val; // save original row text
970
+ // save raw column text even if there is no parser set
971
+ txt = ts.getParsedText( c, cell, cacheIndex, val );
972
+ cols[ cacheIndex ] = txt;
973
+ if ( hasParser && ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
974
+ // determine column max value (ignore sign)
975
+ colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
976
+ }
977
+ // allow colSpan in tbody
978
+ span = cell.colSpan - 1;
979
+ if ( span > 0 ) {
980
+ index = 0;
981
+ while ( index <= span ) {
982
+ // duplicate text (or not) to spanned columns
983
+ // instead of setting duplicate span to empty string, use textExtraction to try to get a value
984
+ // see http://stackoverflow.com/q/36449711/145346
985
+ txt = c.duplicateSpan || index === 0 ?
986
+ val :
987
+ typeof c.textExtraction !== 'string' ?
988
+ ts.getElementText( c, cell, cacheIndex + index ) || '' :
989
+ '';
990
+ rowData.raw[ cacheIndex + index ] = txt;
991
+ cols[ cacheIndex + index ] = txt;
992
+ index++;
993
+ }
994
+ cacheIndex += span;
995
+ max += span;
996
+ }
997
+ }
998
+ cacheIndex++;
999
+ }
1000
+ // ensure rowData is always in the same location (after the last column)
1001
+ cols[ c.columns ] = rowData;
1002
+ cache.normalized[ cache.normalized.length ] = cols;
1003
+ }
1004
+ cache.colMax = colMax;
1005
+ // total up rows, not including child rows
1006
+ c.totalRows += cache.normalized.length;
1007
+
1008
+ }
1009
+ if ( c.showProcessing ) {
1010
+ ts.isProcessing( table ); // remove processing icon
1011
+ }
1012
+ if ( debug ) {
1013
+ len = Math.min( 5, c.cache[ 0 ].normalized.length );
1014
+ console[ console.group ? 'group' : 'log' ]( 'Building cache for ' + c.totalRows +
1015
+ ' rows (showing ' + len + ' rows in log) and ' + c.columns + ' columns' +
1016
+ ts.benchmark( cacheTime ) );
1017
+ val = {};
1018
+ for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {
1019
+ for ( cacheIndex = 0; cacheIndex < len; cacheIndex++ ) {
1020
+ if ( !val[ 'row: ' + cacheIndex ] ) {
1021
+ val[ 'row: ' + cacheIndex ] = {};
1022
+ }
1023
+ val[ 'row: ' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =
1024
+ c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];
1025
+ }
1026
+ }
1027
+ console[ console.table ? 'table' : 'log' ]( val );
1028
+ if ( console.groupEnd ) { console.groupEnd(); }
1029
+ }
1030
+ if ( $.isFunction( callback ) ) {
1031
+ callback( table );
1032
+ }
1033
+ },
1034
+
1035
+ getColumnText : function( table, column, callback, rowFilter ) {
1036
+ table = $( table )[0];
1037
+ var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,
1038
+ hasCallback = typeof callback === 'function',
1039
+ allColumns = column === 'all',
1040
+ data = { raw : [], parsed: [], $cell: [] },
1041
+ c = table.config;
1042
+ if ( ts.isEmptyObject( c ) ) {
1043
+ if ( ts.debug(c, 'core') ) {
1044
+ console.warn( 'No cache found - aborting getColumnText function!' );
1045
+ }
1046
+ } else {
1047
+ tbodyLen = c.$tbodies.length;
1048
+ for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {
1049
+ cache = c.cache[ tbodyIndex ].normalized;
1050
+ rowLen = cache.length;
1051
+ for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {
1052
+ row = cache[ rowIndex ];
1053
+ if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {
1054
+ continue;
1055
+ }
1056
+ result = true;
1057
+ parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];
1058
+ row = row[ c.columns ];
1059
+ raw = ( allColumns ) ? row.raw : row.raw[ column ];
1060
+ $cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
1061
+ if ( hasCallback ) {
1062
+ result = callback({
1063
+ tbodyIndex : tbodyIndex,
1064
+ rowIndex : rowIndex,
1065
+ parsed : parsed,
1066
+ raw : raw,
1067
+ $row : row.$row,
1068
+ $cell : $cell
1069
+ });
1070
+ }
1071
+ if ( result !== false ) {
1072
+ data.parsed[ data.parsed.length ] = parsed;
1073
+ data.raw[ data.raw.length ] = raw;
1074
+ data.$cell[ data.$cell.length ] = $cell;
1075
+ }
1076
+ }
1077
+ }
1078
+ // return everything
1079
+ return data;
1080
+ }
1081
+ },
1082
+
1083
+ /*
1084
+ ██ ██ █████▄ █████▄ ▄████▄ ██████ ██████
1085
+ ██ ██ ██▄▄██ ██ ██ ██▄▄██ ██ ██▄▄
1086
+ ██ ██ ██▀▀▀ ██ ██ ██▀▀██ ██ ██▀▀
1087
+ ▀████▀ ██ █████▀ ██ ██ ██ ██████
1088
+ */
1089
+ setHeadersCss : function( c ) {
1090
+ var indx, column,
1091
+ list = c.sortList,
1092
+ len = list.length,
1093
+ none = ts.css.sortNone + ' ' + c.cssNone,
1094
+ css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ],
1095
+ cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
1096
+ aria = [ 'ascending', 'descending' ],
1097
+ updateColumnSort = function($el, index) {
1098
+ $el
1099
+ .removeClass( none )
1100
+ .addClass( css[ index ] )
1101
+ .attr( 'aria-sort', aria[ index ] )
1102
+ .find( '.' + ts.css.icon )
1103
+ .removeClass( cssIcon[ 2 ] )
1104
+ .addClass( cssIcon[ index ] );
1105
+ },
1106
+ // find the footer
1107
+ $extras = c.$table
1108
+ .find( 'tfoot tr' )
1109
+ .children( 'td, th' )
1110
+ .add( $( c.namespace + '_extra_headers' ) )
1111
+ .removeClass( css.join( ' ' ) ),
1112
+ // remove all header information
1113
+ $sorted = c.$headers
1114
+ .add( $( 'thead ' + c.namespace + '_extra_headers' ) )
1115
+ .removeClass( css.join( ' ' ) )
1116
+ .addClass( none )
1117
+ .attr( 'aria-sort', 'none' )
1118
+ .find( '.' + ts.css.icon )
1119
+ .removeClass( cssIcon.join( ' ' ) )
1120
+ .end();
1121
+ // add css none to all sortable headers
1122
+ $sorted
1123
+ .not( '.sorter-false' )
1124
+ .find( '.' + ts.css.icon )
1125
+ .addClass( cssIcon[ 2 ] );
1126
+ // add disabled css icon class
1127
+ if ( c.cssIconDisabled ) {
1128
+ $sorted
1129
+ .filter( '.sorter-false' )
1130
+ .find( '.' + ts.css.icon )
1131
+ .addClass( c.cssIconDisabled );
1132
+ }
1133
+ for ( indx = 0; indx < len; indx++ ) {
1134
+ // direction = 2 means reset!
1135
+ if ( list[ indx ][ 1 ] !== 2 ) {
1136
+ // multicolumn sorting updating - see #1005
1137
+ // .not(function() {}) needs jQuery 1.4
1138
+ // filter(function(i, el) {}) <- el is undefined in jQuery v1.2.6
1139
+ $sorted = c.$headers.filter( function( i ) {
1140
+ // only include headers that are in the sortList (this includes colspans)
1141
+ var include = true,
1142
+ $el = c.$headers.eq( i ),
1143
+ col = parseInt( $el.attr( 'data-column' ), 10 ),
1144
+ end = col + ts.getClosest( $el, 'th, td' )[0].colSpan;
1145
+ for ( ; col < end; col++ ) {
1146
+ include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;
1147
+ }
1148
+ return include;
1149
+ });
1150
+
1151
+ // choose the :last in case there are nested columns
1152
+ $sorted = $sorted
1153
+ .not( '.sorter-false' )
1154
+ .filter( '[data-column="' + list[ indx ][ 0 ] + '"]' + ( len === 1 ? ':last' : '' ) );
1155
+ if ( $sorted.length ) {
1156
+ for ( column = 0; column < $sorted.length; column++ ) {
1157
+ if ( !$sorted[ column ].sortDisabled ) {
1158
+ updateColumnSort( $sorted.eq( column ), list[ indx ][ 1 ] );
1159
+ }
1160
+ }
1161
+ }
1162
+ // add sorted class to footer & extra headers, if they exist
1163
+ if ( $extras.length ) {
1164
+ updateColumnSort( $extras.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' ), list[ indx ][ 1 ] );
1165
+ }
1166
+ }
1167
+ }
1168
+ // add verbose aria labels
1169
+ len = c.$headers.length;
1170
+ for ( indx = 0; indx < len; indx++ ) {
1171
+ ts.setColumnAriaLabel( c, c.$headers.eq( indx ) );
1172
+ }
1173
+ },
1174
+
1175
+ getClosest : function( $el, selector ) {
1176
+ // jQuery v1.2.6 doesn't have closest()
1177
+ if ( $.fn.closest ) {
1178
+ return $el.closest( selector );
1179
+ }
1180
+ return $el.is( selector ) ?
1181
+ $el :
1182
+ $el.parents( selector ).filter( ':first' );
1183
+ },
1184
+
1185
+ // nextSort (optional), lets you disable next sort text
1186
+ setColumnAriaLabel : function( c, $header, nextSort ) {
1187
+ if ( $header.length ) {
1188
+ var column = parseInt( $header.attr( 'data-column' ), 10 ),
1189
+ vars = c.sortVars[ column ],
1190
+ tmp = $header.hasClass( ts.css.sortAsc ) ?
1191
+ 'sortAsc' :
1192
+ $header.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone',
1193
+ txt = $.trim( $header.text() ) + ': ' + ts.language[ tmp ];
1194
+ if ( $header.hasClass( 'sorter-false' ) || nextSort === false ) {
1195
+ txt += ts.language.sortDisabled;
1196
+ } else {
1197
+ tmp = ( vars.count + 1 ) % vars.order.length;
1198
+ nextSort = vars.order[ tmp ];
1199
+ // if nextSort
1200
+ txt += ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
1201
+ }
1202
+ $header.attr( 'aria-label', txt );
1203
+ if (vars.sortedBy) {
1204
+ $header.attr( 'data-sortedBy', vars.sortedBy );
1205
+ } else {
1206
+ $header.removeAttr('data-sortedBy');
1207
+ }
1208
+ }
1209
+ },
1210
+
1211
+ updateHeader : function( c ) {
1212
+ var index, isDisabled, $header, col,
1213
+ table = c.table,
1214
+ len = c.$headers.length;
1215
+ for ( index = 0; index < len; index++ ) {
1216
+ $header = c.$headers.eq( index );
1217
+ col = ts.getColumnData( table, c.headers, index, true );
1218
+ // add 'sorter-false' class if 'parser-false' is set
1219
+ isDisabled = ts.getData( $header, col, 'sorter' ) === 'false' || ts.getData( $header, col, 'parser' ) === 'false';
1220
+ ts.setColumnSort( c, $header, isDisabled );
1221
+ }
1222
+ },
1223
+
1224
+ setColumnSort : function( c, $header, isDisabled ) {
1225
+ var id = c.table.id;
1226
+ $header[ 0 ].sortDisabled = isDisabled;
1227
+ $header[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' )
1228
+ .attr( 'aria-disabled', '' + isDisabled );
1229
+ // disable tab index on disabled cells
1230
+ if ( c.tabIndex ) {
1231
+ if ( isDisabled ) {
1232
+ $header.removeAttr( 'tabindex' );
1233
+ } else {
1234
+ $header.attr( 'tabindex', '0' );
1235
+ }
1236
+ }
1237
+ // aria-controls - requires table ID
1238
+ if ( id ) {
1239
+ if ( isDisabled ) {
1240
+ $header.removeAttr( 'aria-controls' );
1241
+ } else {
1242
+ $header.attr( 'aria-controls', id );
1243
+ }
1244
+ }
1245
+ },
1246
+
1247
+ updateHeaderSortCount : function( c, list ) {
1248
+ var col, dir, group, indx, primary, temp, val, order,
1249
+ sortList = list || c.sortList,
1250
+ len = sortList.length;
1251
+ c.sortList = [];
1252
+ for ( indx = 0; indx < len; indx++ ) {
1253
+ val = sortList[ indx ];
1254
+ // ensure all sortList values are numeric - fixes #127
1255
+ col = parseInt( val[ 0 ], 10 );
1256
+ // prevents error if sorton array is wrong
1257
+ if ( col < c.columns ) {
1258
+
1259
+ // set order if not already defined - due to colspan header without associated header cell
1260
+ // adding this check prevents a javascript error
1261
+ if ( !c.sortVars[ col ].order ) {
1262
+ if ( ts.getOrder( c.sortInitialOrder ) ) {
1263
+ order = c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ];
1264
+ } else {
1265
+ order = c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ];
1266
+ }
1267
+ c.sortVars[ col ].order = order;
1268
+ c.sortVars[ col ].count = 0;
1269
+ }
1270
+
1271
+ order = c.sortVars[ col ].order;
1272
+ dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
1273
+ dir = dir ? dir[ 0 ] : '';
1274
+ // 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
1275
+ switch ( dir ) {
1276
+ case '1' : case 'd' : // descending
1277
+ dir = 1;
1278
+ break;
1279
+ case 's' : // same direction (as primary column)
1280
+ // if primary sort is set to 's', make it ascending
1281
+ dir = primary || 0;
1282
+ break;
1283
+ case 'o' :
1284
+ temp = order[ ( primary || 0 ) % order.length ];
1285
+ // opposite of primary column; but resets if primary resets
1286
+ dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
1287
+ break;
1288
+ case 'n' :
1289
+ dir = order[ ( ++c.sortVars[ col ].count ) % order.length ];
1290
+ break;
1291
+ default : // ascending
1292
+ dir = 0;
1293
+ break;
1294
+ }
1295
+ primary = indx === 0 ? dir : primary;
1296
+ group = [ col, parseInt( dir, 10 ) || 0 ];
1297
+ c.sortList[ c.sortList.length ] = group;
1298
+ dir = $.inArray( group[ 1 ], order ); // fixes issue #167
1299
+ c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % order.length;
1300
+ }
1301
+ }
1302
+ },
1303
+
1304
+ updateAll : function( c, resort, callback ) {
1305
+ var table = c.table;
1306
+ table.isUpdating = true;
1307
+ ts.refreshWidgets( table, true, true );
1308
+ ts.buildHeaders( c );
1309
+ ts.bindEvents( table, c.$headers, true );
1310
+ ts.bindMethods( c );
1311
+ ts.commonUpdate( c, resort, callback );
1312
+ },
1313
+
1314
+ update : function( c, resort, callback ) {
1315
+ var table = c.table;
1316
+ table.isUpdating = true;
1317
+ // update sorting (if enabled/disabled)
1318
+ ts.updateHeader( c );
1319
+ ts.commonUpdate( c, resort, callback );
1320
+ },
1321
+
1322
+ // simple header update - see #989
1323
+ updateHeaders : function( c, callback ) {
1324
+ c.table.isUpdating = true;
1325
+ ts.buildHeaders( c );
1326
+ ts.bindEvents( c.table, c.$headers, true );
1327
+ ts.resortComplete( c, callback );
1328
+ },
1329
+
1330
+ updateCell : function( c, cell, resort, callback ) {
1331
+ // updateCell for child rows is a mess - we'll ignore them for now
1332
+ // eventually I'll break out the "update" row cache code to make everything consistent
1333
+ if ( $( cell ).closest( 'tr' ).hasClass( c.cssChildRow ) ) {
1334
+ console.warn('Tablesorter Warning! "updateCell" for child row content has been disabled, use "update" instead');
1335
+ return;
1336
+ }
1337
+ if ( ts.isEmptyObject( c.cache ) ) {
1338
+ // empty table, do an update instead - fixes #1099
1339
+ ts.updateHeader( c );
1340
+ ts.commonUpdate( c, resort, callback );
1341
+ return;
1342
+ }
1343
+ c.table.isUpdating = true;
1344
+ c.$table.find( c.selectorRemove ).remove();
1345
+ // get position from the dom
1346
+ var tmp, indx, row, icell, cache, len,
1347
+ $tbodies = c.$tbodies,
1348
+ $cell = $( cell ),
1349
+ // update cache - format: function( s, table, cell, cellIndex )
1350
+ // no closest in jQuery v1.2.6
1351
+ tbodyIndex = $tbodies.index( ts.getClosest( $cell, 'tbody' ) ),
1352
+ tbcache = c.cache[ tbodyIndex ],
1353
+ $row = ts.getClosest( $cell, 'tr' );
1354
+ cell = $cell[ 0 ]; // in case cell is a jQuery object
1355
+ // tbody may not exist if update is initialized while tbody is removed for processing
1356
+ if ( $tbodies.length && tbodyIndex >= 0 ) {
1357
+ row = $tbodies.eq( tbodyIndex ).find( 'tr' ).not( '.' + c.cssChildRow ).index( $row );
1358
+ cache = tbcache.normalized[ row ];
1359
+ len = $row[ 0 ].cells.length;
1360
+ if ( len !== c.columns ) {
1361
+ // colspan in here somewhere!
1362
+ icell = 0;
1363
+ tmp = false;
1364
+ for ( indx = 0; indx < len; indx++ ) {
1365
+ if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {
1366
+ icell += $row[ 0 ].cells[ indx ].colSpan;
1367
+ } else {
1368
+ tmp = true;
1369
+ }
1370
+ }
1371
+ } else {
1372
+ icell = $cell.index();
1373
+ }
1374
+ tmp = ts.getElementText( c, cell, icell ); // raw
1375
+ cache[ c.columns ].raw[ icell ] = tmp;
1376
+ tmp = ts.getParsedText( c, cell, icell, tmp );
1377
+ cache[ icell ] = tmp; // parsed
1378
+ if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
1379
+ // update column max value (ignore sign)
1380
+ tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );
1381
+ }
1382
+ tmp = resort !== 'undefined' ? resort : c.resort;
1383
+ if ( tmp !== false ) {
1384
+ // widgets will be reapplied
1385
+ ts.checkResort( c, tmp, callback );
1386
+ } else {
1387
+ // don't reapply widgets is resort is false, just in case it causes
1388
+ // problems with element focus
1389
+ ts.resortComplete( c, callback );
1390
+ }
1391
+ } else {
1392
+ if ( ts.debug(c, 'core') ) {
1393
+ console.error( 'updateCell aborted, tbody missing or not within the indicated table' );
1394
+ }
1395
+ c.table.isUpdating = false;
1396
+ }
1397
+ },
1398
+
1399
+ addRows : function( c, $row, resort, callback ) {
1400
+ var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len, order,
1401
+ cacheIndex, rowData, cells, cell, span,
1402
+ // allow passing a row string if only one non-info tbody exists in the table
1403
+ valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
1404
+ table = c.table;
1405
+ if ( valid ) {
1406
+ $row = $( $row );
1407
+ c.$tbodies.append( $row );
1408
+ } else if (
1409
+ !$row ||
1410
+ // row is a jQuery object?
1411
+ !( $row instanceof $ ) ||
1412
+ // row contained in the table?
1413
+ ( ts.getClosest( $row, 'table' )[ 0 ] !== c.table )
1414
+ ) {
1415
+ if ( ts.debug(c, 'core') ) {
1416
+ console.error( 'addRows method requires (1) a jQuery selector reference to rows that have already ' +
1417
+ 'been added to the table, or (2) row HTML string to be added to a table with only one tbody' );
1418
+ }
1419
+ return false;
1420
+ }
1421
+ table.isUpdating = true;
1422
+ if ( ts.isEmptyObject( c.cache ) ) {
1423
+ // empty table, do an update instead - fixes #450
1424
+ ts.updateHeader( c );
1425
+ ts.commonUpdate( c, resort, callback );
1426
+ } else {
1427
+ rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
1428
+ tbodyIndex = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
1429
+ // fixes adding rows to an empty table - see issue #179
1430
+ if ( !( c.parsers && c.parsers.length ) ) {
1431
+ ts.setupParsers( c );
1432
+ }
1433
+ // add each row
1434
+ for ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {
1435
+ cacheIndex = 0;
1436
+ len = $row[ rowIndex ].cells.length;
1437
+ order = c.cache[ tbodyIndex ].normalized.length;
1438
+ cells = [];
1439
+ rowData = {
1440
+ child : [],
1441
+ raw : [],
1442
+ $row : $row.eq( rowIndex ),
1443
+ order : order
1444
+ };
1445
+ // add each cell
1446
+ for ( cellIndex = 0; cellIndex < len; cellIndex++ ) {
1447
+ cell = $row[ rowIndex ].cells[ cellIndex ];
1448
+ txt = ts.getElementText( c, cell, cacheIndex );
1449
+ rowData.raw[ cacheIndex ] = txt;
1450
+ val = ts.getParsedText( c, cell, cacheIndex, txt );
1451
+ cells[ cacheIndex ] = val;
1452
+ if ( ( c.parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
1453
+ // update column max value (ignore sign)
1454
+ c.cache[ tbodyIndex ].colMax[ cacheIndex ] =
1455
+ Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );
1456
+ }
1457
+ span = cell.colSpan - 1;
1458
+ if ( span > 0 ) {
1459
+ cacheIndex += span;
1460
+ }
1461
+ cacheIndex++;
1462
+ }
1463
+ // add the row data to the end
1464
+ cells[ c.columns ] = rowData;
1465
+ // update cache
1466
+ c.cache[ tbodyIndex ].normalized[ order ] = cells;
1467
+ }
1468
+ // resort using current settings
1469
+ ts.checkResort( c, resort, callback );
1470
+ }
1471
+ },
1472
+
1473
+ updateCache : function( c, callback, $tbodies ) {
1474
+ // rebuild parsers
1475
+ if ( !( c.parsers && c.parsers.length ) ) {
1476
+ ts.setupParsers( c, $tbodies );
1477
+ }
1478
+ // rebuild the cache map
1479
+ ts.buildCache( c, callback, $tbodies );
1480
+ },
1481
+
1482
+ // init flag (true) used by pager plugin to prevent widget application
1483
+ // renamed from appendToTable
1484
+ appendCache : function( c, init ) {
1485
+ var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,
1486
+ table = c.table,
1487
+ $tbodies = c.$tbodies,
1488
+ rows = [],
1489
+ cache = c.cache;
1490
+ // empty table - fixes #206/#346
1491
+ if ( ts.isEmptyObject( cache ) ) {
1492
+ // run pager appender in case the table was just emptied
1493
+ return c.appender ? c.appender( table, rows ) :
1494
+ table.isUpdating ? c.$table.triggerHandler( 'updateComplete', table ) : ''; // Fixes #532
1495
+ }
1496
+ if ( ts.debug(c, 'core') ) {
1497
+ appendTime = new Date();
1498
+ }
1499
+ for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
1500
+ $tbody = $tbodies.eq( tbodyIndex );
1501
+ if ( $tbody.length ) {
1502
+ // detach tbody for manipulation
1503
+ $curTbody = ts.processTbody( table, $tbody, true );
1504
+ parsed = cache[ tbodyIndex ].normalized;
1505
+ totalRows = parsed.length;
1506
+ for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
1507
+ rows[rows.length] = parsed[ rowIndex ][ c.columns ].$row;
1508
+ // removeRows used by the pager plugin; don't render if using ajax - fixes #411
1509
+ if ( !c.appender || ( c.pager && !c.pager.removeRows && !c.pager.ajax ) ) {
1510
+ $curTbody.append( parsed[ rowIndex ][ c.columns ].$row );
1511
+ }
1512
+ }
1513
+ // restore tbody
1514
+ ts.processTbody( table, $curTbody, false );
1515
+ }
1516
+ }
1517
+ if ( c.appender ) {
1518
+ c.appender( table, rows );
1519
+ }
1520
+ if ( ts.debug(c, 'core') ) {
1521
+ console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
1522
+ }
1523
+ // apply table widgets; but not before ajax completes
1524
+ if ( !init && !c.appender ) {
1525
+ ts.applyWidget( table );
1526
+ }
1527
+ if ( table.isUpdating ) {
1528
+ c.$table.triggerHandler( 'updateComplete', table );
1529
+ }
1530
+ },
1531
+
1532
+ commonUpdate : function( c, resort, callback ) {
1533
+ // remove rows/elements before update
1534
+ c.$table.find( c.selectorRemove ).remove();
1535
+ // rebuild parsers
1536
+ ts.setupParsers( c );
1537
+ // rebuild the cache map
1538
+ ts.buildCache( c );
1539
+ ts.checkResort( c, resort, callback );
1540
+ },
1541
+
1542
+ /*
1543
+ ▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄
1544
+ ▀█▄ ██ ██ ██▄▄██ ██ ██ ██ ██ ██ ▄▄▄
1545
+ ▀█▄ ██ ██ ██▀██ ██ ██ ██ ██ ██ ▀██
1546
+ █████▀ ▀████▀ ██ ██ ██ ██ ██ ██ ▀████▀
1547
+ */
1548
+ initSort : function( c, cell, event ) {
1549
+ if ( c.table.isUpdating ) {
1550
+ // let any updates complete before initializing a sort
1551
+ return setTimeout( function() {
1552
+ ts.initSort( c, cell, event );
1553
+ }, 50 );
1554
+ }
1555
+
1556
+ var arry, indx, headerIndx, dir, temp, tmp, $header,
1557
+ notMultiSort = !event[ c.sortMultiSortKey ],
1558
+ table = c.table,
1559
+ len = c.$headers.length,
1560
+ th = ts.getClosest( $( cell ), 'th, td' ),
1561
+ col = parseInt( th.attr( 'data-column' ), 10 ),
1562
+ sortedBy = event.type === 'mouseup' ? 'user' : event.type,
1563
+ order = c.sortVars[ col ].order;
1564
+ th = th[0];
1565
+ // Only call sortStart if sorting is enabled
1566
+ c.$table.triggerHandler( 'sortStart', table );
1567
+ // get current column sort order
1568
+ tmp = ( c.sortVars[ col ].count + 1 ) % order.length;
1569
+ c.sortVars[ col ].count = event[ c.sortResetKey ] ? 2 : tmp;
1570
+ // reset all sorts on non-current column - issue #30
1571
+ if ( c.sortRestart ) {
1572
+ for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {
1573
+ $header = c.$headers.eq( headerIndx );
1574
+ tmp = parseInt( $header.attr( 'data-column' ), 10 );
1575
+ // only reset counts on columns that weren't just clicked on and if not included in a multisort
1576
+ if ( col !== tmp && ( notMultiSort || $header.hasClass( ts.css.sortNone ) ) ) {
1577
+ c.sortVars[ tmp ].count = -1;
1578
+ }
1579
+ }
1580
+ }
1581
+ // user only wants to sort on one column
1582
+ if ( notMultiSort ) {
1583
+ $.each( c.sortVars, function( i ) {
1584
+ c.sortVars[ i ].sortedBy = '';
1585
+ });
1586
+ // flush the sort list
1587
+ c.sortList = [];
1588
+ c.last.sortList = [];
1589
+ if ( c.sortForce !== null ) {
1590
+ arry = c.sortForce;
1591
+ for ( indx = 0; indx < arry.length; indx++ ) {
1592
+ if ( arry[ indx ][ 0 ] !== col ) {
1593
+ c.sortList[ c.sortList.length ] = arry[ indx ];
1594
+ c.sortVars[ arry[ indx ][ 0 ] ].sortedBy = 'sortForce';
1595
+ }
1596
+ }
1597
+ }
1598
+ // add column to sort list
1599
+ dir = order[ c.sortVars[ col ].count ];
1600
+ if ( dir < 2 ) {
1601
+ c.sortList[ c.sortList.length ] = [ col, dir ];
1602
+ c.sortVars[ col ].sortedBy = sortedBy;
1603
+ // add other columns if header spans across multiple
1604
+ if ( th.colSpan > 1 ) {
1605
+ for ( indx = 1; indx < th.colSpan; indx++ ) {
1606
+ c.sortList[ c.sortList.length ] = [ col + indx, dir ];
1607
+ // update count on columns in colSpan
1608
+ c.sortVars[ col + indx ].count = $.inArray( dir, order );
1609
+ c.sortVars[ col + indx ].sortedBy = sortedBy;
1610
+ }
1611
+ }
1612
+ }
1613
+ // multi column sorting
1614
+ } else {
1615
+ // get rid of the sortAppend before adding more - fixes issue #115 & #523
1616
+ c.sortList = $.extend( [], c.last.sortList );
1617
+
1618
+ // the user has clicked on an already sorted column
1619
+ if ( ts.isValueInArray( col, c.sortList ) >= 0 ) {
1620
+ // reverse the sorting direction
1621
+ c.sortVars[ col ].sortedBy = sortedBy;
1622
+ for ( indx = 0; indx < c.sortList.length; indx++ ) {
1623
+ tmp = c.sortList[ indx ];
1624
+ if ( tmp[ 0 ] === col ) {
1625
+ // order.count seems to be incorrect when compared to cell.count
1626
+ tmp[ 1 ] = order[ c.sortVars[ col ].count ];
1627
+ if ( tmp[1] === 2 ) {
1628
+ c.sortList.splice( indx, 1 );
1629
+ c.sortVars[ col ].count = -1;
1630
+ }
1631
+ }
1632
+ }
1633
+ } else {
1634
+ // add column to sort list array
1635
+ dir = order[ c.sortVars[ col ].count ];
1636
+ c.sortVars[ col ].sortedBy = sortedBy;
1637
+ if ( dir < 2 ) {
1638
+ c.sortList[ c.sortList.length ] = [ col, dir ];
1639
+ // add other columns if header spans across multiple
1640
+ if ( th.colSpan > 1 ) {
1641
+ for ( indx = 1; indx < th.colSpan; indx++ ) {
1642
+ c.sortList[ c.sortList.length ] = [ col + indx, dir ];
1643
+ // update count on columns in colSpan
1644
+ c.sortVars[ col + indx ].count = $.inArray( dir, order );
1645
+ c.sortVars[ col + indx ].sortedBy = sortedBy;
1646
+ }
1647
+ }
1648
+ }
1649
+ }
1650
+ }
1651
+ // save sort before applying sortAppend
1652
+ c.last.sortList = $.extend( [], c.sortList );
1653
+ if ( c.sortList.length && c.sortAppend ) {
1654
+ arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];
1655
+ if ( !ts.isEmptyObject( arry ) ) {
1656
+ for ( indx = 0; indx < arry.length; indx++ ) {
1657
+ if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {
1658
+ dir = arry[ indx ][ 1 ];
1659
+ temp = ( '' + dir ).match( /^(a|d|s|o|n)/ );
1660
+ if ( temp ) {
1661
+ tmp = c.sortList[ 0 ][ 1 ];
1662
+ switch ( temp[ 0 ] ) {
1663
+ case 'd' :
1664
+ dir = 1;
1665
+ break;
1666
+ case 's' :
1667
+ dir = tmp;
1668
+ break;
1669
+ case 'o' :
1670
+ dir = tmp === 0 ? 1 : 0;
1671
+ break;
1672
+ case 'n' :
1673
+ dir = ( tmp + 1 ) % order.length;
1674
+ break;
1675
+ default:
1676
+ dir = 0;
1677
+ break;
1678
+ }
1679
+ }
1680
+ c.sortList[ c.sortList.length ] = [ arry[ indx ][ 0 ], dir ];
1681
+ c.sortVars[ arry[ indx ][ 0 ] ].sortedBy = 'sortAppend';
1682
+ }
1683
+ }
1684
+ }
1685
+ }
1686
+ // sortBegin event triggered immediately before the sort
1687
+ c.$table.triggerHandler( 'sortBegin', table );
1688
+ // setTimeout needed so the processing icon shows up
1689
+ setTimeout( function() {
1690
+ // set css for headers
1691
+ ts.setHeadersCss( c );
1692
+ ts.multisort( c );
1693
+ ts.appendCache( c );
1694
+ c.$table.triggerHandler( 'sortBeforeEnd', table );
1695
+ c.$table.triggerHandler( 'sortEnd', table );
1696
+ }, 1 );
1697
+ },
1698
+
1699
+ // sort multiple columns
1700
+ multisort : function( c ) { /*jshint loopfunc:true */
1701
+ var tbodyIndex, sortTime, colMax, rows, tmp,
1702
+ table = c.table,
1703
+ sorter = [],
1704
+ dir = 0,
1705
+ textSorter = c.textSorter || '',
1706
+ sortList = c.sortList,
1707
+ sortLen = sortList.length,
1708
+ len = c.$tbodies.length;
1709
+ if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {
1710
+ // empty table - fixes #206/#346
1711
+ return;
1712
+ }
1713
+ if ( ts.debug(c, 'core') ) { sortTime = new Date(); }
1714
+ // cache textSorter to optimize speed
1715
+ if ( typeof textSorter === 'object' ) {
1716
+ colMax = c.columns;
1717
+ while ( colMax-- ) {
1718
+ tmp = ts.getColumnData( table, textSorter, colMax );
1719
+ if ( typeof tmp === 'function' ) {
1720
+ sorter[ colMax ] = tmp;
1721
+ }
1722
+ }
1723
+ }
1724
+ for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {
1725
+ colMax = c.cache[ tbodyIndex ].colMax;
1726
+ rows = c.cache[ tbodyIndex ].normalized;
1727
+
1728
+ rows.sort( function( a, b ) {
1729
+ var sortIndex, num, col, order, sort, x, y;
1730
+ // rows is undefined here in IE, so don't use it!
1731
+ for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {
1732
+ col = sortList[ sortIndex ][ 0 ];
1733
+ order = sortList[ sortIndex ][ 1 ];
1734
+ // sort direction, true = asc, false = desc
1735
+ dir = order === 0;
1736
+
1737
+ if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {
1738
+ return a[ c.columns ].order - b[ c.columns ].order;
1739
+ }
1740
+
1741
+ // fallback to natural sort since it is more robust
1742
+ num = /n/i.test( ts.getSortType( c.parsers, col ) );
1743
+ if ( num && c.strings[ col ] ) {
1744
+ // sort strings in numerical columns
1745
+ if ( typeof ( ts.string[ c.strings[ col ] ] ) === 'boolean' ) {
1746
+ num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );
1747
+ } else {
1748
+ num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;
1749
+ }
1750
+ // fall back to built-in numeric sort
1751
+ // var sort = $.tablesorter['sort' + s]( a[col], b[col], dir, colMax[col], table );
1752
+ sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :
1753
+ ts[ 'sortNumeric' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );
1754
+ } else {
1755
+ // set a & b depending on sort direction
1756
+ x = dir ? a : b;
1757
+ y = dir ? b : a;
1758
+ // text sort function
1759
+ if ( typeof textSorter === 'function' ) {
1760
+ // custom OVERALL text sorter
1761
+ sort = textSorter( x[ col ], y[ col ], dir, col, table );
1762
+ } else if ( typeof sorter[ col ] === 'function' ) {
1763
+ // custom text sorter for a SPECIFIC COLUMN
1764
+ sort = sorter[ col ]( x[ col ], y[ col ], dir, col, table );
1765
+ } else {
1766
+ // fall back to natural sort
1767
+ sort = ts[ 'sortNatural' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ] || '', b[ col ] || '', col, c );
1768
+ }
1769
+ }
1770
+ if ( sort ) { return sort; }
1771
+ }
1772
+ return a[ c.columns ].order - b[ c.columns ].order;
1773
+ });
1774
+ }
1775
+ if ( ts.debug(c, 'core') ) {
1776
+ console.log( 'Applying sort ' + sortList.toString() + ts.benchmark( sortTime ) );
1777
+ }
1778
+ },
1779
+
1780
+ resortComplete : function( c, callback ) {
1781
+ if ( c.table.isUpdating ) {
1782
+ c.$table.triggerHandler( 'updateComplete', c.table );
1783
+ }
1784
+ if ( $.isFunction( callback ) ) {
1785
+ callback( c.table );
1786
+ }
1787
+ },
1788
+
1789
+ checkResort : function( c, resort, callback ) {
1790
+ var sortList = $.isArray( resort ) ? resort : c.sortList,
1791
+ // if no resort parameter is passed, fallback to config.resort (true by default)
1792
+ resrt = typeof resort === 'undefined' ? c.resort : resort;
1793
+ // don't try to resort if the table is still processing
1794
+ // this will catch spamming of the updateCell method
1795
+ if ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {
1796
+ if ( sortList.length ) {
1797
+ ts.sortOn( c, sortList, function() {
1798
+ ts.resortComplete( c, callback );
1799
+ }, true );
1800
+ } else {
1801
+ ts.sortReset( c, function() {
1802
+ ts.resortComplete( c, callback );
1803
+ ts.applyWidget( c.table, false );
1804
+ } );
1805
+ }
1806
+ } else {
1807
+ ts.resortComplete( c, callback );
1808
+ ts.applyWidget( c.table, false );
1809
+ }
1810
+ },
1811
+
1812
+ sortOn : function( c, list, callback, init ) {
1813
+ var indx,
1814
+ table = c.table;
1815
+ c.$table.triggerHandler( 'sortStart', table );
1816
+ for (indx = 0; indx < c.columns; indx++) {
1817
+ c.sortVars[ indx ].sortedBy = ts.isValueInArray( indx, list ) > -1 ? 'sorton' : '';
1818
+ }
1819
+ // update header count index
1820
+ ts.updateHeaderSortCount( c, list );
1821
+ // set css for headers
1822
+ ts.setHeadersCss( c );
1823
+ // fixes #346
1824
+ if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
1825
+ ts.buildCache( c );
1826
+ }
1827
+ c.$table.triggerHandler( 'sortBegin', table );
1828
+ // sort the table and append it to the dom
1829
+ ts.multisort( c );
1830
+ ts.appendCache( c, init );
1831
+ c.$table.triggerHandler( 'sortBeforeEnd', table );
1832
+ c.$table.triggerHandler( 'sortEnd', table );
1833
+ ts.applyWidget( table );
1834
+ if ( $.isFunction( callback ) ) {
1835
+ callback( table );
1836
+ }
1837
+ },
1838
+
1839
+ sortReset : function( c, callback ) {
1840
+ c.sortList = [];
1841
+ var indx;
1842
+ for (indx = 0; indx < c.columns; indx++) {
1843
+ c.sortVars[ indx ].count = -1;
1844
+ c.sortVars[ indx ].sortedBy = '';
1845
+ }
1846
+ ts.setHeadersCss( c );
1847
+ ts.multisort( c );
1848
+ ts.appendCache( c );
1849
+ if ( $.isFunction( callback ) ) {
1850
+ callback( c.table );
1851
+ }
1852
+ },
1853
+
1854
+ getSortType : function( parsers, column ) {
1855
+ return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
1856
+ },
1857
+
1858
+ getOrder : function( val ) {
1859
+ // look for 'd' in 'desc' order; return true
1860
+ return ( /^d/i.test( val ) || val === 1 );
1861
+ },
1862
+
1863
+ // Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
1864
+ sortNatural : function( a, b ) {
1865
+ if ( a === b ) { return 0; }
1866
+ a = ( a || '' ).toString();
1867
+ b = ( b || '' ).toString();
1868
+ var aNum, bNum, aFloat, bFloat, indx, max,
1869
+ regex = ts.regex;
1870
+ // first try and sort Hex codes
1871
+ if ( regex.hex.test( b ) ) {
1872
+ aNum = parseInt( a.match( regex.hex ), 16 );
1873
+ bNum = parseInt( b.match( regex.hex ), 16 );
1874
+ if ( aNum < bNum ) { return -1; }
1875
+ if ( aNum > bNum ) { return 1; }
1876
+ }
1877
+ // chunk/tokenize
1878
+ aNum = a.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
1879
+ bNum = b.replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
1880
+ max = Math.max( aNum.length, bNum.length );
1881
+ // natural sorting through split numeric strings and default strings
1882
+ for ( indx = 0; indx < max; indx++ ) {
1883
+ // find floats not starting with '0', string or 0 if not defined
1884
+ aFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;
1885
+ bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;
1886
+ // handle numeric vs string comparison - number < string - (Kyle Adams)
1887
+ if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }
1888
+ // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
1889
+ if ( typeof aFloat !== typeof bFloat ) {
1890
+ aFloat += '';
1891
+ bFloat += '';
1892
+ }
1893
+ if ( aFloat < bFloat ) { return -1; }
1894
+ if ( aFloat > bFloat ) { return 1; }
1895
+ }
1896
+ return 0;
1897
+ },
1898
+
1899
+ sortNaturalAsc : function( a, b, col, c ) {
1900
+ if ( a === b ) { return 0; }
1901
+ var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1902
+ if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
1903
+ if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
1904
+ return ts.sortNatural( a, b );
1905
+ },
1906
+
1907
+ sortNaturalDesc : function( a, b, col, c ) {
1908
+ if ( a === b ) { return 0; }
1909
+ var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1910
+ if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
1911
+ if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
1912
+ return ts.sortNatural( b, a );
1913
+ },
1914
+
1915
+ // basic alphabetical sort
1916
+ sortText : function( a, b ) {
1917
+ return a > b ? 1 : ( a < b ? -1 : 0 );
1918
+ },
1919
+
1920
+ // return text string value by adding up ascii value
1921
+ // so the text is somewhat sorted when using a digital sort
1922
+ // this is NOT an alphanumeric sort
1923
+ getTextValue : function( val, num, max ) {
1924
+ if ( max ) {
1925
+ // make sure the text value is greater than the max numerical value (max)
1926
+ var indx,
1927
+ len = val ? val.length : 0,
1928
+ n = max + num;
1929
+ for ( indx = 0; indx < len; indx++ ) {
1930
+ n += val.charCodeAt( indx );
1931
+ }
1932
+ return num * n;
1933
+ }
1934
+ return 0;
1935
+ },
1936
+
1937
+ sortNumericAsc : function( a, b, num, max, col, c ) {
1938
+ if ( a === b ) { return 0; }
1939
+ var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1940
+ if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
1941
+ if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
1942
+ if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
1943
+ if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
1944
+ return a - b;
1945
+ },
1946
+
1947
+ sortNumericDesc : function( a, b, num, max, col, c ) {
1948
+ if ( a === b ) { return 0; }
1949
+ var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
1950
+ if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
1951
+ if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
1952
+ if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
1953
+ if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
1954
+ return b - a;
1955
+ },
1956
+
1957
+ sortNumeric : function( a, b ) {
1958
+ return a - b;
1959
+ },
1960
+
1961
+ /*
1962
+ ██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄█████
1963
+ ██ ██ ██ ██ ██ ██ ██ ▄▄▄ ██▄▄ ██ ▀█▄
1964
+ ██ ██ ██ ██ ██ ██ ██ ▀██ ██▀▀ ██ ▀█▄
1965
+ ███████▀ ██ █████▀ ▀████▀ ██████ ██ █████▀
1966
+ */
1967
+ addWidget : function( widget ) {
1968
+ if ( widget.id && !ts.isEmptyObject( ts.getWidgetById( widget.id ) ) ) {
1969
+ console.warn( '"' + widget.id + '" widget was loaded more than once!' );
1970
+ }
1971
+ ts.widgets[ ts.widgets.length ] = widget;
1972
+ },
1973
+
1974
+ hasWidget : function( $table, name ) {
1975
+ $table = $( $table );
1976
+ return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;
1977
+ },
1978
+
1979
+ getWidgetById : function( name ) {
1980
+ var indx, widget,
1981
+ len = ts.widgets.length;
1982
+ for ( indx = 0; indx < len; indx++ ) {
1983
+ widget = ts.widgets[ indx ];
1984
+ if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {
1985
+ return widget;
1986
+ }
1987
+ }
1988
+ },
1989
+
1990
+ applyWidgetOptions : function( table ) {
1991
+ var indx, widget, wo,
1992
+ c = table.config,
1993
+ len = c.widgets.length;
1994
+ if ( len ) {
1995
+ for ( indx = 0; indx < len; indx++ ) {
1996
+ widget = ts.getWidgetById( c.widgets[ indx ] );
1997
+ if ( widget && widget.options ) {
1998
+ wo = $.extend( true, {}, widget.options );
1999
+ c.widgetOptions = $.extend( true, wo, c.widgetOptions );
2000
+ // add widgetOptions to defaults for option validator
2001
+ $.extend( true, ts.defaults.widgetOptions, widget.options );
2002
+ }
2003
+ }
2004
+ }
2005
+ },
2006
+
2007
+ addWidgetFromClass : function( table ) {
2008
+ var len, indx,
2009
+ c = table.config,
2010
+ // look for widgets to apply from table class
2011
+ // don't match from 'ui-widget-content'; use \S instead of \w to include widgets
2012
+ // with dashes in the name, e.g. "widget-test-2" extracts out "test-2"
2013
+ regex = '^' + c.widgetClass.replace( ts.regex.templateName, '(\\S+)+' ) + '$',
2014
+ widgetClass = new RegExp( regex, 'g' ),
2015
+ // split up table class (widget id's can include dashes) - stop using match
2016
+ // otherwise only one widget gets extracted, see #1109
2017
+ widgets = ( table.className || '' ).split( ts.regex.spaces );
2018
+ if ( widgets.length ) {
2019
+ len = widgets.length;
2020
+ for ( indx = 0; indx < len; indx++ ) {
2021
+ if ( widgets[ indx ].match( widgetClass ) ) {
2022
+ c.widgets[ c.widgets.length ] = widgets[ indx ].replace( widgetClass, '$1' );
2023
+ }
2024
+ }
2025
+ }
2026
+ },
2027
+
2028
+ applyWidgetId : function( table, id, init ) {
2029
+ table = $(table)[0];
2030
+ var applied, time, name,
2031
+ c = table.config,
2032
+ wo = c.widgetOptions,
2033
+ debug = ts.debug(c, 'core'),
2034
+ widget = ts.getWidgetById( id );
2035
+ if ( widget ) {
2036
+ name = widget.id;
2037
+ applied = false;
2038
+ // add widget name to option list so it gets reapplied after sorting, filtering, etc
2039
+ if ( $.inArray( name, c.widgets ) < 0 ) {
2040
+ c.widgets[ c.widgets.length ] = name;
2041
+ }
2042
+ if ( debug ) { time = new Date(); }
2043
+
2044
+ if ( init || !( c.widgetInit[ name ] ) ) {
2045
+ // set init flag first to prevent calling init more than once (e.g. pager)
2046
+ c.widgetInit[ name ] = true;
2047
+ if ( table.hasInitialized ) {
2048
+ // don't reapply widget options on tablesorter init
2049
+ ts.applyWidgetOptions( table );
2050
+ }
2051
+ if ( typeof widget.init === 'function' ) {
2052
+ applied = true;
2053
+ if ( debug ) {
2054
+ console[ console.group ? 'group' : 'log' ]( 'Initializing ' + name + ' widget' );
2055
+ }
2056
+ widget.init( table, widget, c, wo );
2057
+ }
2058
+ }
2059
+ if ( !init && typeof widget.format === 'function' ) {
2060
+ applied = true;
2061
+ if ( debug ) {
2062
+ console[ console.group ? 'group' : 'log' ]( 'Updating ' + name + ' widget' );
2063
+ }
2064
+ widget.format( table, c, wo, false );
2065
+ }
2066
+ if ( debug ) {
2067
+ if ( applied ) {
2068
+ console.log( 'Completed ' + ( init ? 'initializing ' : 'applying ' ) + name + ' widget' + ts.benchmark( time ) );
2069
+ if ( console.groupEnd ) { console.groupEnd(); }
2070
+ }
2071
+ }
2072
+ }
2073
+ },
2074
+
2075
+ applyWidget : function( table, init, callback ) {
2076
+ table = $( table )[ 0 ]; // in case this is called externally
2077
+ var indx, len, names, widget, time,
2078
+ c = table.config,
2079
+ debug = ts.debug(c, 'core'),
2080
+ widgets = [];
2081
+ // prevent numerous consecutive widget applications
2082
+ if ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {
2083
+ return;
2084
+ }
2085
+ if ( debug ) { time = new Date(); }
2086
+ ts.addWidgetFromClass( table );
2087
+ // prevent "tablesorter-ready" from firing multiple times in a row
2088
+ clearTimeout( c.timerReady );
2089
+ if ( c.widgets.length ) {
2090
+ table.isApplyingWidgets = true;
2091
+ // ensure unique widget ids
2092
+ c.widgets = $.grep( c.widgets, function( val, index ) {
2093
+ return $.inArray( val, c.widgets ) === index;
2094
+ });
2095
+ names = c.widgets || [];
2096
+ len = names.length;
2097
+ // build widget array & add priority as needed
2098
+ for ( indx = 0; indx < len; indx++ ) {
2099
+ widget = ts.getWidgetById( names[ indx ] );
2100
+ if ( widget && widget.id ) {
2101
+ // set priority to 10 if not defined
2102
+ if ( !widget.priority ) { widget.priority = 10; }
2103
+ widgets[ indx ] = widget;
2104
+ } else if ( debug ) {
2105
+ console.warn( '"' + names[ indx ] + '" was enabled, but the widget code has not been loaded!' );
2106
+ }
2107
+ }
2108
+ // sort widgets by priority
2109
+ widgets.sort( function( a, b ) {
2110
+ return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
2111
+ });
2112
+ // add/update selected widgets
2113
+ len = widgets.length;
2114
+ if ( debug ) {
2115
+ console[ console.group ? 'group' : 'log' ]( 'Start ' + ( init ? 'initializing' : 'applying' ) + ' widgets' );
2116
+ }
2117
+ for ( indx = 0; indx < len; indx++ ) {
2118
+ widget = widgets[ indx ];
2119
+ if ( widget && widget.id ) {
2120
+ ts.applyWidgetId( table, widget.id, init );
2121
+ }
2122
+ }
2123
+ if ( debug && console.groupEnd ) { console.groupEnd(); }
2124
+ }
2125
+ c.timerReady = setTimeout( function() {
2126
+ table.isApplyingWidgets = false;
2127
+ $.data( table, 'lastWidgetApplication', new Date() );
2128
+ c.$table.triggerHandler( 'tablesorter-ready' );
2129
+ // callback executed on init only
2130
+ if ( !init && typeof callback === 'function' ) {
2131
+ callback( table );
2132
+ }
2133
+ if ( debug ) {
2134
+ widget = c.widgets.length;
2135
+ console.log( 'Completed ' +
2136
+ ( init === true ? 'initializing ' : 'applying ' ) + widget +
2137
+ ' widget' + ( widget !== 1 ? 's' : '' ) + ts.benchmark( time ) );
2138
+ }
2139
+ }, 10 );
2140
+ },
2141
+
2142
+ removeWidget : function( table, name, refreshing ) {
2143
+ table = $( table )[ 0 ];
2144
+ var index, widget, indx, len,
2145
+ c = table.config;
2146
+ // if name === true, add all widgets from $.tablesorter.widgets
2147
+ if ( name === true ) {
2148
+ name = [];
2149
+ len = ts.widgets.length;
2150
+ for ( indx = 0; indx < len; indx++ ) {
2151
+ widget = ts.widgets[ indx ];
2152
+ if ( widget && widget.id ) {
2153
+ name[ name.length ] = widget.id;
2154
+ }
2155
+ }
2156
+ } else {
2157
+ // name can be either an array of widgets names,
2158
+ // or a space/comma separated list of widget names
2159
+ name = ( $.isArray( name ) ? name.join( ',' ) : name || '' ).toLowerCase().split( /[\s,]+/ );
2160
+ }
2161
+ len = name.length;
2162
+ for ( index = 0; index < len; index++ ) {
2163
+ widget = ts.getWidgetById( name[ index ] );
2164
+ indx = $.inArray( name[ index ], c.widgets );
2165
+ // don't remove the widget from config.widget if refreshing
2166
+ if ( indx >= 0 && refreshing !== true ) {
2167
+ c.widgets.splice( indx, 1 );
2168
+ }
2169
+ if ( widget && widget.remove ) {
2170
+ if ( ts.debug(c, 'core') ) {
2171
+ console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[ index ] + '" widget' );
2172
+ }
2173
+ widget.remove( table, c, c.widgetOptions, refreshing );
2174
+ c.widgetInit[ name[ index ] ] = false;
2175
+ }
2176
+ }
2177
+ c.$table.triggerHandler( 'widgetRemoveEnd', table );
2178
+ },
2179
+
2180
+ refreshWidgets : function( table, doAll, dontapply ) {
2181
+ table = $( table )[ 0 ]; // see issue #243
2182
+ var indx, widget,
2183
+ c = table.config,
2184
+ curWidgets = c.widgets,
2185
+ widgets = ts.widgets,
2186
+ len = widgets.length,
2187
+ list = [],
2188
+ callback = function( table ) {
2189
+ $( table ).triggerHandler( 'refreshComplete' );
2190
+ };
2191
+ // remove widgets not defined in config.widgets, unless doAll is true
2192
+ for ( indx = 0; indx < len; indx++ ) {
2193
+ widget = widgets[ indx ];
2194
+ if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {
2195
+ list[ list.length ] = widget.id;
2196
+ }
2197
+ }
2198
+ ts.removeWidget( table, list.join( ',' ), true );
2199
+ if ( dontapply !== true ) {
2200
+ // call widget init if
2201
+ ts.applyWidget( table, doAll || false, callback );
2202
+ if ( doAll ) {
2203
+ // apply widget format
2204
+ ts.applyWidget( table, false, callback );
2205
+ }
2206
+ } else {
2207
+ callback( table );
2208
+ }
2209
+ },
2210
+
2211
+ /*
2212
+ ██ ██ ██████ ██ ██ ██ ██████ ██ ██████ ▄█████
2213
+ ██ ██ ██ ██ ██ ██ ██ ██ ██▄▄ ▀█▄
2214
+ ██ ██ ██ ██ ██ ██ ██ ██ ██▀▀ ▀█▄
2215
+ ▀████▀ ██ ██ ██████ ██ ██ ██ ██████ █████▀
2216
+ */
2217
+ benchmark : function( diff ) {
2218
+ return ( ' (' + ( new Date().getTime() - diff.getTime() ) + ' ms)' );
2219
+ },
2220
+ // deprecated ts.log
2221
+ log : function() {
2222
+ console.log( arguments );
2223
+ },
2224
+ debug : function(c, name) {
2225
+ return c && (
2226
+ c.debug === true ||
2227
+ typeof c.debug === 'string' && c.debug.indexOf(name) > -1
2228
+ );
2229
+ },
2230
+
2231
+ // $.isEmptyObject from jQuery v1.4
2232
+ isEmptyObject : function( obj ) {
2233
+ /*jshint forin: false */
2234
+ for ( var name in obj ) {
2235
+ return false;
2236
+ }
2237
+ return true;
2238
+ },
2239
+
2240
+ isValueInArray : function( column, arry ) {
2241
+ var indx,
2242
+ len = arry && arry.length || 0;
2243
+ for ( indx = 0; indx < len; indx++ ) {
2244
+ if ( arry[ indx ][ 0 ] === column ) {
2245
+ return indx;
2246
+ }
2247
+ }
2248
+ return -1;
2249
+ },
2250
+
2251
+ formatFloat : function( str, table ) {
2252
+ if ( typeof str !== 'string' || str === '' ) { return str; }
2253
+ // allow using formatFloat without a table; defaults to US number format
2254
+ var num,
2255
+ usFormat = table && table.config ? table.config.usNumberFormat !== false :
2256
+ typeof table !== 'undefined' ? table : true;
2257
+ if ( usFormat ) {
2258
+ // US Format - 1,234,567.89 -> 1234567.89
2259
+ str = str.replace( ts.regex.comma, '' );
2260
+ } else {
2261
+ // German Format = 1.234.567,89 -> 1234567.89
2262
+ // French Format = 1 234 567,89 -> 1234567.89
2263
+ str = str.replace( ts.regex.digitNonUS, '' ).replace( ts.regex.comma, '.' );
2264
+ }
2265
+ if ( ts.regex.digitNegativeTest.test( str ) ) {
2266
+ // make (#) into a negative number -> (10) = -10
2267
+ str = str.replace( ts.regex.digitNegativeReplace, '-$1' );
2268
+ }
2269
+ num = parseFloat( str );
2270
+ // return the text instead of zero
2271
+ return isNaN( num ) ? $.trim( str ) : num;
2272
+ },
2273
+
2274
+ isDigit : function( str ) {
2275
+ // replace all unwanted chars and match
2276
+ return isNaN( str ) ?
2277
+ ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, '' ) ) :
2278
+ str !== '';
2279
+ },
2280
+
2281
+ // computeTableHeaderCellIndexes from:
2282
+ // http://www.javascripttoolbox.com/lib/table/examples.php
2283
+ // http://www.javascripttoolbox.com/temp/table_cellindex.html
2284
+ computeColumnIndex : function( $rows, c ) {
2285
+ var i, j, k, l, cell, cells, rowIndex, rowSpan, colSpan, firstAvailCol,
2286
+ // total columns has been calculated, use it to set the matrixrow
2287
+ columns = c && c.columns || 0,
2288
+ matrix = [],
2289
+ matrixrow = new Array( columns );
2290
+ for ( i = 0; i < $rows.length; i++ ) {
2291
+ cells = $rows[ i ].cells;
2292
+ for ( j = 0; j < cells.length; j++ ) {
2293
+ cell = cells[ j ];
2294
+ rowIndex = i;
2295
+ rowSpan = cell.rowSpan || 1;
2296
+ colSpan = cell.colSpan || 1;
2297
+ if ( typeof matrix[ rowIndex ] === 'undefined' ) {
2298
+ matrix[ rowIndex ] = [];
2299
+ }
2300
+ // Find first available column in the first row
2301
+ for ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {
2302
+ if ( typeof matrix[ rowIndex ][ k ] === 'undefined' ) {
2303
+ firstAvailCol = k;
2304
+ break;
2305
+ }
2306
+ }
2307
+ // jscs:disable disallowEmptyBlocks
2308
+ if ( columns && cell.cellIndex === firstAvailCol ) {
2309
+ // don't to anything
2310
+ } else if ( cell.setAttribute ) {
2311
+ // jscs:enable disallowEmptyBlocks
2312
+ // add data-column (setAttribute = IE8+)
2313
+ cell.setAttribute( 'data-column', firstAvailCol );
2314
+ } else {
2315
+ // remove once we drop support for IE7 - 1/12/2016
2316
+ $( cell ).attr( 'data-column', firstAvailCol );
2317
+ }
2318
+ for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {
2319
+ if ( typeof matrix[ k ] === 'undefined' ) {
2320
+ matrix[ k ] = [];
2321
+ }
2322
+ matrixrow = matrix[ k ];
2323
+ for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
2324
+ matrixrow[ l ] = 'x';
2325
+ }
2326
+ }
2327
+ }
2328
+ }
2329
+ ts.checkColumnCount($rows, matrix, matrixrow.length);
2330
+ return matrixrow.length;
2331
+ },
2332
+
2333
+ checkColumnCount : function($rows, matrix, columns) {
2334
+ // this DOES NOT report any tbody column issues, except for the math and
2335
+ // and column selector widgets
2336
+ var i, len,
2337
+ valid = true,
2338
+ cells = [];
2339
+ for ( i = 0; i < matrix.length; i++ ) {
2340
+ // some matrix entries are undefined when testing the footer because
2341
+ // it is using the rowIndex property
2342
+ if ( matrix[i] ) {
2343
+ len = matrix[i].length;
2344
+ if ( matrix[i].length !== columns ) {
2345
+ valid = false;
2346
+ break;
2347
+ }
2348
+ }
2349
+ }
2350
+ if ( !valid ) {
2351
+ $rows.each( function( indx, el ) {
2352
+ var cell = el.parentElement.nodeName;
2353
+ if ( cells.indexOf( cell ) < 0 ) {
2354
+ cells.push( cell );
2355
+ }
2356
+ });
2357
+ console.error(
2358
+ 'Invalid or incorrect number of columns in the ' +
2359
+ cells.join( ' or ' ) + '; expected ' + columns +
2360
+ ', but found ' + len + ' columns'
2361
+ );
2362
+ }
2363
+ },
2364
+
2365
+ // automatically add a colgroup with col elements set to a percentage width
2366
+ fixColumnWidth : function( table ) {
2367
+ table = $( table )[ 0 ];
2368
+ var overallWidth, percent, $tbodies, len, index,
2369
+ c = table.config,
2370
+ $colgroup = c.$table.children( 'colgroup' );
2371
+ // remove plugin-added colgroup, in case we need to refresh the widths
2372
+ if ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {
2373
+ $colgroup.remove();
2374
+ }
2375
+ if ( c.widthFixed && c.$table.children( 'colgroup' ).length === 0 ) {
2376
+ $colgroup = $( '<colgroup class="' + ts.css.colgroup + '">' );
2377
+ overallWidth = c.$table.width();
2378
+ // only add col for visible columns - fixes #371
2379
+ $tbodies = c.$tbodies.find( 'tr:first' ).children( ':visible' );
2380
+ len = $tbodies.length;
2381
+ for ( index = 0; index < len; index++ ) {
2382
+ percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
2383
+ $colgroup.append( $( '<col>' ).css( 'width', percent ) );
2384
+ }
2385
+ c.$table.prepend( $colgroup );
2386
+ }
2387
+ },
2388
+
2389
+ // get sorter, string, empty, etc options for each column from
2390
+ // jQuery data, metadata, header option or header class name ('sorter-false')
2391
+ // priority = jQuery data > meta > headers option > header class name
2392
+ getData : function( header, configHeader, key ) {
2393
+ var meta, cl4ss,
2394
+ val = '',
2395
+ $header = $( header );
2396
+ if ( !$header.length ) { return ''; }
2397
+ meta = $.metadata ? $header.metadata() : false;
2398
+ cl4ss = ' ' + ( $header.attr( 'class' ) || '' );
2399
+ if ( typeof $header.data( key ) !== 'undefined' ||
2400
+ typeof $header.data( key.toLowerCase() ) !== 'undefined' ) {
2401
+ // 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
2402
+ // 'data-sort-initial-order' is assigned to 'sortInitialOrder'
2403
+ val += $header.data( key ) || $header.data( key.toLowerCase() );
2404
+ } else if ( meta && typeof meta[ key ] !== 'undefined' ) {
2405
+ val += meta[ key ];
2406
+ } else if ( configHeader && typeof configHeader[ key ] !== 'undefined' ) {
2407
+ val += configHeader[ key ];
2408
+ } else if ( cl4ss !== ' ' && cl4ss.match( ' ' + key + '-' ) ) {
2409
+ // include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
2410
+ val = cl4ss.match( new RegExp( '\\s' + key + '-([\\w-]+)' ) )[ 1 ] || '';
2411
+ }
2412
+ return $.trim( val );
2413
+ },
2414
+
2415
+ getColumnData : function( table, obj, indx, getCell, $headers ) {
2416
+ if ( typeof obj !== 'object' || obj === null ) {
2417
+ return obj;
2418
+ }
2419
+ table = $( table )[ 0 ];
2420
+ var $header, key,
2421
+ c = table.config,
2422
+ $cells = ( $headers || c.$headers ),
2423
+ // c.$headerIndexed is not defined initially
2424
+ $cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||
2425
+ $cells.find( '[data-column="' + indx + '"]:last' );
2426
+ if ( typeof obj[ indx ] !== 'undefined' ) {
2427
+ return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];
2428
+ }
2429
+ for ( key in obj ) {
2430
+ if ( typeof key === 'string' ) {
2431
+ $header = $cell
2432
+ // header cell with class/id
2433
+ .filter( key )
2434
+ // find elements within the header cell with cell/id
2435
+ .add( $cell.find( key ) );
2436
+ if ( $header.length ) {
2437
+ return obj[ key ];
2438
+ }
2439
+ }
2440
+ }
2441
+ return;
2442
+ },
2443
+
2444
+ // *** Process table ***
2445
+ // add processing indicator
2446
+ isProcessing : function( $table, toggle, $headers ) {
2447
+ $table = $( $table );
2448
+ var c = $table[ 0 ].config,
2449
+ // default to all headers
2450
+ $header = $headers || $table.find( '.' + ts.css.header );
2451
+ if ( toggle ) {
2452
+ // don't use sortList if custom $headers used
2453
+ if ( typeof $headers !== 'undefined' && c.sortList.length > 0 ) {
2454
+ // get headers from the sortList
2455
+ $header = $header.filter( function() {
2456
+ // get data-column from attr to keep compatibility with jQuery 1.2.6
2457
+ return this.sortDisabled ?
2458
+ false :
2459
+ ts.isValueInArray( parseFloat( $( this ).attr( 'data-column' ) ), c.sortList ) >= 0;
2460
+ });
2461
+ }
2462
+ $table.add( $header ).addClass( ts.css.processing + ' ' + c.cssProcessing );
2463
+ } else {
2464
+ $table.add( $header ).removeClass( ts.css.processing + ' ' + c.cssProcessing );
2465
+ }
2466
+ },
2467
+
2468
+ // detach tbody but save the position
2469
+ // don't use tbody because there are portions that look for a tbody index (updateCell)
2470
+ processTbody : function( table, $tb, getIt ) {
2471
+ table = $( table )[ 0 ];
2472
+ if ( getIt ) {
2473
+ table.isProcessing = true;
2474
+ $tb.before( '<colgroup class="tablesorter-savemyplace"/>' );
2475
+ return $.fn.detach ? $tb.detach() : $tb.remove();
2476
+ }
2477
+ var holdr = $( table ).find( 'colgroup.tablesorter-savemyplace' );
2478
+ $tb.insertAfter( holdr );
2479
+ holdr.remove();
2480
+ table.isProcessing = false;
2481
+ },
2482
+
2483
+ clearTableBody : function( table ) {
2484
+ $( table )[ 0 ].config.$tbodies.children().detach();
2485
+ },
2486
+
2487
+ // used when replacing accented characters during sorting
2488
+ characterEquivalents : {
2489
+ 'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
2490
+ 'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
2491
+ 'c' : '\u00e7\u0107\u010d', // çćč
2492
+ 'C' : '\u00c7\u0106\u010c', // ÇĆČ
2493
+ 'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
2494
+ 'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
2495
+ 'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
2496
+ 'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
2497
+ 'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
2498
+ 'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
2499
+ 'ss': '\u00df', // ß (s sharp)
2500
+ 'SS': '\u1e9e', // ẞ (Capital sharp s)
2501
+ 'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
2502
+ 'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
2503
+ },
2504
+
2505
+ replaceAccents : function( str ) {
2506
+ var chr,
2507
+ acc = '[',
2508
+ eq = ts.characterEquivalents;
2509
+ if ( !ts.characterRegex ) {
2510
+ ts.characterRegexArray = {};
2511
+ for ( chr in eq ) {
2512
+ if ( typeof chr === 'string' ) {
2513
+ acc += eq[ chr ];
2514
+ ts.characterRegexArray[ chr ] = new RegExp( '[' + eq[ chr ] + ']', 'g' );
2515
+ }
2516
+ }
2517
+ ts.characterRegex = new RegExp( acc + ']' );
2518
+ }
2519
+ if ( ts.characterRegex.test( str ) ) {
2520
+ for ( chr in eq ) {
2521
+ if ( typeof chr === 'string' ) {
2522
+ str = str.replace( ts.characterRegexArray[ chr ], chr );
2523
+ }
2524
+ }
2525
+ }
2526
+ return str;
2527
+ },
2528
+
2529
+ validateOptions : function( c ) {
2530
+ var setting, setting2, typ, timer,
2531
+ // ignore options containing an array
2532
+ ignore = 'headers sortForce sortList sortAppend widgets'.split( ' ' ),
2533
+ orig = c.originalSettings;
2534
+ if ( orig ) {
2535
+ if ( ts.debug(c, 'core') ) {
2536
+ timer = new Date();
2537
+ }
2538
+ for ( setting in orig ) {
2539
+ typ = typeof ts.defaults[setting];
2540
+ if ( typ === 'undefined' ) {
2541
+ console.warn( 'Tablesorter Warning! "table.config.' + setting + '" option not recognized' );
2542
+ } else if ( typ === 'object' ) {
2543
+ for ( setting2 in orig[setting] ) {
2544
+ typ = ts.defaults[setting] && typeof ts.defaults[setting][setting2];
2545
+ if ( $.inArray( setting, ignore ) < 0 && typ === 'undefined' ) {
2546
+ console.warn( 'Tablesorter Warning! "table.config.' + setting + '.' + setting2 + '" option not recognized' );
2547
+ }
2548
+ }
2549
+ }
2550
+ }
2551
+ if ( ts.debug(c, 'core') ) {
2552
+ console.log( 'validate options time:' + ts.benchmark( timer ) );
2553
+ }
2554
+ }
2555
+ },
2556
+
2557
+ // restore headers
2558
+ restoreHeaders : function( table ) {
2559
+ var index, $cell,
2560
+ c = $( table )[ 0 ].config,
2561
+ $headers = c.$table.find( c.selectorHeaders ),
2562
+ len = $headers.length;
2563
+ // don't use c.$headers here in case header cells were swapped
2564
+ for ( index = 0; index < len; index++ ) {
2565
+ $cell = $headers.eq( index );
2566
+ // only restore header cells if it is wrapped
2567
+ // because this is also used by the updateAll method
2568
+ if ( $cell.find( '.' + ts.css.headerIn ).length ) {
2569
+ $cell.html( c.headerContent[ index ] );
2570
+ }
2571
+ }
2572
+ },
2573
+
2574
+ destroy : function( table, removeClasses, callback ) {
2575
+ table = $( table )[ 0 ];
2576
+ if ( !table.hasInitialized ) { return; }
2577
+ // remove all widgets
2578
+ ts.removeWidget( table, true, false );
2579
+ var events,
2580
+ $t = $( table ),
2581
+ c = table.config,
2582
+ $h = $t.find( 'thead:first' ),
2583
+ $r = $h.find( 'tr.' + ts.css.headerRow ).removeClass( ts.css.headerRow + ' ' + c.cssHeaderRow ),
2584
+ $f = $t.find( 'tfoot:first > tr' ).children( 'th, td' );
2585
+ if ( removeClasses === false && $.inArray( 'uitheme', c.widgets ) >= 0 ) {
2586
+ // reapply uitheme classes, in case we want to maintain appearance
2587
+ $t.triggerHandler( 'applyWidgetId', [ 'uitheme' ] );
2588
+ $t.triggerHandler( 'applyWidgetId', [ 'zebra' ] );
2589
+ }
2590
+ // remove widget added rows, just in case
2591
+ $h.find( 'tr' ).not( $r ).remove();
2592
+ // disable tablesorter - not using .unbind( namespace ) because namespacing was
2593
+ // added in jQuery v1.4.3 - see http://api.jquery.com/event.namespace/
2594
+ events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
2595
+ 'appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave ' +
2596
+ 'keypress sortBegin sortEnd resetToLoadState '.split( ' ' )
2597
+ .join( c.namespace + ' ' );
2598
+ $t
2599
+ .removeData( 'tablesorter' )
2600
+ .unbind( events.replace( ts.regex.spaces, ' ' ) );
2601
+ c.$headers
2602
+ .add( $f )
2603
+ .removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( ' ' ) )
2604
+ .removeAttr( 'data-column' )
2605
+ .removeAttr( 'aria-label' )
2606
+ .attr( 'aria-disabled', 'true' );
2607
+ $r
2608
+ .find( c.selectorSort )
2609
+ .unbind( ( 'mousedown mouseup keypress '.split( ' ' ).join( c.namespace + ' ' ) ).replace( ts.regex.spaces, ' ' ) );
2610
+ ts.restoreHeaders( table );
2611
+ $t.toggleClass( ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false );
2612
+ $t.removeClass(c.namespace.slice(1));
2613
+ // clear flag in case the plugin is initialized again
2614
+ table.hasInitialized = false;
2615
+ delete table.config.cache;
2616
+ if ( typeof callback === 'function' ) {
2617
+ callback( table );
2618
+ }
2619
+ if ( ts.debug(c, 'core') ) {
2620
+ console.log( 'tablesorter has been removed' );
2621
+ }
2622
+ }
2623
+
2624
+ };
2625
+
2626
+ $.fn.tablesorter = function( settings ) {
2627
+ return this.each( function() {
2628
+ var table = this,
2629
+ // merge & extend config options
2630
+ c = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );
2631
+ // save initial settings
2632
+ c.originalSettings = settings;
2633
+ // create a table from data (build table widget)
2634
+ if ( !table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE' ) {
2635
+ // return the table (in case the original target is the table's container)
2636
+ ts.buildTable( table, c );
2637
+ } else {
2638
+ ts.setup( table, c );
2639
+ }
2640
+ });
2641
+ };
2642
+
2643
+ // set up debug logs
2644
+ if ( !( window.console && window.console.log ) ) {
2645
+ // access $.tablesorter.logs for browsers that don't have a console...
2646
+ ts.logs = [];
2647
+ /*jshint -W020 */
2648
+ console = {};
2649
+ console.log = console.warn = console.error = console.table = function() {
2650
+ var arg = arguments.length > 1 ? arguments : arguments[0];
2651
+ ts.logs[ ts.logs.length ] = { date: Date.now(), log: arg };
2652
+ };
2653
+ }
2654
+
2655
+ // add default parsers
2656
+ ts.addParser({
2657
+ id : 'no-parser',
2658
+ is : function() {
2659
+ return false;
2660
+ },
2661
+ format : function() {
2662
+ return '';
2663
+ },
2664
+ type : 'text'
2665
+ });
2666
+
2667
+ ts.addParser({
2668
+ id : 'text',
2669
+ is : function() {
2670
+ return true;
2671
+ },
2672
+ format : function( str, table ) {
2673
+ var c = table.config;
2674
+ if ( str ) {
2675
+ str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );
2676
+ str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;
2677
+ }
2678
+ return str;
2679
+ },
2680
+ type : 'text'
2681
+ });
2682
+
2683
+ ts.regex.nondigit = /[^\w,. \-()]/g;
2684
+ ts.addParser({
2685
+ id : 'digit',
2686
+ is : function( str ) {
2687
+ return ts.isDigit( str );
2688
+ },
2689
+ format : function( str, table ) {
2690
+ var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
2691
+ return str && typeof num === 'number' ? num :
2692
+ str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
2693
+ },
2694
+ type : 'numeric'
2695
+ });
2696
+
2697
+ ts.regex.currencyReplace = /[+\-,. ]/g;
2698
+ ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
2699
+ ts.addParser({
2700
+ id : 'currency',
2701
+ is : function( str ) {
2702
+ str = ( str || '' ).replace( ts.regex.currencyReplace, '' );
2703
+ // test for £$€¤¥¢
2704
+ return ts.regex.currencyTest.test( str );
2705
+ },
2706
+ format : function( str, table ) {
2707
+ var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
2708
+ return str && typeof num === 'number' ? num :
2709
+ str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
2710
+ },
2711
+ type : 'numeric'
2712
+ });
2713
+
2714
+ // too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
2715
+ // now, this regex can be updated before initialization
2716
+ ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
2717
+ ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\/(www\.)?/;
2718
+ ts.addParser({
2719
+ id : 'url',
2720
+ is : function( str ) {
2721
+ return ts.regex.urlProtocolTest.test( str );
2722
+ },
2723
+ format : function( str ) {
2724
+ return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, '' ) ) : str;
2725
+ },
2726
+ type : 'text'
2727
+ });
2728
+
2729
+ ts.regex.dash = /-/g;
2730
+ ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
2731
+ ts.addParser({
2732
+ id : 'isoDate',
2733
+ is : function( str ) {
2734
+ return ts.regex.isoDate.test( str );
2735
+ },
2736
+ format : function( str ) {
2737
+ var date = str ? new Date( str.replace( ts.regex.dash, '/' ) ) : str;
2738
+ return date instanceof Date && isFinite( date ) ? date.getTime() : str;
2739
+ },
2740
+ type : 'numeric'
2741
+ });
2742
+
2743
+ ts.regex.percent = /%/g;
2744
+ ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
2745
+ ts.addParser({
2746
+ id : 'percent',
2747
+ is : function( str ) {
2748
+ return ts.regex.percentTest.test( str ) && str.length < 15;
2749
+ },
2750
+ format : function( str, table ) {
2751
+ return str ? ts.formatFloat( str.replace( ts.regex.percent, '' ), table ) : str;
2752
+ },
2753
+ type : 'numeric'
2754
+ });
2755
+
2756
+ // added image parser to core v2.17.9
2757
+ ts.addParser({
2758
+ id : 'image',
2759
+ is : function( str, table, node, $node ) {
2760
+ return $node.find( 'img' ).length > 0;
2761
+ },
2762
+ format : function( str, table, cell ) {
2763
+ return $( cell ).find( 'img' ).attr( table.config.imgAttr || 'alt' ) || str;
2764
+ },
2765
+ parsed : true, // filter widget flag
2766
+ type : 'text'
2767
+ });
2768
+
2769
+ ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
2770
+ ts.regex.usLongDateTest1 = /^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i;
2771
+ ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
2772
+ ts.addParser({
2773
+ id : 'usLongDate',
2774
+ is : function( str ) {
2775
+ // two digit years are not allowed cross-browser
2776
+ // Jan 01, 2013 12:34:56 PM or 01 Jan 2013
2777
+ return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );
2778
+ },
2779
+ format : function( str ) {
2780
+ var date = str ? new Date( str.replace( ts.regex.dateReplace, '$1 $2' ) ) : str;
2781
+ return date instanceof Date && isFinite( date ) ? date.getTime() : str;
2782
+ },
2783
+ type : 'numeric'
2784
+ });
2785
+
2786
+ // testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
2787
+ ts.regex.shortDateTest = /(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/;
2788
+ // escaped "-" because JSHint in Firefox was showing it as an error
2789
+ ts.regex.shortDateReplace = /[\-.,]/g;
2790
+ // XXY covers MDY & DMY formats
2791
+ ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
2792
+ ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
2793
+ ts.convertFormat = function( dateString, format ) {
2794
+ dateString = ( dateString || '' )
2795
+ .replace( ts.regex.spaces, ' ' )
2796
+ .replace( ts.regex.shortDateReplace, '/' );
2797
+ if ( format === 'mmddyyyy' ) {
2798
+ dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$1/$2' );
2799
+ } else if ( format === 'ddmmyyyy' ) {
2800
+ dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$2/$1' );
2801
+ } else if ( format === 'yyyymmdd' ) {
2802
+ dateString = dateString.replace( ts.regex.shortDateYMD, '$1/$2/$3' );
2803
+ }
2804
+ var date = new Date( dateString );
2805
+ return date instanceof Date && isFinite( date ) ? date.getTime() : '';
2806
+ };
2807
+
2808
+ ts.addParser({
2809
+ id : 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
2810
+ is : function( str ) {
2811
+ str = ( str || '' ).replace( ts.regex.spaces, ' ' ).replace( ts.regex.shortDateReplace, '/' );
2812
+ return ts.regex.shortDateTest.test( str );
2813
+ },
2814
+ format : function( str, table, cell, cellIndex ) {
2815
+ if ( str ) {
2816
+ var c = table.config,
2817
+ $header = c.$headerIndexed[ cellIndex ],
2818
+ format = $header.length && $header.data( 'dateFormat' ) ||
2819
+ ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat' ) ||
2820
+ c.dateFormat;
2821
+ // save format because getData can be slow...
2822
+ if ( $header.length ) {
2823
+ $header.data( 'dateFormat', format );
2824
+ }
2825
+ return ts.convertFormat( str, format ) || str;
2826
+ }
2827
+ return str;
2828
+ },
2829
+ type : 'numeric'
2830
+ });
2831
+
2832
+ // match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
2833
+ ts.regex.timeTest = /^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i;
2834
+ ts.regex.timeMatch = /(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;
2835
+ ts.addParser({
2836
+ id : 'time',
2837
+ is : function( str ) {
2838
+ return ts.regex.timeTest.test( str );
2839
+ },
2840
+ format : function( str ) {
2841
+ // isolate time... ignore month, day and year
2842
+ var temp,
2843
+ timePart = ( str || '' ).match( ts.regex.timeMatch ),
2844
+ orig = new Date( str ),
2845
+ // no time component? default to 00:00 by leaving it out, but only if str is defined
2846
+ time = str && ( timePart !== null ? timePart[ 0 ] : '00:00 AM' ),
2847
+ date = time ? new Date( '2000/01/01 ' + time.replace( ts.regex.dateReplace, '$1 $2' ) ) : time;
2848
+ if ( date instanceof Date && isFinite( date ) ) {
2849
+ temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;
2850
+ // if original string was a valid date, add it to the decimal so the column sorts in some kind of order
2851
+ // luckily new Date() ignores the decimals
2852
+ return temp ? parseFloat( date.getTime() + '.' + orig.getTime() ) : date.getTime();
2853
+ }
2854
+ return str;
2855
+ },
2856
+ type : 'numeric'
2857
+ });
2858
+
2859
+ ts.addParser({
2860
+ id : 'metadata',
2861
+ is : function() {
2862
+ return false;
2863
+ },
2864
+ format : function( str, table, cell ) {
2865
+ var c = table.config,
2866
+ p = ( !c.parserMetadataName ) ? 'sortValue' : c.parserMetadataName;
2867
+ return $( cell ).metadata()[ p ];
2868
+ },
2869
+ type : 'numeric'
2870
+ });
2871
+
2872
+ /*
2873
+ ██████ ██████ █████▄ █████▄ ▄████▄
2874
+ ▄█▀ ██▄▄ ██▄▄██ ██▄▄██ ██▄▄██
2875
+ ▄█▀ ██▀▀ ██▀▀██ ██▀▀█ ██▀▀██
2876
+ ██████ ██████ █████▀ ██ ██ ██ ██
2877
+ */
2878
+ // add default widgets
2879
+ ts.addWidget({
2880
+ id : 'zebra',
2881
+ priority : 90,
2882
+ format : function( table, c, wo ) {
2883
+ var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,
2884
+ child = new RegExp( c.cssChildRow, 'i' ),
2885
+ $tbodies = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
2886
+ for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
2887
+ // loop through the visible rows
2888
+ count = 0;
2889
+ $visibleRows = $tbodies.eq( tbodyIndex ).children( 'tr:visible' ).not( c.selectorRemove );
2890
+ len = $visibleRows.length;
2891
+ for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
2892
+ $row = $visibleRows.eq( rowIndex );
2893
+ // style child rows the same way the parent row was styled
2894
+ if ( !child.test( $row[ 0 ].className ) ) { count++; }
2895
+ isEven = ( count % 2 === 0 );
2896
+ $row
2897
+ .removeClass( wo.zebra[ isEven ? 1 : 0 ] )
2898
+ .addClass( wo.zebra[ isEven ? 0 : 1 ] );
2899
+ }
2900
+ }
2901
+ },
2902
+ remove : function( table, c, wo, refreshing ) {
2903
+ if ( refreshing ) { return; }
2904
+ var tbodyIndex, $tbody,
2905
+ $tbodies = c.$tbodies,
2906
+ toRemove = ( wo.zebra || [ 'even', 'odd' ] ).join( ' ' );
2907
+ for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
2908
+ $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
2909
+ $tbody.children().removeClass( toRemove );
2910
+ ts.processTbody( table, $tbody, false ); // restore tbody
2911
+ }
2912
+ }
2913
+ });
2914
+
2915
+ })( jQuery );
2916
+ return jQuery.tablesorter;}));
js/tablesorter/jquery.tablesorter.min.js CHANGED
@@ -1 +1 @@
1
- !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(A){"use strict";var L=A.tablesorter={version:"2.31.0",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssIconDisabled:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(t,r){if(t&&t.tHead&&0!==t.tBodies.length&&!0!==t.hasInitialized){var e,o="",s=A(t),a=A.metadata;t.hasInitialized=!1,t.isProcessing=!0,t.config=r,A.data(t,"tablesorter",r),L.debug(r,"core")&&(console[console.group?"group":"log"]("Initializing tablesorter v"+L.version),A.data(t,"startoveralltimer",new Date)),r.supportsDataObject=((e=A.fn.jquery.split("."))[0]=parseInt(e[0],10),1<e[0]||1===e[0]&&4<=parseInt(e[1],10)),r.emptyTo=r.emptyTo.toLowerCase(),r.stringTo=r.stringTo.toLowerCase(),r.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(s.attr("class"))||(o=""!==r.theme?" tablesorter-"+r.theme:""),r.namespace?r.namespace="."+r.namespace.replace(L.regex.nonWord,""):r.namespace=".tablesorter"+Math.random().toString(16).slice(2),r.table=t,r.$table=s.addClass(L.css.table+" "+r.tableClass+o+" "+r.namespace.slice(1)).attr("role","grid"),r.$headers=s.find(r.selectorHeaders),r.$table.children().children("tr").attr("role","row"),r.$tbodies=s.children("tbody:not(."+r.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),r.$table.children("caption").length&&((o=r.$table.children("caption")[0]).id||(o.id=r.namespace.slice(1)+"caption"),r.$table.attr("aria-labelledby",o.id)),r.widgetInit={},r.textExtraction=r.$table.attr("data-text-extraction")||r.textExtraction||"basic",L.buildHeaders(r),L.fixColumnWidth(t),L.addWidgetFromClass(t),L.applyWidgetOptions(t),L.setupParsers(r),r.totalRows=0,r.debug&&L.validateOptions(r),r.delayInit||L.buildCache(r),L.bindEvents(t,r.$headers,!0),L.bindMethods(r),r.supportsDataObject&&void 0!==s.data().sortlist?r.sortList=s.data().sortlist:a&&s.metadata()&&s.metadata().sortlist&&(r.sortList=s.metadata().sortlist),L.applyWidget(t,!0),0<r.sortList.length?L.sortOn(r,r.sortList,{},!r.initWidgets):(L.setHeadersCss(r),r.initWidgets&&L.applyWidget(t,!1)),r.showProcessing&&s.unbind("sortBegin"+r.namespace+" sortEnd"+r.namespace).bind("sortBegin"+r.namespace+" sortEnd"+r.namespace,function(e){clearTimeout(r.timerProcessing),L.isProcessing(t),"sortBegin"===e.type&&(r.timerProcessing=setTimeout(function(){L.isProcessing(t,!0)},500))}),t.hasInitialized=!0,t.isProcessing=!1,L.debug(r,"core")&&(console.log("Overall initialization time:"+L.benchmark(A.data(t,"startoveralltimer"))),L.debug(r,"core")&&console.groupEnd&&console.groupEnd()),s.triggerHandler("tablesorter-initialized",t),"function"==typeof r.initialized&&r.initialized(t)}else L.debug(r,"core")&&(t.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody",t))},bindMethods:function(r){var e=r.$table,t=r.namespace,o="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(t+" ");e.unbind(o.replace(L.regex.spaces," ")).bind("sortReset"+t,function(e,t){e.stopPropagation(),L.sortReset(this.config,function(e){e.isApplyingWidgets?setTimeout(function(){L.applyWidget(e,"",t)},100):L.applyWidget(e,"",t)})}).bind("updateAll"+t,function(e,t,r){e.stopPropagation(),L.updateAll(this.config,t,r)}).bind("update"+t+" updateRows"+t,function(e,t,r){e.stopPropagation(),L.update(this.config,t,r)}).bind("updateHeaders"+t,function(e,t){e.stopPropagation(),L.updateHeaders(this.config,t)}).bind("updateCell"+t,function(e,t,r,o){e.stopPropagation(),L.updateCell(this.config,t,r,o)}).bind("addRows"+t,function(e,t,r,o){e.stopPropagation(),L.addRows(this.config,t,r,o)}).bind("updateComplete"+t,function(){this.isUpdating=!1}).bind("sorton"+t,function(e,t,r,o){e.stopPropagation(),L.sortOn(this.config,t,r,o)}).bind("appendCache"+t,function(e,t,r){e.stopPropagation(),L.appendCache(this.config,r),A.isFunction(t)&&t(this)}).bind("updateCache"+t,function(e,t,r){e.stopPropagation(),L.updateCache(this.config,t,r)}).bind("applyWidgetId"+t,function(e,t){e.stopPropagation(),L.applyWidgetId(this,t)}).bind("applyWidgets"+t,function(e,t){e.stopPropagation(),L.applyWidget(this,!1,t)}).bind("refreshWidgets"+t,function(e,t,r){e.stopPropagation(),L.refreshWidgets(this,t,r)}).bind("removeWidget"+t,function(e,t,r){e.stopPropagation(),L.removeWidget(this,t,r)}).bind("destroy"+t,function(e,t,r){e.stopPropagation(),L.destroy(this,t,r)}).bind("resetToLoadState"+t,function(e){e.stopPropagation(),L.removeWidget(this,!0,!1);var t=A.extend(!0,{},r.originalSettings);(r=A.extend(!0,{},L.defaults,t)).originalSettings=t,this.hasInitialized=!1,L.setup(this,r)})},bindEvents:function(e,t,r){var o,i=(e=A(e)[0]).config,s=i.namespace,d=null;!0!==r&&(t.addClass(s.slice(1)+"_extra_headers"),(o=L.getClosest(t,"table")).length&&"TABLE"===o[0].nodeName&&o[0]!==e&&A(o[0]).addClass(s.slice(1)+"_extra_table")),o=(i.pointerDown+" "+i.pointerUp+" "+i.pointerClick+" sort keyup ").replace(L.regex.spaces," ").split(" ").join(s+" "),t.find(i.selectorSort).add(t.filter(i.selectorSort)).unbind(o).bind(o,function(e,t){var r,o,s,a=A(e.target),n=" "+e.type+" ";if(!(1!==(e.which||e.button)&&!n.match(" "+i.pointerClick+" | sort | keyup ")||" keyup "===n&&e.which!==L.keyCodes.enter||n.match(" "+i.pointerClick+" ")&&void 0!==e.which||n.match(" "+i.pointerUp+" ")&&d!==e.target&&!0!==t)){if(n.match(" "+i.pointerDown+" "))return d=e.target,void("1"===(s=a.jquery.split("."))[0]&&s[1]<4&&e.preventDefault());if(d=null,r=L.getClosest(A(this),"."+L.css.header),L.regex.formElements.test(e.target.nodeName)||a.hasClass(i.cssNoSort)||0<a.parents("."+i.cssNoSort).length||r.hasClass("sorter-false")||0<a.parents("button").length)return!i.cancelSelection;i.delayInit&&L.isEmptyObject(i.cache)&&L.buildCache(i),i.last.clickedIndex=r.attr("data-column")||r.index(),(o=i.$headerIndexed[i.last.clickedIndex][0])&&!o.sortDisabled&&L.initSort(i,o,e)}}),i.cancelSelection&&t.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(d){var e,l,t,r;for(d.headerList=[],d.headerContent=[],d.sortVars=[],L.debug(d,"core")&&(t=new Date),d.columns=L.computeColumnIndex(d.$table.children("thead, tfoot").children("tr")),l=d.cssIcon?'<i class="'+(d.cssIcon===L.css.icon?L.css.icon:d.cssIcon+" "+L.css.icon)+'"></i>':"",d.$headers=A(A.map(d.$table.find(d.selectorHeaders),function(e,t){var r,o,s,a,n,i=A(e);if(!L.getClosest(i,"tr").hasClass(d.cssIgnoreRow))return/(th|td)/i.test(e.nodeName)||(n=L.getClosest(i,"th, td"),i.attr("data-column",n.attr("data-column"))),r=L.getColumnData(d.table,d.headers,t,!0),d.headerContent[t]=i.html(),""===d.headerTemplate||i.find("."+L.css.headerIn).length||(a=d.headerTemplate.replace(L.regex.templateContent,i.html()).replace(L.regex.templateIcon,i.find("."+L.css.icon).length?"":l),d.onRenderTemplate&&(o=d.onRenderTemplate.apply(i,[t,a]))&&"string"==typeof o&&(a=o),i.html('<div class="'+L.css.headerIn+'">'+a+"</div>")),d.onRenderHeader&&d.onRenderHeader.apply(i,[t,d,d.$table]),s=parseInt(i.attr("data-column"),10),e.column=s,n=L.getOrder(L.getData(i,r,"sortInitialOrder")||d.sortInitialOrder),d.sortVars[s]={count:-1,order:n?d.sortReset?[1,0,2]:[1,0]:d.sortReset?[0,1,2]:[0,1],lockedOrder:!1,sortedBy:""},void 0!==(n=L.getData(i,r,"lockedOrder")||!1)&&!1!==n&&(d.sortVars[s].lockedOrder=!0,d.sortVars[s].order=L.getOrder(n)?[1,1]:[0,0]),d.headerList[t]=e,i.addClass(L.css.header+" "+d.cssHeader),L.getClosest(i,"tr").addClass(L.css.headerRow+" "+d.cssHeaderRow).attr("role","row"),d.tabIndex&&i.attr("tabindex",0),e})),d.$headerIndexed=[],r=0;r<d.columns;r++)L.isEmptyObject(d.sortVars[r])&&(d.sortVars[r]={}),e=d.$headers.filter('[data-column="'+r+'"]'),d.$headerIndexed[r]=e.length?e.not(".sorter-false").length?e.not(".sorter-false").filter(":last"):e.filter(":last"):A();d.$table.find(d.selectorHeaders).attr({scope:"col",role:"columnheader"}),L.updateHeader(d),L.debug(d,"core")&&(console.log("Built headers:"+L.benchmark(t)),console.log(d.$headers))},addInstanceMethods:function(e){A.extend(L.instanceMethods,e)},setupParsers:function(e,t){var r,o,s,a,n,i,d,l,c,g,p,u,f,h,m=e.table,b=0,y=L.debug(e,"core"),w={};if(e.$tbodies=e.$table.children("tbody:not(."+e.cssInfoBlock+")"),0===(h=(f=void 0===t?e.$tbodies:t).length))return y?console.warn("Warning: *Empty table!* Not building a parser cache"):"";for(y&&(u=new Date,console[console.group?"group":"log"]("Detecting parsers for each column")),o={extractors:[],parsers:[]};b<h;){if((r=f[b].rows).length)for(n=0,a=e.columns,i=0;i<a;i++){if((d=e.$headerIndexed[n])&&d.length&&(l=L.getColumnData(m,e.headers,n),p=L.getParserById(L.getData(d,l,"extractor")),g=L.getParserById(L.getData(d,l,"sorter")),c="false"===L.getData(d,l,"parser"),e.empties[n]=(L.getData(d,l,"empty")||e.emptyTo||(e.emptyToBottom?"bottom":"top")).toLowerCase(),e.strings[n]=(L.getData(d,l,"string")||e.stringTo||"max").toLowerCase(),c&&(g=L.getParserById("no-parser")),p||(p=!1),g||(g=L.detectParserForColumn(e,r,-1,n)),y&&(w["("+n+") "+d.text()]={parser:g.id,extractor:p?p.id:"none",string:e.strings[n],empty:e.empties[n]}),o.parsers[n]=g,o.extractors[n]=p,0<(s=d[0].colSpan-1)))for(n+=s,a+=s;0<s+1;)o.parsers[n-s]=g,o.extractors[n-s]=p,s--;n++}b+=o.parsers.length?h:1}y&&(L.isEmptyObject(w)?console.warn(" No parsers detected!"):console[console.table?"table":"log"](w),console.log("Completed detecting parsers"+L.benchmark(u)),console.groupEnd&&console.groupEnd()),e.parsers=o.parsers,e.extractors=o.extractors},addParser:function(e){var t,r=L.parsers.length,o=!0;for(t=0;t<r;t++)L.parsers[t].id.toLowerCase()===e.id.toLowerCase()&&(o=!1);o&&(L.parsers[L.parsers.length]=e)},getParserById:function(e){if("false"==e)return!1;var t,r=L.parsers.length;for(t=0;t<r;t++)if(L.parsers[t].id.toLowerCase()===e.toString().toLowerCase())return L.parsers[t];return!1},detectParserForColumn:function(e,t,r,o){for(var s,a,n,i=L.parsers.length,d=!1,l="",c=L.debug(e,"core"),g=!0;""===l&&g;)(n=t[++r])&&r<50?n.className.indexOf(L.cssIgnoreRow)<0&&(d=t[r].cells[o],l=L.getElementText(e,d,o),a=A(d),c&&console.log("Checking if value was empty on row "+r+", column: "+o+': "'+l+'"')):g=!1;for(;0<=--i;)if((s=L.parsers[i])&&"text"!==s.id&&s.is&&s.is(l,e.table,d,a))return s;return L.getParserById("text")},getElementText:function(e,t,r){if(!t)return"";var o,s=e.textExtraction||"",a=t.jquery?t:A(t);return"string"==typeof s?"basic"===s&&void 0!==(o=a.attr(e.textAttribute))?A.trim(o):A.trim(t.textContent||a.text()):"function"==typeof s?A.trim(s(a[0],e.table,r)):"function"==typeof(o=L.getColumnData(e.table,s,r))?A.trim(o(a[0],e.table,r)):A.trim(a[0].textContent||a.text())},getParsedText:function(e,t,r,o){void 0===o&&(o=L.getElementText(e,t,r));var s=""+o,a=e.parsers[r],n=e.extractors[r];return a&&(n&&"function"==typeof n.format&&(o=n.format(o,e.table,t,r)),s="no-parser"===a.id?"":a.format(""+o,e.table,t,r),e.ignoreCase&&"string"==typeof s&&(s=s.toLowerCase())),s},buildCache:function(e,t,r){var o,s,a,n,i,d,l,c,g,p,u,f,h,m,b,y,w,x,v,C,$,I,D=e.table,R=e.parsers,T=L.debug(e,"core");if(e.$tbodies=e.$table.children("tbody:not(."+e.cssInfoBlock+")"),l=void 0===r?e.$tbodies:r,e.cache={},e.totalRows=0,!R)return T?console.warn("Warning: *Empty table!* Not building a cache"):"";for(T&&(f=new Date),e.showProcessing&&L.isProcessing(D,!0),d=0;d<l.length;d++){for(y=[],o=e.cache[d]={normalized:[]},h=l[d]&&l[d].rows.length||0,n=0;n<h;++n)if(m={child:[],raw:[]},g=[],!(c=A(l[d].rows[n])).hasClass(e.selectorRemove.slice(1)))if(c.hasClass(e.cssChildRow)&&0!==n)for($=o.normalized.length-1,(b=o.normalized[$][e.columns]).$row=b.$row.add(c),c.prev().hasClass(e.cssChildRow)||c.prev().addClass(L.css.cssHasChild),p=c.children("th, td"),$=b.child.length,b.child[$]=[],x=0,C=e.columns,i=0;i<C;i++)(u=p[i])&&(b.child[$][i]=L.getParsedText(e,u,i),0<(w=p[i].colSpan-1)&&(x+=w,C+=w)),x++;else{for(m.$row=c,m.order=n,x=0,C=e.columns,i=0;i<C;++i){if((u=c[0].cells[i])&&x<e.columns&&(!(v=void 0!==R[x])&&T&&console.warn("No parser found for row: "+n+", column: "+i+'; cell containing: "'+A(u).text()+'"; does it have a header?'),s=L.getElementText(e,u,x),m.raw[x]=s,a=L.getParsedText(e,u,x,s),g[x]=a,v&&"numeric"===(R[x].type||"").toLowerCase()&&(y[x]=Math.max(Math.abs(a)||0,y[x]||0)),0<(w=u.colSpan-1))){for(I=0;I<=w;)a=e.duplicateSpan||0===I?s:"string"!=typeof e.textExtraction&&L.getElementText(e,u,x+I)||"",m.raw[x+I]=a,g[x+I]=a,I++;x+=w,C+=w}x++}g[e.columns]=m,o.normalized[o.normalized.length]=g}o.colMax=y,e.totalRows+=o.normalized.length}if(e.showProcessing&&L.isProcessing(D),T){for($=Math.min(5,e.cache[0].normalized.length),console[console.group?"group":"log"]("Building cache for "+e.totalRows+" rows (showing "+$+" rows in log) and "+e.columns+" columns"+L.benchmark(f)),s={},i=0;i<e.columns;i++)for(x=0;x<$;x++)s["row: "+x]||(s["row: "+x]={}),s["row: "+x][e.$headerIndexed[i].text()]=e.cache[0].normalized[x][i];console[console.table?"table":"log"](s),console.groupEnd&&console.groupEnd()}A.isFunction(t)&&t(D)},getColumnText:function(e,t,r,o){var s,a,n,i,d,l,c,g,p,u,f="function"==typeof r,h="all"===t,m={raw:[],parsed:[],$cell:[]},b=(e=A(e)[0]).config;if(!L.isEmptyObject(b)){for(d=b.$tbodies.length,s=0;s<d;s++)for(l=(n=b.cache[s].normalized).length,a=0;a<l;a++)i=n[a],o&&!i[b.columns].$row.is(o)||(u=!0,g=h?i.slice(0,b.columns):i[t],i=i[b.columns],c=h?i.raw:i.raw[t],p=h?i.$row.children():i.$row.children().eq(t),f&&(u=r({tbodyIndex:s,rowIndex:a,parsed:g,raw:c,$row:i.$row,$cell:p})),!1!==u&&(m.parsed[m.parsed.length]=g,m.raw[m.raw.length]=c,m.$cell[m.$cell.length]=p));return m}L.debug(b,"core")&&console.warn("No cache found - aborting getColumnText function!")},setHeadersCss:function(a){var e,t,r=a.sortList,o=r.length,s=L.css.sortNone+" "+a.cssNone,n=[L.css.sortAsc+" "+a.cssAsc,L.css.sortDesc+" "+a.cssDesc],i=[a.cssIconAsc,a.cssIconDesc,a.cssIconNone],d=["ascending","descending"],l=function(e,t){e.removeClass(s).addClass(n[t]).attr("aria-sort",d[t]).find("."+L.css.icon).removeClass(i[2]).addClass(i[t])},c=a.$table.find("tfoot tr").children("td, th").add(A(a.namespace+"_extra_headers")).removeClass(n.join(" ")),g=a.$headers.add(A("thead "+a.namespace+"_extra_headers")).removeClass(n.join(" ")).addClass(s).attr("aria-sort","none").find("."+L.css.icon).removeClass(i.join(" ")).end();for(g.not(".sorter-false").find("."+L.css.icon).addClass(i[2]),a.cssIconDisabled&&g.filter(".sorter-false").find("."+L.css.icon).addClass(a.cssIconDisabled),e=0;e<o;e++)if(2!==r[e][1]){if((g=(g=a.$headers.filter(function(e){for(var t=!0,r=a.$headers.eq(e),o=parseInt(r.attr("data-column"),10),s=o+L.getClosest(r,"th, td")[0].colSpan;o<s;o++)t=!!t&&(t||-1<L.isValueInArray(o,a.sortList));return t})).not(".sorter-false").filter('[data-column="'+r[e][0]+'"]'+(1===o?":last":""))).length)for(t=0;t<g.length;t++)g[t].sortDisabled||l(g.eq(t),r[e][1]);c.length&&l(c.filter('[data-column="'+r[e][0]+'"]'),r[e][1])}for(o=a.$headers.length,e=0;e<o;e++)L.setColumnAriaLabel(a,a.$headers.eq(e))},getClosest:function(e,t){return A.fn.closest?e.closest(t):e.is(t)?e:e.parents(t).filter(":first")},setColumnAriaLabel:function(e,t,r){if(t.length){var o=parseInt(t.attr("data-column"),10),s=e.sortVars[o],a=t.hasClass(L.css.sortAsc)?"sortAsc":t.hasClass(L.css.sortDesc)?"sortDesc":"sortNone",n=A.trim(t.text())+": "+L.language[a];t.hasClass("sorter-false")||!1===r?n+=L.language.sortDisabled:(a=(s.count+1)%s.order.length,r=s.order[a],n+=L.language[0===r?"nextAsc":1===r?"nextDesc":"nextNone"]),t.attr("aria-label",n),s.sortedBy?t.attr("data-sortedBy",s.sortedBy):t.removeAttr("data-sortedBy")}},updateHeader:function(e){var t,r,o,s,a=e.table,n=e.$headers.length;for(t=0;t<n;t++)o=e.$headers.eq(t),s=L.getColumnData(a,e.headers,t,!0),r="false"===L.getData(o,s,"sorter")||"false"===L.getData(o,s,"parser"),L.setColumnSort(e,o,r)},setColumnSort:function(e,t,r){var o=e.table.id;t[0].sortDisabled=r,t[r?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+r),e.tabIndex&&(r?t.removeAttr("tabindex"):t.attr("tabindex","0")),o&&(r?t.removeAttr("aria-controls"):t.attr("aria-controls",o))},updateHeaderSortCount:function(e,t){var r,o,s,a,n,i,d,l,c=t||e.sortList,g=c.length;for(e.sortList=[],a=0;a<g;a++)if(d=c[a],(r=parseInt(d[0],10))<e.columns){switch(e.sortVars[r].order||(l=L.getOrder(e.sortInitialOrder)?e.sortReset?[1,0,2]:[1,0]:e.sortReset?[0,1,2]:[0,1],e.sortVars[r].order=l,e.sortVars[r].count=0),l=e.sortVars[r].order,o=(o=(""+d[1]).match(/^(1|d|s|o|n)/))?o[0]:""){case"1":case"d":o=1;break;case"s":o=n||0;break;case"o":o=0===(i=l[(n||0)%l.length])?1:1===i?0:2;break;case"n":o=l[++e.sortVars[r].count%l.length];break;default:o=0}n=0===a?o:n,s=[r,parseInt(o,10)||0],e.sortList[e.sortList.length]=s,o=A.inArray(s[1],l),e.sortVars[r].count=0<=o?o:s[1]%l.length}},updateAll:function(e,t,r){var o=e.table;o.isUpdating=!0,L.refreshWidgets(o,!0,!0),L.buildHeaders(e),L.bindEvents(o,e.$headers,!0),L.bindMethods(e),L.commonUpdate(e,t,r)},update:function(e,t,r){e.table.isUpdating=!0,L.updateHeader(e),L.commonUpdate(e,t,r)},updateHeaders:function(e,t){e.table.isUpdating=!0,L.buildHeaders(e),L.bindEvents(e.table,e.$headers,!0),L.resortComplete(e,t)},updateCell:function(e,t,r,o){if(A(t).closest("tr").hasClass(e.cssChildRow))console.warn('Tablesorter Warning! "updateCell" for child row content has been disabled, use "update" instead');else{if(L.isEmptyObject(e.cache))return L.updateHeader(e),void L.commonUpdate(e,r,o);e.table.isUpdating=!0,e.$table.find(e.selectorRemove).remove();var s,a,n,i,d,l,c=e.$tbodies,g=A(t),p=c.index(L.getClosest(g,"tbody")),u=e.cache[p],f=L.getClosest(g,"tr");if(t=g[0],c.length&&0<=p){if(n=c.eq(p).find("tr").not("."+e.cssChildRow).index(f),d=u.normalized[n],(l=f[0].cells.length)!==e.columns)for(s=!1,a=i=0;a<l;a++)s||f[0].cells[a]===t?s=!0:i+=f[0].cells[a].colSpan;else i=g.index();s=L.getElementText(e,t,i),d[e.columns].raw[i]=s,s=L.getParsedText(e,t,i,s),d[i]=s,"numeric"===(e.parsers[i].type||"").toLowerCase()&&(u.colMax[i]=Math.max(Math.abs(s)||0,u.colMax[i]||0)),!1!==(s="undefined"!==r?r:e.resort)?L.checkResort(e,s,o):L.resortComplete(e,o)}else L.debug(e,"core")&&console.error("updateCell aborted, tbody missing or not within the indicated table"),e.table.isUpdating=!1}},addRows:function(e,t,r,o){var s,a,n,i,d,l,c,g,p,u,f,h,m,b="string"==typeof t&&1===e.$tbodies.length&&/<tr/.test(t||""),y=e.table;if(b)t=A(t),e.$tbodies.append(t);else if(!(t&&t instanceof A&&L.getClosest(t,"table")[0]===e.table))return L.debug(e,"core")&&console.error("addRows method requires (1) a jQuery selector reference to rows that have already been added to the table, or (2) row HTML string to be added to a table with only one tbody"),!1;if(y.isUpdating=!0,L.isEmptyObject(e.cache))L.updateHeader(e),L.commonUpdate(e,r,o);else{for(d=t.filter("tr").attr("role","row").length,n=e.$tbodies.index(t.parents("tbody").filter(":first")),e.parsers&&e.parsers.length||L.setupParsers(e),i=0;i<d;i++){for(p=0,c=t[i].cells.length,g=e.cache[n].normalized.length,f=[],u={child:[],raw:[],$row:t.eq(i),order:g},l=0;l<c;l++)h=t[i].cells[l],s=L.getElementText(e,h,p),u.raw[p]=s,a=L.getParsedText(e,h,p,s),f[p]=a,"numeric"===(e.parsers[p].type||"").toLowerCase()&&(e.cache[n].colMax[p]=Math.max(Math.abs(a)||0,e.cache[n].colMax[p]||0)),0<(m=h.colSpan-1)&&(p+=m),p++;f[e.columns]=u,e.cache[n].normalized[g]=f}L.checkResort(e,r,o)}},updateCache:function(e,t,r){e.parsers&&e.parsers.length||L.setupParsers(e,r),L.buildCache(e,t,r)},appendCache:function(e,t){var r,o,s,a,n,i,d,l=e.table,c=e.$tbodies,g=[],p=e.cache;if(L.isEmptyObject(p))return e.appender?e.appender(l,g):l.isUpdating?e.$table.triggerHandler("updateComplete",l):"";for(L.debug(e,"core")&&(d=new Date),i=0;i<c.length;i++)if((s=c.eq(i)).length){for(a=L.processTbody(l,s,!0),o=(r=p[i].normalized).length,n=0;n<o;n++)g[g.length]=r[n][e.columns].$row,e.appender&&(!e.pager||e.pager.removeRows||e.pager.ajax)||a.append(r[n][e.columns].$row);L.processTbody(l,a,!1)}e.appender&&e.appender(l,g),L.debug(e,"core")&&console.log("Rebuilt table"+L.benchmark(d)),t||e.appender||L.applyWidget(l),l.isUpdating&&e.$table.triggerHandler("updateComplete",l)},commonUpdate:function(e,t,r){e.$table.find(e.selectorRemove).remove(),L.setupParsers(e),L.buildCache(e),L.checkResort(e,t,r)},initSort:function(t,e,r){if(t.table.isUpdating)return setTimeout(function(){L.initSort(t,e,r)},50);var o,s,a,n,i,d,l,c=!r[t.sortMultiSortKey],g=t.table,p=t.$headers.length,u=L.getClosest(A(e),"th, td"),f=parseInt(u.attr("data-column"),10),h="mouseup"===r.type?"user":r.type,m=t.sortVars[f].order;if(u=u[0],t.$table.triggerHandler("sortStart",g),d=(t.sortVars[f].count+1)%m.length,t.sortVars[f].count=r[t.sortResetKey]?2:d,t.sortRestart)for(a=0;a<p;a++)l=t.$headers.eq(a),f!==(d=parseInt(l.attr("data-column"),10))&&(c||l.hasClass(L.css.sortNone))&&(t.sortVars[d].count=-1);if(c){if(A.each(t.sortVars,function(e){t.sortVars[e].sortedBy=""}),t.sortList=[],t.last.sortList=[],null!==t.sortForce)for(o=t.sortForce,s=0;s<o.length;s++)o[s][0]!==f&&(t.sortList[t.sortList.length]=o[s],t.sortVars[o[s][0]].sortedBy="sortForce");if((n=m[t.sortVars[f].count])<2&&(t.sortList[t.sortList.length]=[f,n],t.sortVars[f].sortedBy=h,1<u.colSpan))for(s=1;s<u.colSpan;s++)t.sortList[t.sortList.length]=[f+s,n],t.sortVars[f+s].count=A.inArray(n,m),t.sortVars[f+s].sortedBy=h}else if(t.sortList=A.extend([],t.last.sortList),0<=L.isValueInArray(f,t.sortList))for(t.sortVars[f].sortedBy=h,s=0;s<t.sortList.length;s++)(d=t.sortList[s])[0]===f&&(d[1]=m[t.sortVars[f].count],2===d[1]&&(t.sortList.splice(s,1),t.sortVars[f].count=-1));else if(n=m[t.sortVars[f].count],t.sortVars[f].sortedBy=h,n<2&&(t.sortList[t.sortList.length]=[f,n],1<u.colSpan))for(s=1;s<u.colSpan;s++)t.sortList[t.sortList.length]=[f+s,n],t.sortVars[f+s].count=A.inArray(n,m),t.sortVars[f+s].sortedBy=h;if(t.last.sortList=A.extend([],t.sortList),t.sortList.length&&t.sortAppend&&(o=A.isArray(t.sortAppend)?t.sortAppend:t.sortAppend[t.sortList[0][0]],!L.isEmptyObject(o)))for(s=0;s<o.length;s++)if(o[s][0]!==f&&L.isValueInArray(o[s][0],t.sortList)<0){if(i=(""+(n=o[s][1])).match(/^(a|d|s|o|n)/))switch(d=t.sortList[0][1],i[0]){case"d":n=1;break;case"s":n=d;break;case"o":n=0===d?1:0;break;case"n":n=(d+1)%m.length;break;default:n=0}t.sortList[t.sortList.length]=[o[s][0],n],t.sortVars[o[s][0]].sortedBy="sortAppend"}t.$table.triggerHandler("sortBegin",g),setTimeout(function(){L.setHeadersCss(t),L.multisort(t),L.appendCache(t),t.$table.triggerHandler("sortBeforeEnd",g),t.$table.triggerHandler("sortEnd",g)},1)},multisort:function(l){var e,t,c,r,g=l.table,p=[],u=0,f=l.textSorter||"",h=l.sortList,m=h.length,o=l.$tbodies.length;if(!l.serverSideSorting&&!L.isEmptyObject(l.cache)){if(L.debug(l,"core")&&(t=new Date),"object"==typeof f)for(c=l.columns;c--;)"function"==typeof(r=L.getColumnData(g,f,c))&&(p[c]=r);for(e=0;e<o;e++)c=l.cache[e].colMax,l.cache[e].normalized.sort(function(e,t){var r,o,s,a,n,i,d;for(r=0;r<m;r++){if(s=h[r][0],a=h[r][1],u=0===a,l.sortStable&&e[s]===t[s]&&1===m)return e[l.columns].order-t[l.columns].order;if((o=/n/i.test(L.getSortType(l.parsers,s)))&&l.strings[s]?(o="boolean"==typeof L.string[l.strings[s]]?(u?1:-1)*(L.string[l.strings[s]]?-1:1):l.strings[s]&&L.string[l.strings[s]]||0,n=l.numberSorter?l.numberSorter(e[s],t[s],u,c[s],g):L["sortNumeric"+(u?"Asc":"Desc")](e[s],t[s],o,c[s],s,l)):(i=u?e:t,d=u?t:e,n="function"==typeof f?f(i[s],d[s],u,s,g):"function"==typeof p[s]?p[s](i[s],d[s],u,s,g):L["sortNatural"+(u?"Asc":"Desc")](e[s]||"",t[s]||"",s,l)),n)return n}return e[l.columns].order-t[l.columns].order});L.debug(l,"core")&&console.log("Applying sort "+h.toString()+L.benchmark(t))}},resortComplete:function(e,t){e.table.isUpdating&&e.$table.triggerHandler("updateComplete",e.table),A.isFunction(t)&&t(e.table)},checkResort:function(e,t,r){var o=A.isArray(t)?t:e.sortList;!1===(void 0===t?e.resort:t)||e.serverSideSorting||e.table.isProcessing?(L.resortComplete(e,r),L.applyWidget(e.table,!1)):o.length?L.sortOn(e,o,function(){L.resortComplete(e,r)},!0):L.sortReset(e,function(){L.resortComplete(e,r),L.applyWidget(e.table,!1)})},sortOn:function(e,t,r,o){var s,a=e.table;for(e.$table.triggerHandler("sortStart",a),s=0;s<e.columns;s++)e.sortVars[s].sortedBy=-1<L.isValueInArray(s,t)?"sorton":"";L.updateHeaderSortCount(e,t),L.setHeadersCss(e),e.delayInit&&L.isEmptyObject(e.cache)&&L.buildCache(e),e.$table.triggerHandler("sortBegin",a),L.multisort(e),L.appendCache(e,o),e.$table.triggerHandler("sortBeforeEnd",a),e.$table.triggerHandler("sortEnd",a),L.applyWidget(a),A.isFunction(r)&&r(a)},sortReset:function(e,t){var r;for(e.sortList=[],r=0;r<e.columns;r++)e.sortVars[r].count=-1,e.sortVars[r].sortedBy="";L.setHeadersCss(e),L.multisort(e),L.appendCache(e),A.isFunction(t)&&t(e.table)},getSortType:function(e,t){return e&&e[t]&&e[t].type||""},getOrder:function(e){return/^d/i.test(e)||1===e},sortNatural:function(e,t){if(e===t)return 0;e=(e||"").toString(),t=(t||"").toString();var r,o,s,a,n,i,d=L.regex;if(d.hex.test(t)){if((r=parseInt(e.match(d.hex),16))<(o=parseInt(t.match(d.hex),16)))return-1;if(o<r)return 1}for(r=e.replace(d.chunk,"\\0$1\\0").replace(d.chunks,"").split("\\0"),o=t.replace(d.chunk,"\\0$1\\0").replace(d.chunks,"").split("\\0"),i=Math.max(r.length,o.length),n=0;n<i;n++){if(s=isNaN(r[n])?r[n]||0:parseFloat(r[n])||0,a=isNaN(o[n])?o[n]||0:parseFloat(o[n])||0,isNaN(s)!==isNaN(a))return isNaN(s)?1:-1;if(typeof s!=typeof a&&(s+="",a+=""),s<a)return-1;if(a<s)return 1}return 0},sortNaturalAsc:function(e,t,r,o){if(e===t)return 0;var s=L.string[o.empties[r]||o.emptyTo];return""===e&&0!==s?"boolean"==typeof s?s?-1:1:-s||-1:""===t&&0!==s?"boolean"==typeof s?s?1:-1:s||1:L.sortNatural(e,t)},sortNaturalDesc:function(e,t,r,o){if(e===t)return 0;var s=L.string[o.empties[r]||o.emptyTo];return""===e&&0!==s?"boolean"==typeof s?s?-1:1:s||1:""===t&&0!==s?"boolean"==typeof s?s?1:-1:-s||-1:L.sortNatural(t,e)},sortText:function(e,t){return t<e?1:e<t?-1:0},getTextValue:function(e,t,r){if(r){var o,s=e?e.length:0,a=r+t;for(o=0;o<s;o++)a+=e.charCodeAt(o);return t*a}return 0},sortNumericAsc:function(e,t,r,o,s,a){if(e===t)return 0;var n=L.string[a.empties[s]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:-n||-1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:n||1:(isNaN(e)&&(e=L.getTextValue(e,r,o)),isNaN(t)&&(t=L.getTextValue(t,r,o)),e-t)},sortNumericDesc:function(e,t,r,o,s,a){if(e===t)return 0;var n=L.string[a.empties[s]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:n||1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:-n||-1:(isNaN(e)&&(e=L.getTextValue(e,r,o)),isNaN(t)&&(t=L.getTextValue(t,r,o)),t-e)},sortNumeric:function(e,t){return e-t},addWidget:function(e){e.id&&!L.isEmptyObject(L.getWidgetById(e.id))&&console.warn('"'+e.id+'" widget was loaded more than once!'),L.widgets[L.widgets.length]=e},hasWidget:function(e,t){return(e=A(e)).length&&e[0].config&&e[0].config.widgetInit[t]||!1},getWidgetById:function(e){var t,r,o=L.widgets.length;for(t=0;t<o;t++)if((r=L.widgets[t])&&r.id&&r.id.toLowerCase()===e.toLowerCase())return r},applyWidgetOptions:function(e){var t,r,o,s=e.config,a=s.widgets.length;if(a)for(t=0;t<a;t++)(r=L.getWidgetById(s.widgets[t]))&&r.options&&(o=A.extend(!0,{},r.options),s.widgetOptions=A.extend(!0,o,s.widgetOptions),A.extend(!0,L.defaults.widgetOptions,r.options))},addWidgetFromClass:function(e){var t,r,o=e.config,s="^"+o.widgetClass.replace(L.regex.templateName,"(\\S+)+")+"$",a=new RegExp(s,"g"),n=(e.className||"").split(L.regex.spaces);if(n.length)for(t=n.length,r=0;r<t;r++)n[r].match(a)&&(o.widgets[o.widgets.length]=n[r].replace(a,"$1"))},applyWidgetId:function(e,t,r){var o,s,a,n=(e=A(e)[0]).config,i=n.widgetOptions,d=L.debug(n,"core"),l=L.getWidgetById(t);l&&(a=l.id,o=!1,A.inArray(a,n.widgets)<0&&(n.widgets[n.widgets.length]=a),d&&(s=new Date),!r&&n.widgetInit[a]||(n.widgetInit[a]=!0,e.hasInitialized&&L.applyWidgetOptions(e),"function"==typeof l.init&&(o=!0,d&&console[console.group?"group":"log"]("Initializing "+a+" widget"),l.init(e,l,n,i))),r||"function"!=typeof l.format||(o=!0,d&&console[console.group?"group":"log"]("Updating "+a+" widget"),l.format(e,n,i,!1)),d&&o&&(console.log("Completed "+(r?"initializing ":"applying ")+a+" widget"+L.benchmark(s)),console.groupEnd&&console.groupEnd()))},applyWidget:function(e,t,r){var o,s,a,n,i,d=(e=A(e)[0]).config,l=L.debug(d,"core"),c=[];if(!1===t||!e.hasInitialized||!e.isApplyingWidgets&&!e.isUpdating){if(l&&(i=new Date),L.addWidgetFromClass(e),clearTimeout(d.timerReady),d.widgets.length){for(e.isApplyingWidgets=!0,d.widgets=A.grep(d.widgets,function(e,t){return A.inArray(e,d.widgets)===t}),s=(a=d.widgets||[]).length,o=0;o<s;o++)(n=L.getWidgetById(a[o]))&&n.id?(n.priority||(n.priority=10),c[o]=n):l&&console.warn('"'+a[o]+'" was enabled, but the widget code has not been loaded!');for(c.sort(function(e,t){return e.priority<t.priority?-1:e.priority===t.priority?0:1}),s=c.length,l&&console[console.group?"group":"log"]("Start "+(t?"initializing":"applying")+" widgets"),o=0;o<s;o++)(n=c[o])&&n.id&&L.applyWidgetId(e,n.id,t);l&&console.groupEnd&&console.groupEnd()}d.timerReady=setTimeout(function(){e.isApplyingWidgets=!1,A.data(e,"lastWidgetApplication",new Date),d.$table.triggerHandler("tablesorter-ready"),t||"function"!=typeof r||r(e),l&&(n=d.widgets.length,console.log("Completed "+(!0===t?"initializing ":"applying ")+n+" widget"+(1!==n?"s":"")+L.benchmark(i)))},10)}},removeWidget:function(e,t,r){var o,s,a,n,i=(e=A(e)[0]).config;if(!0===t)for(t=[],n=L.widgets.length,a=0;a<n;a++)(s=L.widgets[a])&&s.id&&(t[t.length]=s.id);else t=(A.isArray(t)?t.join(","):t||"").toLowerCase().split(/[\s,]+/);for(n=t.length,o=0;o<n;o++)s=L.getWidgetById(t[o]),0<=(a=A.inArray(t[o],i.widgets))&&!0!==r&&i.widgets.splice(a,1),s&&s.remove&&(L.debug(i,"core")&&console.log((r?"Refreshing":"Removing")+' "'+t[o]+'" widget'),s.remove(e,i,i.widgetOptions,r),i.widgetInit[t[o]]=!1);i.$table.triggerHandler("widgetRemoveEnd",e)},refreshWidgets:function(e,t,r){var o,s,a=(e=A(e)[0]).config.widgets,n=L.widgets,i=n.length,d=[],l=function(e){A(e).triggerHandler("refreshComplete")};for(o=0;o<i;o++)(s=n[o])&&s.id&&(t||A.inArray(s.id,a)<0)&&(d[d.length]=s.id);L.removeWidget(e,d.join(","),!0),!0!==r?(L.applyWidget(e,t||!1,l),t&&L.applyWidget(e,!1,l)):l(e)},benchmark:function(e){return" ("+((new Date).getTime()-e.getTime())+" ms)"},log:function(){console.log(arguments)},debug:function(e,t){return e&&(!0===e.debug||"string"==typeof e.debug&&-1<e.debug.indexOf(t))},isEmptyObject:function(e){for(var t in e)return!1;return!0},isValueInArray:function(e,t){var r,o=t&&t.length||0;for(r=0;r<o;r++)if(t[r][0]===e)return r;return-1},formatFloat:function(e,t){return"string"!=typeof e||""===e?e:(e=(t&&t.config?!1!==t.config.usNumberFormat:void 0===t||t)?e.replace(L.regex.comma,""):e.replace(L.regex.digitNonUS,"").replace(L.regex.comma,"."),L.regex.digitNegativeTest.test(e)&&(e=e.replace(L.regex.digitNegativeReplace,"-$1")),r=parseFloat(e),isNaN(r)?A.trim(e):r);var r},isDigit:function(e){return isNaN(e)?L.regex.digitTest.test(e.toString().replace(L.regex.digitReplace,"")):""!==e},computeColumnIndex:function(e,t){var r,o,s,a,n,i,d,l,c,g,p=t&&t.columns||0,u=[],f=new Array(p);for(r=0;r<e.length;r++)for(i=e[r].cells,o=0;o<i.length;o++){for(d=r,l=(n=i[o]).rowSpan||1,c=n.colSpan||1,void 0===u[d]&&(u[d]=[]),s=0;s<u[d].length+1;s++)if(void 0===u[d][s]){g=s;break}for(p&&n.cellIndex===g||(n.setAttribute?n.setAttribute("data-column",g):A(n).attr("data-column",g)),s=d;s<d+l;s++)for(void 0===u[s]&&(u[s]=[]),f=u[s],a=g;a<g+c;a++)f[a]="x"}return L.checkColumnCount(e,u,f.length),f.length},checkColumnCount:function(e,t,r){var o,s,a=!0,n=[];for(o=0;o<t.length;o++)if(t[o]&&(s=t[o].length,t[o].length!==r)){a=!1;break}a||(e.each(function(e,t){var r=t.parentElement.nodeName;n.indexOf(r)<0&&n.push(r)}),console.error("Invalid or incorrect number of columns in the "+n.join(" or ")+"; expected "+r+", but found "+s+" columns"))},fixColumnWidth:function(e){var t,r,o,s,a,n=(e=A(e)[0]).config,i=n.$table.children("colgroup");if(i.length&&i.hasClass(L.css.colgroup)&&i.remove(),n.widthFixed&&0===n.$table.children("colgroup").length){for(i=A('<colgroup class="'+L.css.colgroup+'">'),t=n.$table.width(),s=(o=n.$tbodies.find("tr:first").children(":visible")).length,a=0;a<s;a++)r=parseInt(o.eq(a).width()/t*1e3,10)/10+"%",i.append(A("<col>").css("width",r));n.$table.prepend(i)}},getData:function(e,t,r){var o,s,a="",n=A(e);return n.length?(o=!!A.metadata&&n.metadata(),s=" "+(n.attr("class")||""),void 0!==n.data(r)||void 0!==n.data(r.toLowerCase())?a+=n.data(r)||n.data(r.toLowerCase()):o&&void 0!==o[r]?a+=o[r]:t&&void 0!==t[r]?a+=t[r]:" "!==s&&s.match(" "+r+"-")&&(a=s.match(new RegExp("\\s"+r+"-([\\w-]+)"))[1]||""),A.trim(a)):""},getColumnData:function(e,t,r,o,s){if("object"!=typeof t||null===t)return t;var a,n=(e=A(e)[0]).config,i=s||n.$headers,d=n.$headerIndexed&&n.$headerIndexed[r]||i.find('[data-column="'+r+'"]:last');if(void 0!==t[r])return o?t[r]:t[i.index(d)];for(a in t)if("string"==typeof a&&d.filter(a).add(d.find(a)).length)return t[a]},isProcessing:function(e,t,r){var o=(e=A(e))[0].config,s=r||e.find("."+L.css.header);t?(void 0!==r&&0<o.sortList.length&&(s=s.filter(function(){return!this.sortDisabled&&0<=L.isValueInArray(parseFloat(A(this).attr("data-column")),o.sortList)})),e.add(s).addClass(L.css.processing+" "+o.cssProcessing)):e.add(s).removeClass(L.css.processing+" "+o.cssProcessing)},processTbody:function(e,t,r){if(e=A(e)[0],r)return e.isProcessing=!0,t.before('<colgroup class="tablesorter-savemyplace"/>'),A.fn.detach?t.detach():t.remove();var o=A(e).find("colgroup.tablesorter-savemyplace");t.insertAfter(o),o.remove(),e.isProcessing=!1},clearTableBody:function(e){A(e)[0].config.$tbodies.children().detach()},characterEquivalents:{a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},replaceAccents:function(e){var t,r="[",o=L.characterEquivalents;if(!L.characterRegex){for(t in L.characterRegexArray={},o)"string"==typeof t&&(r+=o[t],L.characterRegexArray[t]=new RegExp("["+o[t]+"]","g"));L.characterRegex=new RegExp(r+"]")}if(L.characterRegex.test(e))for(t in o)"string"==typeof t&&(e=e.replace(L.characterRegexArray[t],t));return e},validateOptions:function(e){var t,r,o,s,a="headers sortForce sortList sortAppend widgets".split(" "),n=e.originalSettings;if(n){for(t in L.debug(e,"core")&&(s=new Date),n)if("undefined"===(o=typeof L.defaults[t]))console.warn('Tablesorter Warning! "table.config.'+t+'" option not recognized');else if("object"===o)for(r in n[t])o=L.defaults[t]&&typeof L.defaults[t][r],A.inArray(t,a)<0&&"undefined"===o&&console.warn('Tablesorter Warning! "table.config.'+t+"."+r+'" option not recognized');L.debug(e,"core")&&console.log("validate options time:"+L.benchmark(s))}},restoreHeaders:function(e){var t,r,o=A(e)[0].config,s=o.$table.find(o.selectorHeaders),a=s.length;for(t=0;t<a;t++)(r=s.eq(t)).find("."+L.css.headerIn).length&&r.html(o.headerContent[t])},destroy:function(e,t,r){if((e=A(e)[0]).hasInitialized){L.removeWidget(e,!0,!1);var o,s=A(e),a=e.config,n=s.find("thead:first"),i=n.find("tr."+L.css.headerRow).removeClass(L.css.headerRow+" "+a.cssHeaderRow),d=s.find("tfoot:first > tr").children("th, td");!1===t&&0<=A.inArray("uitheme",a.widgets)&&(s.triggerHandler("applyWidgetId",["uitheme"]),s.triggerHandler("applyWidgetId",["zebra"])),n.find("tr").not(i).remove(),o="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave "+"keypress sortBegin sortEnd resetToLoadState ".split(" ").join(a.namespace+" "),s.removeData("tablesorter").unbind(o.replace(L.regex.spaces," ")),a.$headers.add(d).removeClass([L.css.header,a.cssHeader,a.cssAsc,a.cssDesc,L.css.sortAsc,L.css.sortDesc,L.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),i.find(a.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(a.namespace+" ").replace(L.regex.spaces," ")),L.restoreHeaders(e),s.toggleClass(L.css.table+" "+a.tableClass+" tablesorter-"+a.theme,!1===t),s.removeClass(a.namespace.slice(1)),e.hasInitialized=!1,delete e.config.cache,"function"==typeof r&&r(e),L.debug(a,"core")&&console.log("tablesorter has been removed")}}};A.fn.tablesorter=function(t){return this.each(function(){var e=A.extend(!0,{},L.defaults,t,L.instanceMethods);e.originalSettings=t,!this.hasInitialized&&L.buildTable&&"TABLE"!==this.nodeName?L.buildTable(this,e):L.setup(this,e)})},window.console&&window.console.log||(L.logs=[],console={},console.log=console.warn=console.error=console.table=function(){var e=1<arguments.length?arguments:arguments[0];L.logs[L.logs.length]={date:Date.now(),log:e}}),L.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),L.addParser({id:"text",is:function(){return!0},format:function(e,t){var r=t.config;return e&&(e=A.trim(r.ignoreCase?e.toLocaleLowerCase():e),e=r.sortLocaleCompare?L.replaceAccents(e):e),e},type:"text"}),L.regex.nondigit=/[^\w,. \-()]/g,L.addParser({id:"digit",is:function(e){return L.isDigit(e)},format:function(e,t){var r=L.formatFloat((e||"").replace(L.regex.nondigit,""),t);return e&&"number"==typeof r?r:e?A.trim(e&&t.config.ignoreCase?e.toLocaleLowerCase():e):e},type:"numeric"}),L.regex.currencyReplace=/[+\-,. ]/g,L.regex.currencyTest=/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/,L.addParser({id:"currency",is:function(e){return e=(e||"").replace(L.regex.currencyReplace,""),L.regex.currencyTest.test(e)},format:function(e,t){var r=L.formatFloat((e||"").replace(L.regex.nondigit,""),t);return e&&"number"==typeof r?r:e?A.trim(e&&t.config.ignoreCase?e.toLocaleLowerCase():e):e},type:"numeric"}),L.regex.urlProtocolTest=/^(https?|ftp|file):\/\//,L.regex.urlProtocolReplace=/(https?|ftp|file):\/\/(www\.)?/,L.addParser({id:"url",is:function(e){return L.regex.urlProtocolTest.test(e)},format:function(e){return e?A.trim(e.replace(L.regex.urlProtocolReplace,"")):e},type:"text"}),L.regex.dash=/-/g,L.regex.isoDate=/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,L.addParser({id:"isoDate",is:function(e){return L.regex.isoDate.test(e)},format:function(e){var t=e?new Date(e.replace(L.regex.dash,"/")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),L.regex.percent=/%/g,L.regex.percentTest=/(\d\s*?%|%\s*?\d)/,L.addParser({id:"percent",is:function(e){return L.regex.percentTest.test(e)&&e.length<15},format:function(e,t){return e?L.formatFloat(e.replace(L.regex.percent,""),t):e},type:"numeric"}),L.addParser({id:"image",is:function(e,t,r,o){return 0<o.find("img").length},format:function(e,t,r){return A(r).find("img").attr(t.config.imgAttr||"alt")||e},parsed:!0,type:"text"}),L.regex.dateReplace=/(\S)([AP]M)$/i,L.regex.usLongDateTest1=/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i,L.regex.usLongDateTest2=/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i,L.addParser({id:"usLongDate",is:function(e){return L.regex.usLongDateTest1.test(e)||L.regex.usLongDateTest2.test(e)},format:function(e){var t=e?new Date(e.replace(L.regex.dateReplace,"$1 $2")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),L.regex.shortDateTest=/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/,L.regex.shortDateReplace=/[\-.,]/g,L.regex.shortDateXXY=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,L.regex.shortDateYMD=/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,L.convertFormat=function(e,t){e=(e||"").replace(L.regex.spaces," ").replace(L.regex.shortDateReplace,"/"),"mmddyyyy"===t?e=e.replace(L.regex.shortDateXXY,"$3/$1/$2"):"ddmmyyyy"===t?e=e.replace(L.regex.shortDateXXY,"$3/$2/$1"):"yyyymmdd"===t&&(e=e.replace(L.regex.shortDateYMD,"$1/$2/$3"));var r=new Date(e);return r instanceof Date&&isFinite(r)?r.getTime():""},L.addParser({id:"shortDate",is:function(e){return e=(e||"").replace(L.regex.spaces," ").replace(L.regex.shortDateReplace,"/"),L.regex.shortDateTest.test(e)},format:function(e,t,r,o){if(e){var s=t.config,a=s.$headerIndexed[o],n=a.length&&a.data("dateFormat")||L.getData(a,L.getColumnData(t,s.headers,o),"dateFormat")||s.dateFormat;return a.length&&a.data("dateFormat",n),L.convertFormat(e,n)||e}return e},type:"numeric"}),L.regex.timeTest=/^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i,L.regex.timeMatch=/(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i,L.addParser({id:"time",is:function(e){return L.regex.timeTest.test(e)},format:function(e){var t=(e||"").match(L.regex.timeMatch),r=new Date(e),o=e&&(null!==t?t[0]:"00:00 AM"),s=o?new Date("2000/01/01 "+o.replace(L.regex.dateReplace,"$1 $2")):o;return s instanceof Date&&isFinite(s)?(r instanceof Date&&isFinite(r)?r.getTime():0)?parseFloat(s.getTime()+"."+r.getTime()):s.getTime():e},type:"numeric"}),L.addParser({id:"metadata",is:function(){return!1},format:function(e,t,r){var o=t.config,s=o.parserMetadataName?o.parserMetadataName:"sortValue";return A(r).metadata()[s]},type:"numeric"}),L.addWidget({id:"zebra",priority:90,format:function(e,t,r){var o,s,a,n,i,d,l,c=new RegExp(t.cssChildRow,"i"),g=t.$tbodies.add(A(t.namespace+"_extra_table").children("tbody:not(."+t.cssInfoBlock+")"));for(i=0;i<g.length;i++)for(a=0,l=(o=g.eq(i).children("tr:visible").not(t.selectorRemove)).length,d=0;d<l;d++)s=o.eq(d),c.test(s[0].className)||a++,n=a%2==0,s.removeClass(r.zebra[n?1:0]).addClass(r.zebra[n?0:1])},remove:function(e,t,r,o){if(!o){var s,a,n=t.$tbodies,i=(r.zebra||["even","odd"]).join(" ");for(s=0;s<n.length;s++)(a=L.processTbody(e,n.eq(s),!0)).children().removeClass(i),L.processTbody(e,a,!1)}}})}(e),e.tablesorter});
1
+ !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(A){"use strict";var L=A.tablesorter={version:"2.31.1",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",cssIconDisabled:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(t,r){if(t&&t.tHead&&0!==t.tBodies.length&&!0!==t.hasInitialized){var e,o="",s=A(t),a=A.metadata;t.hasInitialized=!1,t.isProcessing=!0,t.config=r,A.data(t,"tablesorter",r),L.debug(r,"core")&&(console[console.group?"group":"log"]("Initializing tablesorter v"+L.version),A.data(t,"startoveralltimer",new Date)),r.supportsDataObject=((e=A.fn.jquery.split("."))[0]=parseInt(e[0],10),1<e[0]||1===e[0]&&4<=parseInt(e[1],10)),r.emptyTo=r.emptyTo.toLowerCase(),r.stringTo=r.stringTo.toLowerCase(),r.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(s.attr("class"))||(o=""!==r.theme?" tablesorter-"+r.theme:""),r.namespace?r.namespace="."+r.namespace.replace(L.regex.nonWord,""):r.namespace=".tablesorter"+Math.random().toString(16).slice(2),r.table=t,r.$table=s.addClass(L.css.table+" "+r.tableClass+o+" "+r.namespace.slice(1)).attr("role","grid"),r.$headers=s.find(r.selectorHeaders),r.$table.children().children("tr").attr("role","row"),r.$tbodies=s.children("tbody:not(."+r.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),r.$table.children("caption").length&&((o=r.$table.children("caption")[0]).id||(o.id=r.namespace.slice(1)+"caption"),r.$table.attr("aria-labelledby",o.id)),r.widgetInit={},r.textExtraction=r.$table.attr("data-text-extraction")||r.textExtraction||"basic",L.buildHeaders(r),L.fixColumnWidth(t),L.addWidgetFromClass(t),L.applyWidgetOptions(t),L.setupParsers(r),r.totalRows=0,r.debug&&L.validateOptions(r),r.delayInit||L.buildCache(r),L.bindEvents(t,r.$headers,!0),L.bindMethods(r),r.supportsDataObject&&void 0!==s.data().sortlist?r.sortList=s.data().sortlist:a&&s.metadata()&&s.metadata().sortlist&&(r.sortList=s.metadata().sortlist),L.applyWidget(t,!0),0<r.sortList.length?(r.last.sortList=r.sortList,L.sortOn(r,r.sortList,{},!r.initWidgets)):(L.setHeadersCss(r),r.initWidgets&&L.applyWidget(t,!1)),r.showProcessing&&s.unbind("sortBegin"+r.namespace+" sortEnd"+r.namespace).bind("sortBegin"+r.namespace+" sortEnd"+r.namespace,function(e){clearTimeout(r.timerProcessing),L.isProcessing(t),"sortBegin"===e.type&&(r.timerProcessing=setTimeout(function(){L.isProcessing(t,!0)},500))}),t.hasInitialized=!0,t.isProcessing=!1,L.debug(r,"core")&&(console.log("Overall initialization time:"+L.benchmark(A.data(t,"startoveralltimer"))),L.debug(r,"core")&&console.groupEnd&&console.groupEnd()),s.triggerHandler("tablesorter-initialized",t),"function"==typeof r.initialized&&r.initialized(t)}else L.debug(r,"core")&&(t.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody",t))},bindMethods:function(r){var e=r.$table,t=r.namespace,o="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(t+" ");e.unbind(o.replace(L.regex.spaces," ")).bind("sortReset"+t,function(e,t){e.stopPropagation(),L.sortReset(this.config,function(e){e.isApplyingWidgets?setTimeout(function(){L.applyWidget(e,"",t)},100):L.applyWidget(e,"",t)})}).bind("updateAll"+t,function(e,t,r){e.stopPropagation(),L.updateAll(this.config,t,r)}).bind("update"+t+" updateRows"+t,function(e,t,r){e.stopPropagation(),L.update(this.config,t,r)}).bind("updateHeaders"+t,function(e,t){e.stopPropagation(),L.updateHeaders(this.config,t)}).bind("updateCell"+t,function(e,t,r,o){e.stopPropagation(),L.updateCell(this.config,t,r,o)}).bind("addRows"+t,function(e,t,r,o){e.stopPropagation(),L.addRows(this.config,t,r,o)}).bind("updateComplete"+t,function(){this.isUpdating=!1}).bind("sorton"+t,function(e,t,r,o){e.stopPropagation(),L.sortOn(this.config,t,r,o)}).bind("appendCache"+t,function(e,t,r){e.stopPropagation(),L.appendCache(this.config,r),A.isFunction(t)&&t(this)}).bind("updateCache"+t,function(e,t,r){e.stopPropagation(),L.updateCache(this.config,t,r)}).bind("applyWidgetId"+t,function(e,t){e.stopPropagation(),L.applyWidgetId(this,t)}).bind("applyWidgets"+t,function(e,t){e.stopPropagation(),L.applyWidget(this,!1,t)}).bind("refreshWidgets"+t,function(e,t,r){e.stopPropagation(),L.refreshWidgets(this,t,r)}).bind("removeWidget"+t,function(e,t,r){e.stopPropagation(),L.removeWidget(this,t,r)}).bind("destroy"+t,function(e,t,r){e.stopPropagation(),L.destroy(this,t,r)}).bind("resetToLoadState"+t,function(e){e.stopPropagation(),L.removeWidget(this,!0,!1);var t=A.extend(!0,{},r.originalSettings);(r=A.extend(!0,{},L.defaults,t)).originalSettings=t,this.hasInitialized=!1,L.setup(this,r)})},bindEvents:function(e,t,r){var o,i=(e=A(e)[0]).config,s=i.namespace,d=null;!0!==r&&(t.addClass(s.slice(1)+"_extra_headers"),(o=L.getClosest(t,"table")).length&&"TABLE"===o[0].nodeName&&o[0]!==e&&A(o[0]).addClass(s.slice(1)+"_extra_table")),o=(i.pointerDown+" "+i.pointerUp+" "+i.pointerClick+" sort keyup ").replace(L.regex.spaces," ").split(" ").join(s+" "),t.find(i.selectorSort).add(t.filter(i.selectorSort)).unbind(o).bind(o,function(e,t){var r,o,s,a=A(e.target),n=" "+e.type+" ";if(!(1!==(e.which||e.button)&&!n.match(" "+i.pointerClick+" | sort | keyup ")||" keyup "===n&&e.which!==L.keyCodes.enter||n.match(" "+i.pointerClick+" ")&&void 0!==e.which||n.match(" "+i.pointerUp+" ")&&d!==e.target&&!0!==t)){if(n.match(" "+i.pointerDown+" "))return d=e.target,void("1"===(s=a.jquery.split("."))[0]&&s[1]<4&&e.preventDefault());if(d=null,r=L.getClosest(A(this),"."+L.css.header),L.regex.formElements.test(e.target.nodeName)||a.hasClass(i.cssNoSort)||0<a.parents("."+i.cssNoSort).length||r.hasClass("sorter-false")||0<a.parents("button").length)return!i.cancelSelection;i.delayInit&&L.isEmptyObject(i.cache)&&L.buildCache(i),i.last.clickedIndex=r.attr("data-column")||r.index(),(o=i.$headerIndexed[i.last.clickedIndex][0])&&!o.sortDisabled&&L.initSort(i,o,e)}}),i.cancelSelection&&t.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(d){var e,l,t,r;for(d.headerList=[],d.headerContent=[],d.sortVars=[],L.debug(d,"core")&&(t=new Date),d.columns=L.computeColumnIndex(d.$table.children("thead, tfoot").children("tr")),l=d.cssIcon?'<i class="'+(d.cssIcon===L.css.icon?L.css.icon:d.cssIcon+" "+L.css.icon)+'"></i>':"",d.$headers=A(A.map(d.$table.find(d.selectorHeaders),function(e,t){var r,o,s,a,n,i=A(e);if(!L.getClosest(i,"tr").hasClass(d.cssIgnoreRow))return/(th|td)/i.test(e.nodeName)||(n=L.getClosest(i,"th, td"),i.attr("data-column",n.attr("data-column"))),r=L.getColumnData(d.table,d.headers,t,!0),d.headerContent[t]=i.html(),""===d.headerTemplate||i.find("."+L.css.headerIn).length||(a=d.headerTemplate.replace(L.regex.templateContent,i.html()).replace(L.regex.templateIcon,i.find("."+L.css.icon).length?"":l),d.onRenderTemplate&&(o=d.onRenderTemplate.apply(i,[t,a]))&&"string"==typeof o&&(a=o),i.html('<div class="'+L.css.headerIn+'">'+a+"</div>")),d.onRenderHeader&&d.onRenderHeader.apply(i,[t,d,d.$table]),s=parseInt(i.attr("data-column"),10),e.column=s,n=L.getOrder(L.getData(i,r,"sortInitialOrder")||d.sortInitialOrder),d.sortVars[s]={count:-1,order:n?d.sortReset?[1,0,2]:[1,0]:d.sortReset?[0,1,2]:[0,1],lockedOrder:!1,sortedBy:""},void 0!==(n=L.getData(i,r,"lockedOrder")||!1)&&!1!==n&&(d.sortVars[s].lockedOrder=!0,d.sortVars[s].order=L.getOrder(n)?[1,1]:[0,0]),d.headerList[t]=e,i.addClass(L.css.header+" "+d.cssHeader),L.getClosest(i,"tr").addClass(L.css.headerRow+" "+d.cssHeaderRow).attr("role","row"),d.tabIndex&&i.attr("tabindex",0),e})),d.$headerIndexed=[],r=0;r<d.columns;r++)L.isEmptyObject(d.sortVars[r])&&(d.sortVars[r]={}),e=d.$headers.filter('[data-column="'+r+'"]'),d.$headerIndexed[r]=e.length?e.not(".sorter-false").length?e.not(".sorter-false").filter(":last"):e.filter(":last"):A();d.$table.find(d.selectorHeaders).attr({scope:"col",role:"columnheader"}),L.updateHeader(d),L.debug(d,"core")&&(console.log("Built headers:"+L.benchmark(t)),console.log(d.$headers))},addInstanceMethods:function(e){A.extend(L.instanceMethods,e)},setupParsers:function(e,t){var r,o,s,a,n,i,d,l,c,g,p,u,f,h,m=e.table,b=0,y=L.debug(e,"core"),w={};if(e.$tbodies=e.$table.children("tbody:not(."+e.cssInfoBlock+")"),0===(h=(f=void 0===t?e.$tbodies:t).length))return y?console.warn("Warning: *Empty table!* Not building a parser cache"):"";for(y&&(u=new Date,console[console.group?"group":"log"]("Detecting parsers for each column")),o={extractors:[],parsers:[]};b<h;){if((r=f[b].rows).length)for(n=0,a=e.columns,i=0;i<a;i++){if((d=e.$headerIndexed[n])&&d.length&&(l=L.getColumnData(m,e.headers,n),p=L.getParserById(L.getData(d,l,"extractor")),g=L.getParserById(L.getData(d,l,"sorter")),c="false"===L.getData(d,l,"parser"),e.empties[n]=(L.getData(d,l,"empty")||e.emptyTo||(e.emptyToBottom?"bottom":"top")).toLowerCase(),e.strings[n]=(L.getData(d,l,"string")||e.stringTo||"max").toLowerCase(),c&&(g=L.getParserById("no-parser")),p||(p=!1),g||(g=L.detectParserForColumn(e,r,-1,n)),y&&(w["("+n+") "+d.text()]={parser:g.id,extractor:p?p.id:"none",string:e.strings[n],empty:e.empties[n]}),o.parsers[n]=g,o.extractors[n]=p,0<(s=d[0].colSpan-1)))for(n+=s,a+=s;0<s+1;)o.parsers[n-s]=g,o.extractors[n-s]=p,s--;n++}b+=o.parsers.length?h:1}y&&(L.isEmptyObject(w)?console.warn(" No parsers detected!"):console[console.table?"table":"log"](w),console.log("Completed detecting parsers"+L.benchmark(u)),console.groupEnd&&console.groupEnd()),e.parsers=o.parsers,e.extractors=o.extractors},addParser:function(e){var t,r=L.parsers.length,o=!0;for(t=0;t<r;t++)L.parsers[t].id.toLowerCase()===e.id.toLowerCase()&&(o=!1);o&&(L.parsers[L.parsers.length]=e)},getParserById:function(e){if("false"==e)return!1;var t,r=L.parsers.length;for(t=0;t<r;t++)if(L.parsers[t].id.toLowerCase()===e.toString().toLowerCase())return L.parsers[t];return!1},detectParserForColumn:function(e,t,r,o){for(var s,a,n,i=L.parsers.length,d=!1,l="",c=L.debug(e,"core"),g=!0;""===l&&g;)(n=t[++r])&&r<50?n.className.indexOf(L.cssIgnoreRow)<0&&(d=t[r].cells[o],l=L.getElementText(e,d,o),a=A(d),c&&console.log("Checking if value was empty on row "+r+", column: "+o+': "'+l+'"')):g=!1;for(;0<=--i;)if((s=L.parsers[i])&&"text"!==s.id&&s.is&&s.is(l,e.table,d,a))return s;return L.getParserById("text")},getElementText:function(e,t,r){if(!t)return"";var o,s=e.textExtraction||"",a=t.jquery?t:A(t);return"string"==typeof s?"basic"===s&&void 0!==(o=a.attr(e.textAttribute))?A.trim(o):A.trim(t.textContent||a.text()):"function"==typeof s?A.trim(s(a[0],e.table,r)):"function"==typeof(o=L.getColumnData(e.table,s,r))?A.trim(o(a[0],e.table,r)):A.trim(a[0].textContent||a.text())},getParsedText:function(e,t,r,o){void 0===o&&(o=L.getElementText(e,t,r));var s=""+o,a=e.parsers[r],n=e.extractors[r];return a&&(n&&"function"==typeof n.format&&(o=n.format(o,e.table,t,r)),s="no-parser"===a.id?"":a.format(""+o,e.table,t,r),e.ignoreCase&&"string"==typeof s&&(s=s.toLowerCase())),s},buildCache:function(e,t,r){var o,s,a,n,i,d,l,c,g,p,u,f,h,m,b,y,w,x,v,C,$,I,D=e.table,R=e.parsers,T=L.debug(e,"core");if(e.$tbodies=e.$table.children("tbody:not(."+e.cssInfoBlock+")"),l=void 0===r?e.$tbodies:r,e.cache={},e.totalRows=0,!R)return T?console.warn("Warning: *Empty table!* Not building a cache"):"";for(T&&(f=new Date),e.showProcessing&&L.isProcessing(D,!0),d=0;d<l.length;d++){for(y=[],o=e.cache[d]={normalized:[]},h=l[d]&&l[d].rows.length||0,n=0;n<h;++n)if(m={child:[],raw:[]},g=[],!(c=A(l[d].rows[n])).hasClass(e.selectorRemove.slice(1)))if(c.hasClass(e.cssChildRow)&&0!==n)for($=o.normalized.length-1,(b=o.normalized[$][e.columns]).$row=b.$row.add(c),c.prev().hasClass(e.cssChildRow)||c.prev().addClass(L.css.cssHasChild),p=c.children("th, td"),$=b.child.length,b.child[$]=[],x=0,C=e.columns,i=0;i<C;i++)(u=p[i])&&(b.child[$][i]=L.getParsedText(e,u,i),0<(w=p[i].colSpan-1)&&(x+=w,C+=w)),x++;else{for(m.$row=c,m.order=n,x=0,C=e.columns,i=0;i<C;++i){if((u=c[0].cells[i])&&x<e.columns&&(!(v=void 0!==R[x])&&T&&console.warn("No parser found for row: "+n+", column: "+i+'; cell containing: "'+A(u).text()+'"; does it have a header?'),s=L.getElementText(e,u,x),m.raw[x]=s,a=L.getParsedText(e,u,x,s),g[x]=a,v&&"numeric"===(R[x].type||"").toLowerCase()&&(y[x]=Math.max(Math.abs(a)||0,y[x]||0)),0<(w=u.colSpan-1))){for(I=0;I<=w;)a=e.duplicateSpan||0===I?s:"string"!=typeof e.textExtraction&&L.getElementText(e,u,x+I)||"",m.raw[x+I]=a,g[x+I]=a,I++;x+=w,C+=w}x++}g[e.columns]=m,o.normalized[o.normalized.length]=g}o.colMax=y,e.totalRows+=o.normalized.length}if(e.showProcessing&&L.isProcessing(D),T){for($=Math.min(5,e.cache[0].normalized.length),console[console.group?"group":"log"]("Building cache for "+e.totalRows+" rows (showing "+$+" rows in log) and "+e.columns+" columns"+L.benchmark(f)),s={},i=0;i<e.columns;i++)for(x=0;x<$;x++)s["row: "+x]||(s["row: "+x]={}),s["row: "+x][e.$headerIndexed[i].text()]=e.cache[0].normalized[x][i];console[console.table?"table":"log"](s),console.groupEnd&&console.groupEnd()}A.isFunction(t)&&t(D)},getColumnText:function(e,t,r,o){var s,a,n,i,d,l,c,g,p,u,f="function"==typeof r,h="all"===t,m={raw:[],parsed:[],$cell:[]},b=(e=A(e)[0]).config;if(!L.isEmptyObject(b)){for(d=b.$tbodies.length,s=0;s<d;s++)for(l=(n=b.cache[s].normalized).length,a=0;a<l;a++)i=n[a],o&&!i[b.columns].$row.is(o)||(u=!0,g=h?i.slice(0,b.columns):i[t],i=i[b.columns],c=h?i.raw:i.raw[t],p=h?i.$row.children():i.$row.children().eq(t),f&&(u=r({tbodyIndex:s,rowIndex:a,parsed:g,raw:c,$row:i.$row,$cell:p})),!1!==u&&(m.parsed[m.parsed.length]=g,m.raw[m.raw.length]=c,m.$cell[m.$cell.length]=p));return m}L.debug(b,"core")&&console.warn("No cache found - aborting getColumnText function!")},setHeadersCss:function(a){var e,t,r=a.sortList,o=r.length,s=L.css.sortNone+" "+a.cssNone,n=[L.css.sortAsc+" "+a.cssAsc,L.css.sortDesc+" "+a.cssDesc],i=[a.cssIconAsc,a.cssIconDesc,a.cssIconNone],d=["ascending","descending"],l=function(e,t){e.removeClass(s).addClass(n[t]).attr("aria-sort",d[t]).find("."+L.css.icon).removeClass(i[2]).addClass(i[t])},c=a.$table.find("tfoot tr").children("td, th").add(A(a.namespace+"_extra_headers")).removeClass(n.join(" ")),g=a.$headers.add(A("thead "+a.namespace+"_extra_headers")).removeClass(n.join(" ")).addClass(s).attr("aria-sort","none").find("."+L.css.icon).removeClass(i.join(" ")).end();for(g.not(".sorter-false").find("."+L.css.icon).addClass(i[2]),a.cssIconDisabled&&g.filter(".sorter-false").find("."+L.css.icon).addClass(a.cssIconDisabled),e=0;e<o;e++)if(2!==r[e][1]){if((g=(g=a.$headers.filter(function(e){for(var t=!0,r=a.$headers.eq(e),o=parseInt(r.attr("data-column"),10),s=o+L.getClosest(r,"th, td")[0].colSpan;o<s;o++)t=!!t&&(t||-1<L.isValueInArray(o,a.sortList));return t})).not(".sorter-false").filter('[data-column="'+r[e][0]+'"]'+(1===o?":last":""))).length)for(t=0;t<g.length;t++)g[t].sortDisabled||l(g.eq(t),r[e][1]);c.length&&l(c.filter('[data-column="'+r[e][0]+'"]'),r[e][1])}for(o=a.$headers.length,e=0;e<o;e++)L.setColumnAriaLabel(a,a.$headers.eq(e))},getClosest:function(e,t){return A.fn.closest?e.closest(t):e.is(t)?e:e.parents(t).filter(":first")},setColumnAriaLabel:function(e,t,r){if(t.length){var o=parseInt(t.attr("data-column"),10),s=e.sortVars[o],a=t.hasClass(L.css.sortAsc)?"sortAsc":t.hasClass(L.css.sortDesc)?"sortDesc":"sortNone",n=A.trim(t.text())+": "+L.language[a];t.hasClass("sorter-false")||!1===r?n+=L.language.sortDisabled:(a=(s.count+1)%s.order.length,r=s.order[a],n+=L.language[0===r?"nextAsc":1===r?"nextDesc":"nextNone"]),t.attr("aria-label",n),s.sortedBy?t.attr("data-sortedBy",s.sortedBy):t.removeAttr("data-sortedBy")}},updateHeader:function(e){var t,r,o,s,a=e.table,n=e.$headers.length;for(t=0;t<n;t++)o=e.$headers.eq(t),s=L.getColumnData(a,e.headers,t,!0),r="false"===L.getData(o,s,"sorter")||"false"===L.getData(o,s,"parser"),L.setColumnSort(e,o,r)},setColumnSort:function(e,t,r){var o=e.table.id;t[0].sortDisabled=r,t[r?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+r),e.tabIndex&&(r?t.removeAttr("tabindex"):t.attr("tabindex","0")),o&&(r?t.removeAttr("aria-controls"):t.attr("aria-controls",o))},updateHeaderSortCount:function(e,t){var r,o,s,a,n,i,d,l,c=t||e.sortList,g=c.length;for(e.sortList=[],a=0;a<g;a++)if(d=c[a],(r=parseInt(d[0],10))<e.columns){switch(e.sortVars[r].order||(l=L.getOrder(e.sortInitialOrder)?e.sortReset?[1,0,2]:[1,0]:e.sortReset?[0,1,2]:[0,1],e.sortVars[r].order=l,e.sortVars[r].count=0),l=e.sortVars[r].order,o=(o=(""+d[1]).match(/^(1|d|s|o|n)/))?o[0]:""){case"1":case"d":o=1;break;case"s":o=n||0;break;case"o":o=0===(i=l[(n||0)%l.length])?1:1===i?0:2;break;case"n":o=l[++e.sortVars[r].count%l.length];break;default:o=0}n=0===a?o:n,s=[r,parseInt(o,10)||0],e.sortList[e.sortList.length]=s,o=A.inArray(s[1],l),e.sortVars[r].count=0<=o?o:s[1]%l.length}},updateAll:function(e,t,r){var o=e.table;o.isUpdating=!0,L.refreshWidgets(o,!0,!0),L.buildHeaders(e),L.bindEvents(o,e.$headers,!0),L.bindMethods(e),L.commonUpdate(e,t,r)},update:function(e,t,r){e.table.isUpdating=!0,L.updateHeader(e),L.commonUpdate(e,t,r)},updateHeaders:function(e,t){e.table.isUpdating=!0,L.buildHeaders(e),L.bindEvents(e.table,e.$headers,!0),L.resortComplete(e,t)},updateCell:function(e,t,r,o){if(A(t).closest("tr").hasClass(e.cssChildRow))console.warn('Tablesorter Warning! "updateCell" for child row content has been disabled, use "update" instead');else{if(L.isEmptyObject(e.cache))return L.updateHeader(e),void L.commonUpdate(e,r,o);e.table.isUpdating=!0,e.$table.find(e.selectorRemove).remove();var s,a,n,i,d,l,c=e.$tbodies,g=A(t),p=c.index(L.getClosest(g,"tbody")),u=e.cache[p],f=L.getClosest(g,"tr");if(t=g[0],c.length&&0<=p){if(n=c.eq(p).find("tr").not("."+e.cssChildRow).index(f),d=u.normalized[n],(l=f[0].cells.length)!==e.columns)for(s=!1,a=i=0;a<l;a++)s||f[0].cells[a]===t?s=!0:i+=f[0].cells[a].colSpan;else i=g.index();s=L.getElementText(e,t,i),d[e.columns].raw[i]=s,s=L.getParsedText(e,t,i,s),d[i]=s,"numeric"===(e.parsers[i].type||"").toLowerCase()&&(u.colMax[i]=Math.max(Math.abs(s)||0,u.colMax[i]||0)),!1!==(s="undefined"!==r?r:e.resort)?L.checkResort(e,s,o):L.resortComplete(e,o)}else L.debug(e,"core")&&console.error("updateCell aborted, tbody missing or not within the indicated table"),e.table.isUpdating=!1}},addRows:function(e,t,r,o){var s,a,n,i,d,l,c,g,p,u,f,h,m,b="string"==typeof t&&1===e.$tbodies.length&&/<tr/.test(t||""),y=e.table;if(b)t=A(t),e.$tbodies.append(t);else if(!(t&&t instanceof A&&L.getClosest(t,"table")[0]===e.table))return L.debug(e,"core")&&console.error("addRows method requires (1) a jQuery selector reference to rows that have already been added to the table, or (2) row HTML string to be added to a table with only one tbody"),!1;if(y.isUpdating=!0,L.isEmptyObject(e.cache))L.updateHeader(e),L.commonUpdate(e,r,o);else{for(d=t.filter("tr").attr("role","row").length,n=e.$tbodies.index(t.parents("tbody").filter(":first")),e.parsers&&e.parsers.length||L.setupParsers(e),i=0;i<d;i++){for(p=0,c=t[i].cells.length,g=e.cache[n].normalized.length,f=[],u={child:[],raw:[],$row:t.eq(i),order:g},l=0;l<c;l++)h=t[i].cells[l],s=L.getElementText(e,h,p),u.raw[p]=s,a=L.getParsedText(e,h,p,s),f[p]=a,"numeric"===(e.parsers[p].type||"").toLowerCase()&&(e.cache[n].colMax[p]=Math.max(Math.abs(a)||0,e.cache[n].colMax[p]||0)),0<(m=h.colSpan-1)&&(p+=m),p++;f[e.columns]=u,e.cache[n].normalized[g]=f}L.checkResort(e,r,o)}},updateCache:function(e,t,r){e.parsers&&e.parsers.length||L.setupParsers(e,r),L.buildCache(e,t,r)},appendCache:function(e,t){var r,o,s,a,n,i,d,l=e.table,c=e.$tbodies,g=[],p=e.cache;if(L.isEmptyObject(p))return e.appender?e.appender(l,g):l.isUpdating?e.$table.triggerHandler("updateComplete",l):"";for(L.debug(e,"core")&&(d=new Date),i=0;i<c.length;i++)if((s=c.eq(i)).length){for(a=L.processTbody(l,s,!0),o=(r=p[i].normalized).length,n=0;n<o;n++)g[g.length]=r[n][e.columns].$row,e.appender&&(!e.pager||e.pager.removeRows||e.pager.ajax)||a.append(r[n][e.columns].$row);L.processTbody(l,a,!1)}e.appender&&e.appender(l,g),L.debug(e,"core")&&console.log("Rebuilt table"+L.benchmark(d)),t||e.appender||L.applyWidget(l),l.isUpdating&&e.$table.triggerHandler("updateComplete",l)},commonUpdate:function(e,t,r){e.$table.find(e.selectorRemove).remove(),L.setupParsers(e),L.buildCache(e),L.checkResort(e,t,r)},initSort:function(t,e,r){if(t.table.isUpdating)return setTimeout(function(){L.initSort(t,e,r)},50);var o,s,a,n,i,d,l,c=!r[t.sortMultiSortKey],g=t.table,p=t.$headers.length,u=L.getClosest(A(e),"th, td"),f=parseInt(u.attr("data-column"),10),h="mouseup"===r.type?"user":r.type,m=t.sortVars[f].order;if(u=u[0],t.$table.triggerHandler("sortStart",g),d=(t.sortVars[f].count+1)%m.length,t.sortVars[f].count=r[t.sortResetKey]?2:d,t.sortRestart)for(a=0;a<p;a++)l=t.$headers.eq(a),f!==(d=parseInt(l.attr("data-column"),10))&&(c||l.hasClass(L.css.sortNone))&&(t.sortVars[d].count=-1);if(c){if(A.each(t.sortVars,function(e){t.sortVars[e].sortedBy=""}),t.sortList=[],t.last.sortList=[],null!==t.sortForce)for(o=t.sortForce,s=0;s<o.length;s++)o[s][0]!==f&&(t.sortList[t.sortList.length]=o[s],t.sortVars[o[s][0]].sortedBy="sortForce");if((n=m[t.sortVars[f].count])<2&&(t.sortList[t.sortList.length]=[f,n],t.sortVars[f].sortedBy=h,1<u.colSpan))for(s=1;s<u.colSpan;s++)t.sortList[t.sortList.length]=[f+s,n],t.sortVars[f+s].count=A.inArray(n,m),t.sortVars[f+s].sortedBy=h}else if(t.sortList=A.extend([],t.last.sortList),0<=L.isValueInArray(f,t.sortList))for(t.sortVars[f].sortedBy=h,s=0;s<t.sortList.length;s++)(d=t.sortList[s])[0]===f&&(d[1]=m[t.sortVars[f].count],2===d[1]&&(t.sortList.splice(s,1),t.sortVars[f].count=-1));else if(n=m[t.sortVars[f].count],t.sortVars[f].sortedBy=h,n<2&&(t.sortList[t.sortList.length]=[f,n],1<u.colSpan))for(s=1;s<u.colSpan;s++)t.sortList[t.sortList.length]=[f+s,n],t.sortVars[f+s].count=A.inArray(n,m),t.sortVars[f+s].sortedBy=h;if(t.last.sortList=A.extend([],t.sortList),t.sortList.length&&t.sortAppend&&(o=A.isArray(t.sortAppend)?t.sortAppend:t.sortAppend[t.sortList[0][0]],!L.isEmptyObject(o)))for(s=0;s<o.length;s++)if(o[s][0]!==f&&L.isValueInArray(o[s][0],t.sortList)<0){if(i=(""+(n=o[s][1])).match(/^(a|d|s|o|n)/))switch(d=t.sortList[0][1],i[0]){case"d":n=1;break;case"s":n=d;break;case"o":n=0===d?1:0;break;case"n":n=(d+1)%m.length;break;default:n=0}t.sortList[t.sortList.length]=[o[s][0],n],t.sortVars[o[s][0]].sortedBy="sortAppend"}t.$table.triggerHandler("sortBegin",g),setTimeout(function(){L.setHeadersCss(t),L.multisort(t),L.appendCache(t),t.$table.triggerHandler("sortBeforeEnd",g),t.$table.triggerHandler("sortEnd",g)},1)},multisort:function(l){var e,t,c,r,g=l.table,p=[],u=0,f=l.textSorter||"",h=l.sortList,m=h.length,o=l.$tbodies.length;if(!l.serverSideSorting&&!L.isEmptyObject(l.cache)){if(L.debug(l,"core")&&(t=new Date),"object"==typeof f)for(c=l.columns;c--;)"function"==typeof(r=L.getColumnData(g,f,c))&&(p[c]=r);for(e=0;e<o;e++)c=l.cache[e].colMax,l.cache[e].normalized.sort(function(e,t){var r,o,s,a,n,i,d;for(r=0;r<m;r++){if(s=h[r][0],a=h[r][1],u=0===a,l.sortStable&&e[s]===t[s]&&1===m)return e[l.columns].order-t[l.columns].order;if(n=(o=/n/i.test(L.getSortType(l.parsers,s)))&&l.strings[s]?(o="boolean"==typeof L.string[l.strings[s]]?(u?1:-1)*(L.string[l.strings[s]]?-1:1):l.strings[s]&&L.string[l.strings[s]]||0,l.numberSorter?l.numberSorter(e[s],t[s],u,c[s],g):L["sortNumeric"+(u?"Asc":"Desc")](e[s],t[s],o,c[s],s,l)):(i=u?e:t,d=u?t:e,"function"==typeof f?f(i[s],d[s],u,s,g):"function"==typeof p[s]?p[s](i[s],d[s],u,s,g):L["sortNatural"+(u?"Asc":"Desc")](e[s]||"",t[s]||"",s,l)))return n}return e[l.columns].order-t[l.columns].order});L.debug(l,"core")&&console.log("Applying sort "+h.toString()+L.benchmark(t))}},resortComplete:function(e,t){e.table.isUpdating&&e.$table.triggerHandler("updateComplete",e.table),A.isFunction(t)&&t(e.table)},checkResort:function(e,t,r){var o=A.isArray(t)?t:e.sortList;!1===(void 0===t?e.resort:t)||e.serverSideSorting||e.table.isProcessing?(L.resortComplete(e,r),L.applyWidget(e.table,!1)):o.length?L.sortOn(e,o,function(){L.resortComplete(e,r)},!0):L.sortReset(e,function(){L.resortComplete(e,r),L.applyWidget(e.table,!1)})},sortOn:function(e,t,r,o){var s,a=e.table;for(e.$table.triggerHandler("sortStart",a),s=0;s<e.columns;s++)e.sortVars[s].sortedBy=-1<L.isValueInArray(s,t)?"sorton":"";L.updateHeaderSortCount(e,t),L.setHeadersCss(e),e.delayInit&&L.isEmptyObject(e.cache)&&L.buildCache(e),e.$table.triggerHandler("sortBegin",a),L.multisort(e),L.appendCache(e,o),e.$table.triggerHandler("sortBeforeEnd",a),e.$table.triggerHandler("sortEnd",a),L.applyWidget(a),A.isFunction(r)&&r(a)},sortReset:function(e,t){var r;for(e.sortList=[],r=0;r<e.columns;r++)e.sortVars[r].count=-1,e.sortVars[r].sortedBy="";L.setHeadersCss(e),L.multisort(e),L.appendCache(e),A.isFunction(t)&&t(e.table)},getSortType:function(e,t){return e&&e[t]&&e[t].type||""},getOrder:function(e){return/^d/i.test(e)||1===e},sortNatural:function(e,t){if(e===t)return 0;e=(e||"").toString(),t=(t||"").toString();var r,o,s,a,n,i,d=L.regex;if(d.hex.test(t)){if((r=parseInt(e.match(d.hex),16))<(o=parseInt(t.match(d.hex),16)))return-1;if(o<r)return 1}for(r=e.replace(d.chunk,"\\0$1\\0").replace(d.chunks,"").split("\\0"),o=t.replace(d.chunk,"\\0$1\\0").replace(d.chunks,"").split("\\0"),i=Math.max(r.length,o.length),n=0;n<i;n++){if(s=isNaN(r[n])?r[n]||0:parseFloat(r[n])||0,a=isNaN(o[n])?o[n]||0:parseFloat(o[n])||0,isNaN(s)!==isNaN(a))return isNaN(s)?1:-1;if(typeof s!=typeof a&&(s+="",a+=""),s<a)return-1;if(a<s)return 1}return 0},sortNaturalAsc:function(e,t,r,o){if(e===t)return 0;var s=L.string[o.empties[r]||o.emptyTo];return""===e&&0!==s?"boolean"==typeof s?s?-1:1:-s||-1:""===t&&0!==s?"boolean"==typeof s?s?1:-1:s||1:L.sortNatural(e,t)},sortNaturalDesc:function(e,t,r,o){if(e===t)return 0;var s=L.string[o.empties[r]||o.emptyTo];return""===e&&0!==s?"boolean"==typeof s?s?-1:1:s||1:""===t&&0!==s?"boolean"==typeof s?s?1:-1:-s||-1:L.sortNatural(t,e)},sortText:function(e,t){return t<e?1:e<t?-1:0},getTextValue:function(e,t,r){if(r){var o,s=e?e.length:0,a=r+t;for(o=0;o<s;o++)a+=e.charCodeAt(o);return t*a}return 0},sortNumericAsc:function(e,t,r,o,s,a){if(e===t)return 0;var n=L.string[a.empties[s]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:-n||-1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:n||1:(isNaN(e)&&(e=L.getTextValue(e,r,o)),isNaN(t)&&(t=L.getTextValue(t,r,o)),e-t)},sortNumericDesc:function(e,t,r,o,s,a){if(e===t)return 0;var n=L.string[a.empties[s]||a.emptyTo];return""===e&&0!==n?"boolean"==typeof n?n?-1:1:n||1:""===t&&0!==n?"boolean"==typeof n?n?1:-1:-n||-1:(isNaN(e)&&(e=L.getTextValue(e,r,o)),isNaN(t)&&(t=L.getTextValue(t,r,o)),t-e)},sortNumeric:function(e,t){return e-t},addWidget:function(e){e.id&&!L.isEmptyObject(L.getWidgetById(e.id))&&console.warn('"'+e.id+'" widget was loaded more than once!'),L.widgets[L.widgets.length]=e},hasWidget:function(e,t){return(e=A(e)).length&&e[0].config&&e[0].config.widgetInit[t]||!1},getWidgetById:function(e){var t,r,o=L.widgets.length;for(t=0;t<o;t++)if((r=L.widgets[t])&&r.id&&r.id.toLowerCase()===e.toLowerCase())return r},applyWidgetOptions:function(e){var t,r,o,s=e.config,a=s.widgets.length;if(a)for(t=0;t<a;t++)(r=L.getWidgetById(s.widgets[t]))&&r.options&&(o=A.extend(!0,{},r.options),s.widgetOptions=A.extend(!0,o,s.widgetOptions),A.extend(!0,L.defaults.widgetOptions,r.options))},addWidgetFromClass:function(e){var t,r,o=e.config,s="^"+o.widgetClass.replace(L.regex.templateName,"(\\S+)+")+"$",a=new RegExp(s,"g"),n=(e.className||"").split(L.regex.spaces);if(n.length)for(t=n.length,r=0;r<t;r++)n[r].match(a)&&(o.widgets[o.widgets.length]=n[r].replace(a,"$1"))},applyWidgetId:function(e,t,r){var o,s,a,n=(e=A(e)[0]).config,i=n.widgetOptions,d=L.debug(n,"core"),l=L.getWidgetById(t);l&&(a=l.id,o=!1,A.inArray(a,n.widgets)<0&&(n.widgets[n.widgets.length]=a),d&&(s=new Date),!r&&n.widgetInit[a]||(n.widgetInit[a]=!0,e.hasInitialized&&L.applyWidgetOptions(e),"function"==typeof l.init&&(o=!0,d&&console[console.group?"group":"log"]("Initializing "+a+" widget"),l.init(e,l,n,i))),r||"function"!=typeof l.format||(o=!0,d&&console[console.group?"group":"log"]("Updating "+a+" widget"),l.format(e,n,i,!1)),d&&o&&(console.log("Completed "+(r?"initializing ":"applying ")+a+" widget"+L.benchmark(s)),console.groupEnd&&console.groupEnd()))},applyWidget:function(e,t,r){var o,s,a,n,i,d=(e=A(e)[0]).config,l=L.debug(d,"core"),c=[];if(!1===t||!e.hasInitialized||!e.isApplyingWidgets&&!e.isUpdating){if(l&&(i=new Date),L.addWidgetFromClass(e),clearTimeout(d.timerReady),d.widgets.length){for(e.isApplyingWidgets=!0,d.widgets=A.grep(d.widgets,function(e,t){return A.inArray(e,d.widgets)===t}),s=(a=d.widgets||[]).length,o=0;o<s;o++)(n=L.getWidgetById(a[o]))&&n.id?(n.priority||(n.priority=10),c[o]=n):l&&console.warn('"'+a[o]+'" was enabled, but the widget code has not been loaded!');for(c.sort(function(e,t){return e.priority<t.priority?-1:e.priority===t.priority?0:1}),s=c.length,l&&console[console.group?"group":"log"]("Start "+(t?"initializing":"applying")+" widgets"),o=0;o<s;o++)(n=c[o])&&n.id&&L.applyWidgetId(e,n.id,t);l&&console.groupEnd&&console.groupEnd()}d.timerReady=setTimeout(function(){e.isApplyingWidgets=!1,A.data(e,"lastWidgetApplication",new Date),d.$table.triggerHandler("tablesorter-ready"),t||"function"!=typeof r||r(e),l&&(n=d.widgets.length,console.log("Completed "+(!0===t?"initializing ":"applying ")+n+" widget"+(1!==n?"s":"")+L.benchmark(i)))},10)}},removeWidget:function(e,t,r){var o,s,a,n,i=(e=A(e)[0]).config;if(!0===t)for(t=[],n=L.widgets.length,a=0;a<n;a++)(s=L.widgets[a])&&s.id&&(t[t.length]=s.id);else t=(A.isArray(t)?t.join(","):t||"").toLowerCase().split(/[\s,]+/);for(n=t.length,o=0;o<n;o++)s=L.getWidgetById(t[o]),0<=(a=A.inArray(t[o],i.widgets))&&!0!==r&&i.widgets.splice(a,1),s&&s.remove&&(L.debug(i,"core")&&console.log((r?"Refreshing":"Removing")+' "'+t[o]+'" widget'),s.remove(e,i,i.widgetOptions,r),i.widgetInit[t[o]]=!1);i.$table.triggerHandler("widgetRemoveEnd",e)},refreshWidgets:function(e,t,r){var o,s,a=(e=A(e)[0]).config.widgets,n=L.widgets,i=n.length,d=[],l=function(e){A(e).triggerHandler("refreshComplete")};for(o=0;o<i;o++)(s=n[o])&&s.id&&(t||A.inArray(s.id,a)<0)&&(d[d.length]=s.id);L.removeWidget(e,d.join(","),!0),!0!==r?(L.applyWidget(e,t||!1,l),t&&L.applyWidget(e,!1,l)):l(e)},benchmark:function(e){return" ("+((new Date).getTime()-e.getTime())+" ms)"},log:function(){console.log(arguments)},debug:function(e,t){return e&&(!0===e.debug||"string"==typeof e.debug&&-1<e.debug.indexOf(t))},isEmptyObject:function(e){for(var t in e)return!1;return!0},isValueInArray:function(e,t){var r,o=t&&t.length||0;for(r=0;r<o;r++)if(t[r][0]===e)return r;return-1},formatFloat:function(e,t){return"string"!=typeof e||""===e?e:(e=(t&&t.config?!1!==t.config.usNumberFormat:void 0===t||t)?e.replace(L.regex.comma,""):e.replace(L.regex.digitNonUS,"").replace(L.regex.comma,"."),L.regex.digitNegativeTest.test(e)&&(e=e.replace(L.regex.digitNegativeReplace,"-$1")),r=parseFloat(e),isNaN(r)?A.trim(e):r);var r},isDigit:function(e){return isNaN(e)?L.regex.digitTest.test(e.toString().replace(L.regex.digitReplace,"")):""!==e},computeColumnIndex:function(e,t){var r,o,s,a,n,i,d,l,c,g,p=t&&t.columns||0,u=[],f=new Array(p);for(r=0;r<e.length;r++)for(i=e[r].cells,o=0;o<i.length;o++){for(d=r,l=(n=i[o]).rowSpan||1,c=n.colSpan||1,void 0===u[d]&&(u[d]=[]),s=0;s<u[d].length+1;s++)if(void 0===u[d][s]){g=s;break}for(p&&n.cellIndex===g||(n.setAttribute?n.setAttribute("data-column",g):A(n).attr("data-column",g)),s=d;s<d+l;s++)for(void 0===u[s]&&(u[s]=[]),f=u[s],a=g;a<g+c;a++)f[a]="x"}return L.checkColumnCount(e,u,f.length),f.length},checkColumnCount:function(e,t,r){var o,s,a=!0,n=[];for(o=0;o<t.length;o++)if(t[o]&&(s=t[o].length,t[o].length!==r)){a=!1;break}a||(e.each(function(e,t){var r=t.parentElement.nodeName;n.indexOf(r)<0&&n.push(r)}),console.error("Invalid or incorrect number of columns in the "+n.join(" or ")+"; expected "+r+", but found "+s+" columns"))},fixColumnWidth:function(e){var t,r,o,s,a,n=(e=A(e)[0]).config,i=n.$table.children("colgroup");if(i.length&&i.hasClass(L.css.colgroup)&&i.remove(),n.widthFixed&&0===n.$table.children("colgroup").length){for(i=A('<colgroup class="'+L.css.colgroup+'">'),t=n.$table.width(),s=(o=n.$tbodies.find("tr:first").children(":visible")).length,a=0;a<s;a++)r=parseInt(o.eq(a).width()/t*1e3,10)/10+"%",i.append(A("<col>").css("width",r));n.$table.prepend(i)}},getData:function(e,t,r){var o,s,a="",n=A(e);return n.length?(o=!!A.metadata&&n.metadata(),s=" "+(n.attr("class")||""),void 0!==n.data(r)||void 0!==n.data(r.toLowerCase())?a+=n.data(r)||n.data(r.toLowerCase()):o&&void 0!==o[r]?a+=o[r]:t&&void 0!==t[r]?a+=t[r]:" "!==s&&s.match(" "+r+"-")&&(a=s.match(new RegExp("\\s"+r+"-([\\w-]+)"))[1]||""),A.trim(a)):""},getColumnData:function(e,t,r,o,s){if("object"!=typeof t||null===t)return t;var a,n=(e=A(e)[0]).config,i=s||n.$headers,d=n.$headerIndexed&&n.$headerIndexed[r]||i.find('[data-column="'+r+'"]:last');if(void 0!==t[r])return o?t[r]:t[i.index(d)];for(a in t)if("string"==typeof a&&d.filter(a).add(d.find(a)).length)return t[a]},isProcessing:function(e,t,r){var o=(e=A(e))[0].config,s=r||e.find("."+L.css.header);t?(void 0!==r&&0<o.sortList.length&&(s=s.filter(function(){return!this.sortDisabled&&0<=L.isValueInArray(parseFloat(A(this).attr("data-column")),o.sortList)})),e.add(s).addClass(L.css.processing+" "+o.cssProcessing)):e.add(s).removeClass(L.css.processing+" "+o.cssProcessing)},processTbody:function(e,t,r){if(e=A(e)[0],r)return e.isProcessing=!0,t.before('<colgroup class="tablesorter-savemyplace"/>'),A.fn.detach?t.detach():t.remove();var o=A(e).find("colgroup.tablesorter-savemyplace");t.insertAfter(o),o.remove(),e.isProcessing=!1},clearTableBody:function(e){A(e)[0].config.$tbodies.children().detach()},characterEquivalents:{a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},replaceAccents:function(e){var t,r="[",o=L.characterEquivalents;if(!L.characterRegex){for(t in L.characterRegexArray={},o)"string"==typeof t&&(r+=o[t],L.characterRegexArray[t]=new RegExp("["+o[t]+"]","g"));L.characterRegex=new RegExp(r+"]")}if(L.characterRegex.test(e))for(t in o)"string"==typeof t&&(e=e.replace(L.characterRegexArray[t],t));return e},validateOptions:function(e){var t,r,o,s,a="headers sortForce sortList sortAppend widgets".split(" "),n=e.originalSettings;if(n){for(t in L.debug(e,"core")&&(s=new Date),n)if("undefined"===(o=typeof L.defaults[t]))console.warn('Tablesorter Warning! "table.config.'+t+'" option not recognized');else if("object"===o)for(r in n[t])o=L.defaults[t]&&typeof L.defaults[t][r],A.inArray(t,a)<0&&"undefined"===o&&console.warn('Tablesorter Warning! "table.config.'+t+"."+r+'" option not recognized');L.debug(e,"core")&&console.log("validate options time:"+L.benchmark(s))}},restoreHeaders:function(e){var t,r,o=A(e)[0].config,s=o.$table.find(o.selectorHeaders),a=s.length;for(t=0;t<a;t++)(r=s.eq(t)).find("."+L.css.headerIn).length&&r.html(o.headerContent[t])},destroy:function(e,t,r){if((e=A(e)[0]).hasInitialized){L.removeWidget(e,!0,!1);var o,s=A(e),a=e.config,n=s.find("thead:first"),i=n.find("tr."+L.css.headerRow).removeClass(L.css.headerRow+" "+a.cssHeaderRow),d=s.find("tfoot:first > tr").children("th, td");!1===t&&0<=A.inArray("uitheme",a.widgets)&&(s.triggerHandler("applyWidgetId",["uitheme"]),s.triggerHandler("applyWidgetId",["zebra"])),n.find("tr").not(i).remove(),o="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave "+"keypress sortBegin sortEnd resetToLoadState ".split(" ").join(a.namespace+" "),s.removeData("tablesorter").unbind(o.replace(L.regex.spaces," ")),a.$headers.add(d).removeClass([L.css.header,a.cssHeader,a.cssAsc,a.cssDesc,L.css.sortAsc,L.css.sortDesc,L.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),i.find(a.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(a.namespace+" ").replace(L.regex.spaces," ")),L.restoreHeaders(e),s.toggleClass(L.css.table+" "+a.tableClass+" tablesorter-"+a.theme,!1===t),s.removeClass(a.namespace.slice(1)),e.hasInitialized=!1,delete e.config.cache,"function"==typeof r&&r(e),L.debug(a,"core")&&console.log("tablesorter has been removed")}}};A.fn.tablesorter=function(t){return this.each(function(){var e=A.extend(!0,{},L.defaults,t,L.instanceMethods);e.originalSettings=t,!this.hasInitialized&&L.buildTable&&"TABLE"!==this.nodeName?L.buildTable(this,e):L.setup(this,e)})},window.console&&window.console.log||(L.logs=[],console={},console.log=console.warn=console.error=console.table=function(){var e=1<arguments.length?arguments:arguments[0];L.logs[L.logs.length]={date:Date.now(),log:e}}),L.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),L.addParser({id:"text",is:function(){return!0},format:function(e,t){var r=t.config;return e&&(e=A.trim(r.ignoreCase?e.toLocaleLowerCase():e),e=r.sortLocaleCompare?L.replaceAccents(e):e),e},type:"text"}),L.regex.nondigit=/[^\w,. \-()]/g,L.addParser({id:"digit",is:function(e){return L.isDigit(e)},format:function(e,t){var r=L.formatFloat((e||"").replace(L.regex.nondigit,""),t);return e&&"number"==typeof r?r:e?A.trim(e&&t.config.ignoreCase?e.toLocaleLowerCase():e):e},type:"numeric"}),L.regex.currencyReplace=/[+\-,. ]/g,L.regex.currencyTest=/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/,L.addParser({id:"currency",is:function(e){return e=(e||"").replace(L.regex.currencyReplace,""),L.regex.currencyTest.test(e)},format:function(e,t){var r=L.formatFloat((e||"").replace(L.regex.nondigit,""),t);return e&&"number"==typeof r?r:e?A.trim(e&&t.config.ignoreCase?e.toLocaleLowerCase():e):e},type:"numeric"}),L.regex.urlProtocolTest=/^(https?|ftp|file):\/\//,L.regex.urlProtocolReplace=/(https?|ftp|file):\/\/(www\.)?/,L.addParser({id:"url",is:function(e){return L.regex.urlProtocolTest.test(e)},format:function(e){return e?A.trim(e.replace(L.regex.urlProtocolReplace,"")):e},type:"text"}),L.regex.dash=/-/g,L.regex.isoDate=/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,L.addParser({id:"isoDate",is:function(e){return L.regex.isoDate.test(e)},format:function(e){var t=e?new Date(e.replace(L.regex.dash,"/")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),L.regex.percent=/%/g,L.regex.percentTest=/(\d\s*?%|%\s*?\d)/,L.addParser({id:"percent",is:function(e){return L.regex.percentTest.test(e)&&e.length<15},format:function(e,t){return e?L.formatFloat(e.replace(L.regex.percent,""),t):e},type:"numeric"}),L.addParser({id:"image",is:function(e,t,r,o){return 0<o.find("img").length},format:function(e,t,r){return A(r).find("img").attr(t.config.imgAttr||"alt")||e},parsed:!0,type:"text"}),L.regex.dateReplace=/(\S)([AP]M)$/i,L.regex.usLongDateTest1=/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i,L.regex.usLongDateTest2=/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i,L.addParser({id:"usLongDate",is:function(e){return L.regex.usLongDateTest1.test(e)||L.regex.usLongDateTest2.test(e)},format:function(e){var t=e?new Date(e.replace(L.regex.dateReplace,"$1 $2")):e;return t instanceof Date&&isFinite(t)?t.getTime():e},type:"numeric"}),L.regex.shortDateTest=/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/,L.regex.shortDateReplace=/[\-.,]/g,L.regex.shortDateXXY=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,L.regex.shortDateYMD=/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,L.convertFormat=function(e,t){e=(e||"").replace(L.regex.spaces," ").replace(L.regex.shortDateReplace,"/"),"mmddyyyy"===t?e=e.replace(L.regex.shortDateXXY,"$3/$1/$2"):"ddmmyyyy"===t?e=e.replace(L.regex.shortDateXXY,"$3/$2/$1"):"yyyymmdd"===t&&(e=e.replace(L.regex.shortDateYMD,"$1/$2/$3"));var r=new Date(e);return r instanceof Date&&isFinite(r)?r.getTime():""},L.addParser({id:"shortDate",is:function(e){return e=(e||"").replace(L.regex.spaces," ").replace(L.regex.shortDateReplace,"/"),L.regex.shortDateTest.test(e)},format:function(e,t,r,o){if(e){var s=t.config,a=s.$headerIndexed[o],n=a.length&&a.data("dateFormat")||L.getData(a,L.getColumnData(t,s.headers,o),"dateFormat")||s.dateFormat;return a.length&&a.data("dateFormat",n),L.convertFormat(e,n)||e}return e},type:"numeric"}),L.regex.timeTest=/^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i,L.regex.timeMatch=/(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i,L.addParser({id:"time",is:function(e){return L.regex.timeTest.test(e)},format:function(e){var t=(e||"").match(L.regex.timeMatch),r=new Date(e),o=e&&(null!==t?t[0]:"00:00 AM"),s=o?new Date("2000/01/01 "+o.replace(L.regex.dateReplace,"$1 $2")):o;return s instanceof Date&&isFinite(s)?(r instanceof Date&&isFinite(r)?r.getTime():0)?parseFloat(s.getTime()+"."+r.getTime()):s.getTime():e},type:"numeric"}),L.addParser({id:"metadata",is:function(){return!1},format:function(e,t,r){var o=t.config,s=o.parserMetadataName?o.parserMetadataName:"sortValue";return A(r).metadata()[s]},type:"numeric"}),L.addWidget({id:"zebra",priority:90,format:function(e,t,r){var o,s,a,n,i,d,l,c=new RegExp(t.cssChildRow,"i"),g=t.$tbodies.add(A(t.namespace+"_extra_table").children("tbody:not(."+t.cssInfoBlock+")"));for(i=0;i<g.length;i++)for(a=0,l=(o=g.eq(i).children("tr:visible").not(t.selectorRemove)).length,d=0;d<l;d++)s=o.eq(d),c.test(s[0].className)||a++,n=a%2==0,s.removeClass(r.zebra[n?1:0]).addClass(r.zebra[n?0:1])},remove:function(e,t,r,o){if(!o){var s,a,n=t.$tbodies,i=(r.zebra||["even","odd"]).join(" ");for(s=0;s<n.length;s++)(a=L.processTbody(e,n.eq(s),!0)).children().removeClass(i),L.processTbody(e,a,!1)}}})}(e),e.tablesorter});
js/tablesorter/jquery.tablesorter.widgets.js CHANGED
@@ -1,3176 +1,3176 @@
1
- /*! tablesorter (FORK) - updated 2018-08-27 (v2.31.0)*/
2
- /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
3
- (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery) {
4
- /*! Widget: storage - updated 2018-03-18 (v2.30.0) */
5
- /*global JSON:false */
6
- ;(function ($, window, document) {
7
- 'use strict';
8
-
9
- var ts = $.tablesorter || {};
10
-
11
- // update defaults for validator; these values must be falsy!
12
- $.extend(true, ts.defaults, {
13
- fixedUrl: '',
14
- widgetOptions: {
15
- storage_fixedUrl: '',
16
- storage_group: '',
17
- storage_page: '',
18
- storage_storageType: '',
19
- storage_tableId: '',
20
- storage_useSessionStorage: ''
21
- }
22
- });
23
-
24
- // *** Store data in local storage, with a cookie fallback ***
25
- /* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
26
- if you need it, then include https://github.com/douglascrockford/JSON-js
27
-
28
- $.parseJSON is not available is jQuery versions older than 1.4.1, using older
29
- versions will only allow storing information for one page at a time
30
-
31
- // *** Save data (JSON format only) ***
32
- // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
33
- var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
34
- // $.tablesorter.storage(table, key, val);
35
- $.tablesorter.storage(table, 'tablesorter-mywidget', val);
36
-
37
- // *** Get data: $.tablesorter.storage(table, key); ***
38
- v = $.tablesorter.storage(table, 'tablesorter-mywidget');
39
- // val may be empty, so also check for your data
40
- val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
41
- alert(val); // 'data1' if saved, or '' if not
42
- */
43
- ts.storage = function(table, key, value, options) {
44
- table = $(table)[0];
45
- var cookieIndex, cookies, date,
46
- hasStorage = false,
47
- values = {},
48
- c = table.config,
49
- wo = c && c.widgetOptions,
50
- debug = ts.debug(c, 'storage'),
51
- storageType = (
52
- ( options && options.storageType ) || ( wo && wo.storage_storageType )
53
- ).toString().charAt(0).toLowerCase(),
54
- // deprecating "useSessionStorage"; any storageType setting overrides it
55
- session = storageType ? '' :
56
- ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ),
57
- $table = $(table),
58
- // id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
59
- // (4) table ID, then (5) table index
60
- id = options && options.id ||
61
- $table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') ||
62
- wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ),
63
- // url from (1) options url, (2) table 'data-table-page' attribute, (3) widgetOptions.storage_fixedUrl,
64
- // (4) table.config.fixedUrl (deprecated), then (5) window location path
65
- url = options && options.url ||
66
- $table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') ||
67
- wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname;
68
-
69
- // skip if using cookies
70
- if (storageType !== 'c') {
71
- storageType = (storageType === 's' || session) ? 'sessionStorage' : 'localStorage';
72
- // https://gist.github.com/paulirish/5558557
73
- if (storageType in window) {
74
- try {
75
- window[storageType].setItem('_tmptest', 'temp');
76
- hasStorage = true;
77
- window[storageType].removeItem('_tmptest');
78
- } catch (error) {
79
- console.warn( storageType + ' is not supported in this browser' );
80
- }
81
- }
82
- }
83
- if (debug) {
84
- console.log('Storage >> Using', hasStorage ? storageType : 'cookies');
85
- }
86
- // *** get value ***
87
- if ($.parseJSON) {
88
- if (hasStorage) {
89
- values = $.parseJSON( window[storageType][key] || 'null' ) || {};
90
- } else {
91
- // old browser, using cookies
92
- cookies = document.cookie.split(/[;\s|=]/);
93
- // add one to get from the key to the value
94
- cookieIndex = $.inArray(key, cookies) + 1;
95
- values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
96
- }
97
- }
98
- // allow value to be an empty string too
99
- if (typeof value !== 'undefined' && window.JSON && JSON.hasOwnProperty('stringify')) {
100
- // add unique identifiers = url pathname > table ID/index on page > data
101
- if (!values[url]) {
102
- values[url] = {};
103
- }
104
- values[url][id] = value;
105
- // *** set value ***
106
- if (hasStorage) {
107
- window[storageType][key] = JSON.stringify(values);
108
- } else {
109
- date = new Date();
110
- date.setTime(date.getTime() + (31536e+6)); // 365 days
111
- document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g, '\"') + '; expires=' + date.toGMTString() + '; path=/';
112
- }
113
- } else {
114
- return values && values[url] ? values[url][id] : '';
115
- }
116
- };
117
-
118
- })(jQuery, window, document);
119
-
120
- /*! Widget: uitheme - updated 2018-03-18 (v2.30.0) */
121
- ;(function ($) {
122
- 'use strict';
123
- var ts = $.tablesorter || {};
124
-
125
- ts.themes = {
126
- 'bootstrap' : {
127
- table : 'table table-bordered table-striped',
128
- caption : 'caption',
129
- // header class names
130
- header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css)
131
- sortNone : '',
132
- sortAsc : '',
133
- sortDesc : '',
134
- active : '', // applied when column is sorted
135
- hover : '', // custom css required - a defined bootstrap style may not override other classes
136
- // icon class names
137
- icons : '', // add 'bootstrap-icon-white' to make them white; this icon class is added to the <i> in the header
138
- iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted
139
- iconSortAsc : 'glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort
140
- iconSortDesc : 'glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort
141
- filterRow : '', // filter row class
142
- footerRow : '',
143
- footerCells : '',
144
- even : '', // even row zebra striping
145
- odd : '' // odd row zebra striping
146
- },
147
- 'jui' : {
148
- table : 'ui-widget ui-widget-content ui-corner-all', // table classes
149
- caption : 'ui-widget-content',
150
- // header class names
151
- header : 'ui-widget-header ui-corner-all ui-state-default', // header classes
152
- sortNone : '',
153
- sortAsc : '',
154
- sortDesc : '',
155
- active : 'ui-state-active', // applied when column is sorted
156
- hover : 'ui-state-hover', // hover class
157
- // icon class names
158
- icons : 'ui-icon', // icon class added to the <i> in the header
159
- iconSortNone : 'ui-icon-carat-2-n-s ui-icon-caret-2-n-s', // class name added to icon when column is not sorted
160
- iconSortAsc : 'ui-icon-carat-1-n ui-icon-caret-1-n', // class name added to icon when column has ascending sort
161
- iconSortDesc : 'ui-icon-carat-1-s ui-icon-caret-1-s', // class name added to icon when column has descending sort
162
- filterRow : '',
163
- footerRow : '',
164
- footerCells : '',
165
- even : 'ui-widget-content', // even row zebra striping
166
- odd : 'ui-state-default' // odd row zebra striping
167
- }
168
- };
169
-
170
- $.extend(ts.css, {
171
- wrapper : 'tablesorter-wrapper' // ui theme & resizable
172
- });
173
-
174
- ts.addWidget({
175
- id: 'uitheme',
176
- priority: 10,
177
- format: function(table, c, wo) {
178
- var i, tmp, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
179
- themesAll = ts.themes,
180
- $table = c.$table.add( $( c.namespace + '_extra_table' ) ),
181
- $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ),
182
- theme = c.theme || 'jui',
183
- themes = themesAll[theme] || {},
184
- remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
185
- iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ),
186
- debug = ts.debug(c, 'uitheme');
187
- if (debug) { time = new Date(); }
188
- // initialization code - run once
189
- if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
190
- wo.uitheme_applied = true;
191
- oldtheme = themesAll[c.appliedTheme] || {};
192
- hasOldTheme = !$.isEmptyObject(oldtheme);
193
- oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
194
- oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
195
- if (hasOldTheme) {
196
- wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
197
- wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
198
- c.$tbodies.children().removeClass( [ oldtheme.even, oldtheme.odd ].join(' ') );
199
- }
200
- // update zebra stripes
201
- if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
202
- if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
203
- // add caption style
204
- $table.children('caption')
205
- .removeClass(oldtheme.caption || '')
206
- .addClass(themes.caption);
207
- // add table/footer class names
208
- $tfoot = $table
209
- // remove other selected themes
210
- .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
211
- .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
212
- .children('tfoot');
213
- c.appliedTheme = c.theme;
214
-
215
- if ($tfoot.length) {
216
- $tfoot
217
- // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
218
- .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
219
- .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
220
- }
221
- // update header classes
222
- $headers
223
- .removeClass( (hasOldTheme ? [ oldtheme.header, oldtheme.hover, oldremove ].join(' ') : '') || '' )
224
- .addClass(themes.header)
225
- .not('.sorter-false')
226
- .unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
227
- .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
228
- // toggleClass with switch added in jQuery 1.3
229
- $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
230
- });
231
-
232
- $headers.each(function() {
233
- var $this = $(this);
234
- if (!$this.find('.' + ts.css.wrapper).length) {
235
- // Firefox needs this inner div to position the icon & resizer correctly
236
- $this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
237
- }
238
- });
239
- if (c.cssIcon) {
240
- // if c.cssIcon is '', then no <i> is added to the header
241
- $headers
242
- .find('.' + ts.css.icon)
243
- .removeClass(hasOldTheme ? [ oldtheme.icons, oldIconRmv ].join(' ') : '')
244
- .addClass(themes.icons || '');
245
- }
246
- // filter widget initializes after uitheme
247
- if (ts.hasWidget( c.table, 'filter' )) {
248
- tmp = function() {
249
- $table.children('thead').children('.' + ts.css.filterRow)
250
- .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
251
- .addClass(themes.filterRow || '');
252
- };
253
- if (wo.filter_initialized) {
254
- tmp();
255
- } else {
256
- $table.one('filterInit', function() {
257
- tmp();
258
- });
259
- }
260
- }
261
- }
262
- for (i = 0; i < c.columns; i++) {
263
- $header = c.$headers
264
- .add($(c.namespace + '_extra_headers'))
265
- .not('.sorter-false')
266
- .filter('[data-column="' + i + '"]');
267
- $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
268
- $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
269
- if ($h.length) {
270
- $header.removeClass(remove);
271
- $icon.removeClass(iconRmv);
272
- if ($h[0].sortDisabled) {
273
- // no sort arrows for disabled columns!
274
- $icon.removeClass(themes.icons || '');
275
- } else {
276
- hdr = themes.sortNone;
277
- icon = themes.iconSortNone;
278
- if ($h.hasClass(ts.css.sortAsc)) {
279
- hdr = [ themes.sortAsc, themes.active ].join(' ');
280
- icon = themes.iconSortAsc;
281
- } else if ($h.hasClass(ts.css.sortDesc)) {
282
- hdr = [ themes.sortDesc, themes.active ].join(' ');
283
- icon = themes.iconSortDesc;
284
- }
285
- $header.addClass(hdr);
286
- $icon.addClass(icon || '');
287
- }
288
- }
289
- }
290
- if (debug) {
291
- console.log('uitheme >> Applied ' + theme + ' theme' + ts.benchmark(time));
292
- }
293
- },
294
- remove: function(table, c, wo, refreshing) {
295
- if (!wo.uitheme_applied) { return; }
296
- var $table = c.$table,
297
- theme = c.appliedTheme || 'jui',
298
- themes = ts.themes[ theme ] || ts.themes.jui,
299
- $headers = $table.children('thead').children(),
300
- remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
301
- iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
302
- $table.removeClass('tablesorter-' + theme + ' ' + themes.table);
303
- wo.uitheme_applied = false;
304
- if (refreshing) { return; }
305
- $table.find(ts.css.header).removeClass(themes.header);
306
- $headers
307
- .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
308
- .removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
309
- .filter('.' + ts.css.filterRow)
310
- .removeClass(themes.filterRow);
311
- $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
312
- }
313
- });
314
-
315
- })(jQuery);
316
-
317
- /*! Widget: columns - updated 5/24/2017 (v2.28.11) */
318
- ;(function ($) {
319
- 'use strict';
320
- var ts = $.tablesorter || {};
321
-
322
- ts.addWidget({
323
- id: 'columns',
324
- priority: 65,
325
- options : {
326
- columns : [ 'primary', 'secondary', 'tertiary' ]
327
- },
328
- format: function(table, c, wo) {
329
- var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
330
- $table = c.$table,
331
- $tbodies = c.$tbodies,
332
- sortList = c.sortList,
333
- len = sortList.length,
334
- // removed c.widgetColumns support
335
- css = wo && wo.columns || [ 'primary', 'secondary', 'tertiary' ],
336
- last = css.length - 1;
337
- remove = css.join(' ');
338
- // check if there is a sort (on initialization there may not be one)
339
- for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
340
- $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
341
- $rows = $tbody.children('tr');
342
- // loop through the visible rows
343
- $rows.each(function() {
344
- $row = $(this);
345
- if (this.style.display !== 'none') {
346
- // remove all columns class names
347
- $cells = $row.children().removeClass(remove);
348
- // add appropriate column class names
349
- if (sortList && sortList[0]) {
350
- // primary sort column class
351
- $cells.eq(sortList[0][0]).addClass(css[0]);
352
- if (len > 1) {
353
- for (indx = 1; indx < len; indx++) {
354
- // secondary, tertiary, etc sort column classes
355
- $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
356
- }
357
- }
358
- }
359
- }
360
- });
361
- ts.processTbody(table, $tbody, false);
362
- }
363
- // add classes to thead and tfoot
364
- rows = wo.columns_thead !== false ? [ 'thead tr' ] : [];
365
- if (wo.columns_tfoot !== false) {
366
- rows.push('tfoot tr');
367
- }
368
- if (rows.length) {
369
- $rows = $table.find( rows.join(',') ).children().removeClass(remove);
370
- if (len) {
371
- for (indx = 0; indx < len; indx++) {
372
- // add primary. secondary, tertiary, etc sort column classes
373
- $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
374
- }
375
- }
376
- }
377
- },
378
- remove: function(table, c, wo) {
379
- var tbodyIndex, $tbody,
380
- $tbodies = c.$tbodies,
381
- remove = (wo.columns || [ 'primary', 'secondary', 'tertiary' ]).join(' ');
382
- c.$headers.removeClass(remove);
383
- c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
384
- for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
385
- $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
386
- $tbody.children('tr').each(function() {
387
- $(this).children().removeClass(remove);
388
- });
389
- ts.processTbody(table, $tbody, false); // restore tbody
390
- }
391
- }
392
- });
393
-
394
- })(jQuery);
395
-
396
- /*! Widget: filter - updated 2018-03-18 (v2.30.0) *//*
397
- * Requires tablesorter v2.8+ and jQuery 1.7+
398
- * by Rob Garrison
399
- */
400
- ;( function ( $ ) {
401
- 'use strict';
402
- var tsf, tsfRegex,
403
- ts = $.tablesorter || {},
404
- tscss = ts.css,
405
- tskeyCodes = ts.keyCodes;
406
-
407
- $.extend( tscss, {
408
- filterRow : 'tablesorter-filter-row',
409
- filter : 'tablesorter-filter',
410
- filterDisabled : 'disabled',
411
- filterRowHide : 'hideme'
412
- });
413
-
414
- $.extend( tskeyCodes, {
415
- backSpace : 8,
416
- escape : 27,
417
- space : 32,
418
- left : 37,
419
- down : 40
420
- });
421
-
422
- ts.addWidget({
423
- id: 'filter',
424
- priority: 50,
425
- options : {
426
- filter_cellFilter : '', // css class name added to the filter cell ( string or array )
427
- filter_childRows : false, // if true, filter includes child row content in the search
428
- filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
429
- filter_childWithSibs : true, // if true, include matching child row siblings
430
- filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
431
- filter_columnFilters : true, // if true, a filter will be added to the top of each table column
432
- filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
433
- filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
434
- filter_defaultFilter : {}, // add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
435
- filter_excludeFilter : {}, // filters to exclude, per column
436
- filter_external : '', // jQuery selector string ( or jQuery object ) of external filters
437
- filter_filteredRow : 'filtered', // class added to filtered rows; define in css with "display:none" to hide the filtered-out rows
438
- filter_filterLabel : 'Filter "{{label}}" column by...', // Aria-label added to filter input/select; see #1495
439
- filter_formatter : null, // add custom filter elements to the filter row
440
- filter_functions : null, // add custom filter functions using this option
441
- filter_hideEmpty : true, // hide filter row when table is empty
442
- filter_hideFilters : false, // collapse filter row when mouse leaves the area
443
- filter_ignoreCase : true, // if true, make all searches case-insensitive
444
- filter_liveSearch : true, // if true, search column content while the user types ( with a delay )
445
- filter_matchType : { 'input': 'exact', 'select': 'exact' }, // global query settings ('exact' or 'match'); overridden by "filter-match" or "filter-exact" class
446
- filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
447
- filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting )
448
- filter_reset : null, // jQuery selector string of an element used to reset the filters
449
- filter_resetOnEsc : true, // Reset filter input when the user presses escape - normalized across browsers
450
- filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters
451
- filter_searchDelay : 300, // typing delay in milliseconds before starting a search
452
- filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
453
- filter_selectSource : null, // include a function to return an array of values to be added to the column filter select
454
- filter_selectSourceSeparator : '|', // filter_selectSource array text left of the separator is added to the option value, right into the option text
455
- filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
456
- filter_startsWith : false, // if true, filter start from the beginning of the cell contents
457
- filter_useParsedData : false // filter all data using parsed content
458
- },
459
- format: function( table, c, wo ) {
460
- if ( !c.$table.hasClass( 'hasFilters' ) ) {
461
- tsf.init( table, c, wo );
462
- }
463
- },
464
- remove: function( table, c, wo, refreshing ) {
465
- var tbodyIndex, $tbody,
466
- $table = c.$table,
467
- $tbodies = c.$tbodies,
468
- events = (
469
- 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
470
- 'filterAndSortReset filterFomatterUpdate filterEnd search stickyHeadersInit '
471
- ).split( ' ' ).join( c.namespace + 'filter ' );
472
- $table
473
- .removeClass( 'hasFilters' )
474
- // add filter namespace to all BUT search
475
- .unbind( events.replace( ts.regex.spaces, ' ' ) )
476
- // remove the filter row even if refreshing, because the column might have been moved
477
- .find( '.' + tscss.filterRow ).remove();
478
- wo.filter_initialized = false;
479
- if ( refreshing ) { return; }
480
- for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
481
- $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
482
- $tbody.children().removeClass( wo.filter_filteredRow ).show();
483
- ts.processTbody( table, $tbody, false ); // restore tbody
484
- }
485
- if ( wo.filter_reset ) {
486
- $( document ).undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' );
487
- }
488
- }
489
- });
490
-
491
- tsf = ts.filter = {
492
-
493
- // regex used in filter 'check' functions - not for general use and not documented
494
- regex: {
495
- regex : /^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/, // regex to test for regex
496
- child : /tablesorter-childRow/, // child row class name; this gets updated in the script
497
- filtered : /filtered/, // filtered (hidden) row class name; updated in the script
498
- type : /undefined|number/, // check type
499
- exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
500
- operators : /[<>=]/g, // replace operators
501
- query : '(q|query)', // replace filter queries
502
- wild01 : /\?/g, // wild card match 0 or 1
503
- wild0More : /\*/g, // wild care match 0 or more
504
- quote : /\"/g,
505
- isNeg1 : /(>=?\s*-\d)/,
506
- isNeg2 : /(<=?\s*\d)/
507
- },
508
- // function( c, data ) { }
509
- // c = table.config
510
- // data.$row = jQuery object of the row currently being processed
511
- // data.$cells = jQuery object of all cells within the current row
512
- // data.filters = array of filters for all columns ( some may be undefined )
513
- // data.filter = filter for the current column
514
- // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true )
515
- // data.exact = table cell text ( or parsed data if column parser enabled; may be a number & not a string )
516
- // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true; may be a number & not a string )
517
- // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true )
518
- // data.cacheArray = An array of parsed content from each table cell in the row being processed
519
- // data.index = column index; table = table element ( DOM )
520
- // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
521
- types: {
522
- or : function( c, data, vars ) {
523
- // look for "|", but not if it is inside of a regular expression
524
- if ( ( tsfRegex.orTest.test( data.iFilter ) || tsfRegex.orSplit.test( data.filter ) ) &&
525
- // this test for regex has potential to slow down the overall search
526
- !tsfRegex.regex.test( data.filter ) ) {
527
- var indx, filterMatched, query, regex,
528
- // duplicate data but split filter
529
- data2 = $.extend( {}, data ),
530
- filter = data.filter.split( tsfRegex.orSplit ),
531
- iFilter = data.iFilter.split( tsfRegex.orSplit ),
532
- len = filter.length;
533
- for ( indx = 0; indx < len; indx++ ) {
534
- data2.nestedFilters = true;
535
- data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
536
- data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
537
- query = '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')';
538
- try {
539
- // use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
540
- // e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
541
- regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
542
- // filterMatched = data2.filter === '' && indx > 0 ? true
543
- // look for an exact match with the 'or' unless the 'filter-match' class is found
544
- filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
545
- if ( filterMatched ) {
546
- return filterMatched;
547
- }
548
- } catch ( error ) {
549
- return null;
550
- }
551
- }
552
- // may be null from processing types
553
- return filterMatched || false;
554
- }
555
- return null;
556
- },
557
- // Look for an AND or && operator ( logical and )
558
- and : function( c, data, vars ) {
559
- if ( tsfRegex.andTest.test( data.filter ) ) {
560
- var indx, filterMatched, result, query, regex,
561
- // duplicate data but split filter
562
- data2 = $.extend( {}, data ),
563
- filter = data.filter.split( tsfRegex.andSplit ),
564
- iFilter = data.iFilter.split( tsfRegex.andSplit ),
565
- len = filter.length;
566
- for ( indx = 0; indx < len; indx++ ) {
567
- data2.nestedFilters = true;
568
- data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
569
- data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
570
- query = ( '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')' )
571
- // replace wild cards since /(a*)/i will match anything
572
- .replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' );
573
- try {
574
- // use try/catch just in case RegExp is invalid
575
- regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
576
- // look for an exact match with the 'and' unless the 'filter-match' class is found
577
- result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
578
- if ( indx === 0 ) {
579
- filterMatched = result;
580
- } else {
581
- filterMatched = filterMatched && result;
582
- }
583
- } catch ( error ) {
584
- return null;
585
- }
586
- }
587
- // may be null from processing types
588
- return filterMatched || false;
589
- }
590
- return null;
591
- },
592
- // Look for regex
593
- regex: function( c, data ) {
594
- if ( tsfRegex.regex.test( data.filter ) ) {
595
- var matches,
596
- // cache regex per column for optimal speed
597
- regex = data.filter_regexCache[ data.index ] || tsfRegex.regex.exec( data.filter ),
598
- isRegex = regex instanceof RegExp;
599
- try {
600
- if ( !isRegex ) {
601
- // force case insensitive search if ignoreCase option set?
602
- // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
603
- data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
604
- }
605
- matches = regex.test( data.exact );
606
- } catch ( error ) {
607
- matches = false;
608
- }
609
- return matches;
610
- }
611
- return null;
612
- },
613
- // Look for operators >, >=, < or <=
614
- operators: function( c, data ) {
615
- // ignore empty strings... because '' < 10 is true
616
- if ( tsfRegex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
617
- var cachedValue, result, txt,
618
- table = c.table,
619
- parsed = data.parsed[ data.index ],
620
- query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
621
- parser = c.parsers[ data.index ] || {},
622
- savedSearch = query;
623
- // parse filter value in case we're comparing numbers ( dates )
624
- if ( parsed || parser.type === 'numeric' ) {
625
- txt = $.trim( '' + data.iFilter.replace( tsfRegex.operators, '' ) );
626
- result = tsf.parseFilter( c, txt, data, true );
627
- query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
628
- }
629
- // iExact may be numeric - see issue #149;
630
- // check if cached is defined, because sometimes j goes out of range? ( numeric columns )
631
- if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
632
- typeof data.cache !== 'undefined' ) {
633
- cachedValue = data.cache;
634
- } else {
635
- txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
636
- cachedValue = ts.formatFloat( txt, table );
637
- }
638
- if ( tsfRegex.gtTest.test( data.iFilter ) ) {
639
- result = tsfRegex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
640
- } else if ( tsfRegex.ltTest.test( data.iFilter ) ) {
641
- result = tsfRegex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
642
- }
643
- // keep showing all rows if nothing follows the operator
644
- if ( !result && savedSearch === '' ) {
645
- result = true;
646
- }
647
- return result;
648
- }
649
- return null;
650
- },
651
- // Look for a not match
652
- notMatch: function( c, data ) {
653
- if ( tsfRegex.notTest.test( data.iFilter ) ) {
654
- var indx,
655
- txt = data.iFilter.replace( '!', '' ),
656
- filter = tsf.parseFilter( c, txt, data ) || '';
657
- if ( tsfRegex.exact.test( filter ) ) {
658
- // look for exact not matches - see #628
659
- filter = filter.replace( tsfRegex.exact, '' );
660
- return filter === '' ? true : $.trim( filter ) !== data.iExact;
661
- } else {
662
- indx = data.iExact.search( $.trim( filter ) );
663
- return filter === '' ? true :
664
- // return true if not found
665
- data.anyMatch ? indx < 0 :
666
- // return false if found
667
- !( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
668
- }
669
- }
670
- return null;
671
- },
672
- // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
673
- exact: function( c, data ) {
674
- /*jshint eqeqeq:false */
675
- if ( tsfRegex.exact.test( data.iFilter ) ) {
676
- var txt = data.iFilter.replace( tsfRegex.exact, '' ),
677
- filter = tsf.parseFilter( c, txt, data ) || '';
678
- // eslint-disable-next-line eqeqeq
679
- return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
680
- }
681
- return null;
682
- },
683
- // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
684
- range : function( c, data ) {
685
- if ( tsfRegex.toTest.test( data.iFilter ) ) {
686
- var result, tmp, range1, range2,
687
- table = c.table,
688
- index = data.index,
689
- parsed = data.parsed[index],
690
- // make sure the dash is for a range and not indicating a negative number
691
- query = data.iFilter.split( tsfRegex.toSplit );
692
-
693
- tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
694
- range1 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
695
- tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
696
- range2 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
697
- // parse filter value in case we're comparing numbers ( dates )
698
- if ( parsed || c.parsers[ index ].type === 'numeric' ) {
699
- result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
700
- range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
701
- result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
702
- range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
703
- }
704
- if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
705
- result = data.cache;
706
- } else {
707
- tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
708
- result = ts.formatFloat( tmp, table );
709
- }
710
- if ( range1 > range2 ) {
711
- tmp = range1; range1 = range2; range2 = tmp; // swap
712
- }
713
- return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
714
- }
715
- return null;
716
- },
717
- // Look for wild card: ? = single, * = multiple, or | = logical OR
718
- wild : function( c, data ) {
719
- if ( tsfRegex.wildOrTest.test( data.iFilter ) ) {
720
- var query = '' + ( tsf.parseFilter( c, data.iFilter, data ) || '' );
721
- // look for an exact match with the 'or' unless the 'filter-match' class is found
722
- if ( !tsfRegex.wildTest.test( query ) && data.nestedFilters ) {
723
- query = data.isMatch ? query : '^(' + query + ')$';
724
- }
725
- // parsing the filter may not work properly when using wildcards =/
726
- try {
727
- return new RegExp(
728
- query.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' ),
729
- c.widgetOptions.filter_ignoreCase ? 'i' : ''
730
- )
731
- .test( data.exact );
732
- } catch ( error ) {
733
- return null;
734
- }
735
- }
736
- return null;
737
- },
738
- // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
739
- fuzzy: function( c, data ) {
740
- if ( tsfRegex.fuzzyTest.test( data.iFilter ) ) {
741
- var indx,
742
- patternIndx = 0,
743
- len = data.iExact.length,
744
- txt = data.iFilter.slice( 1 ),
745
- pattern = tsf.parseFilter( c, txt, data ) || '';
746
- for ( indx = 0; indx < len; indx++ ) {
747
- if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
748
- patternIndx += 1;
749
- }
750
- }
751
- return patternIndx === pattern.length;
752
- }
753
- return null;
754
- }
755
- },
756
- init: function( table ) {
757
- // filter language options
758
- ts.language = $.extend( true, {}, {
759
- to : 'to',
760
- or : 'or',
761
- and : 'and'
762
- }, ts.language );
763
-
764
- var options, string, txt, $header, column, val, fxn, noSelect,
765
- c = table.config,
766
- wo = c.widgetOptions,
767
- processStr = function(prefix, str, suffix) {
768
- str = str.trim();
769
- // don't include prefix/suffix if str is empty
770
- return str === '' ? '' : (prefix || '') + str + (suffix || '');
771
- };
772
- c.$table.addClass( 'hasFilters' );
773
- c.lastSearch = [];
774
-
775
- // define timers so using clearTimeout won't cause an undefined error
776
- wo.filter_searchTimer = null;
777
- wo.filter_initTimer = null;
778
- wo.filter_formatterCount = 0;
779
- wo.filter_formatterInit = [];
780
- wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
781
- wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
782
-
783
- val = '\\{' + tsfRegex.query + '\\}';
784
- $.extend( tsfRegex, {
785
- child : new RegExp( c.cssChildRow ),
786
- filtered : new RegExp( wo.filter_filteredRow ),
787
- alreadyFiltered : new RegExp( '(\\s+(-' + processStr('|', ts.language.or) + processStr('|', ts.language.to) + ')\\s+)', 'i' ),
788
- toTest : new RegExp( '\\s+(-' + processStr('|', ts.language.to) + ')\\s+', 'i' ),
789
- toSplit : new RegExp( '(?:\\s+(?:-' + processStr('|', ts.language.to) + ')\\s+)', 'gi' ),
790
- andTest : new RegExp( '\\s+(' + processStr('', ts.language.and, '|') + '&&)\\s+', 'i' ),
791
- andSplit : new RegExp( '(?:\\s+(?:' + processStr('', ts.language.and, '|') + '&&)\\s+)', 'gi' ),
792
- orTest : new RegExp( '(\\|' + processStr('|\\s+', ts.language.or, '\\s+') + ')', 'i' ),
793
- orSplit : new RegExp( '(?:\\|' + processStr('|\\s+(?:', ts.language.or, ')\\s+') + ')', 'gi' ),
794
- iQuery : new RegExp( val, 'i' ),
795
- igQuery : new RegExp( val, 'ig' ),
796
- operTest : /^[<>]=?/,
797
- gtTest : />/,
798
- gteTest : />=/,
799
- ltTest : /</,
800
- lteTest : /<=/,
801
- notTest : /^\!/,
802
- wildOrTest : /[\?\*\|]/,
803
- wildTest : /\?\*/,
804
- fuzzyTest : /^~/,
805
- exactTest : /[=\"\|!]/
806
- });
807
-
808
- // don't build filter row if columnFilters is false or all columns are set to 'filter-false'
809
- // see issue #156
810
- val = c.$headers.filter( '.filter-false, .parser-false' ).length;
811
- if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
812
- // build filter row
813
- tsf.buildRow( table, c, wo );
814
- }
815
-
816
- txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
817
- 'filterAndSortReset filterResetSaved filterEnd search '.split( ' ' ).join( c.namespace + 'filter ' );
818
- c.$table.bind( txt, function( event, filter ) {
819
- val = wo.filter_hideEmpty &&
820
- $.isEmptyObject( c.cache ) &&
821
- !( c.delayInit && event.type === 'appendCache' );
822
- // hide filter row using the 'filtered' class name
823
- c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
824
- if ( !/(search|filter)/.test( event.type ) ) {
825
- event.stopPropagation();
826
- tsf.buildDefault( table, true );
827
- }
828
- // Add filterAndSortReset - see #1361
829
- if ( event.type === 'filterReset' || event.type === 'filterAndSortReset' ) {
830
- c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
831
- if ( event.type === 'filterAndSortReset' ) {
832
- ts.sortReset( this.config, function() {
833
- tsf.searching( table, [] );
834
- });
835
- } else {
836
- tsf.searching( table, [] );
837
- }
838
- } else if ( event.type === 'filterResetSaved' ) {
839
- ts.storage( table, 'tablesorter-filters', '' );
840
- } else if ( event.type === 'filterEnd' ) {
841
- tsf.buildDefault( table, true );
842
- } else {
843
- // send false argument to force a new search; otherwise if the filter hasn't changed,
844
- // it will return
845
- filter = event.type === 'search' ? filter :
846
- event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
847
- if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
848
- // force a new search since content has changed
849
- c.lastCombinedFilter = null;
850
- c.lastSearch = [];
851
- // update filterFormatters after update (& small delay) - Fixes #1237
852
- setTimeout(function() {
853
- c.$table.triggerHandler( 'filterFomatterUpdate' );
854
- }, 100);
855
- }
856
- // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
857
- // input ensures all inputs are updated when a search is triggered on the table
858
- // $( 'table' ).trigger( 'search', [...] );
859
- tsf.searching( table, filter, true );
860
- }
861
- return false;
862
- });
863
-
864
- // reset button/link
865
- if ( wo.filter_reset ) {
866
- if ( wo.filter_reset instanceof $ ) {
867
- // reset contains a jQuery object, bind to it
868
- wo.filter_reset.click( function() {
869
- c.$table.triggerHandler( 'filterReset' );
870
- });
871
- } else if ( $( wo.filter_reset ).length ) {
872
- // reset is a jQuery selector, use event delegation
873
- $( document )
874
- .undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' )
875
- .delegate( wo.filter_reset, 'click' + c.namespace + 'filter', function() {
876
- // trigger a reset event, so other functions ( filter_formatter ) know when to reset
877
- c.$table.triggerHandler( 'filterReset' );
878
- });
879
- }
880
- }
881
- if ( wo.filter_functions ) {
882
- for ( column = 0; column < c.columns; column++ ) {
883
- fxn = ts.getColumnData( table, wo.filter_functions, column );
884
- if ( fxn ) {
885
- // remove 'filter-select' from header otherwise the options added here are replaced with
886
- // all options
887
- $header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
888
- // don't build select if 'filter-false' or 'parser-false' set
889
- noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
890
- options = '';
891
- if ( fxn === true && noSelect ) {
892
- tsf.buildSelect( table, column );
893
- } else if ( typeof fxn === 'object' && noSelect ) {
894
- // add custom drop down list
895
- for ( string in fxn ) {
896
- if ( typeof string === 'string' ) {
897
- options += options === '' ?
898
- '<option value="">' +
899
- ( $header.data( 'placeholder' ) ||
900
- $header.attr( 'data-placeholder' ) ||
901
- wo.filter_placeholder.select ||
902
- ''
903
- ) +
904
- '</option>' : '';
905
- val = string;
906
- txt = string;
907
- if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
908
- val = string.split( wo.filter_selectSourceSeparator );
909
- txt = val[1];
910
- val = val[0];
911
- }
912
- options += '<option ' +
913
- ( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
914
- 'value="' + val + '">' + txt + '</option>';
915
- }
916
- }
917
- c.$table
918
- .find( 'thead' )
919
- .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
920
- .append( options );
921
- txt = wo.filter_selectSource;
922
- fxn = typeof txt === 'function' ? true : ts.getColumnData( table, txt, column );
923
- if ( fxn ) {
924
- // updating so the extra options are appended
925
- tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
926
- }
927
- }
928
- }
929
- }
930
- }
931
- // not really updating, but if the column has both the 'filter-select' class &
932
- // filter_functions set to true, it would append the same options twice.
933
- tsf.buildDefault( table, true );
934
-
935
- tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
936
- if ( wo.filter_external ) {
937
- tsf.bindSearch( table, wo.filter_external );
938
- }
939
-
940
- if ( wo.filter_hideFilters ) {
941
- tsf.hideFilters( c );
942
- }
943
-
944
- // show processing icon
945
- if ( c.showProcessing ) {
946
- txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter-sp ' );
947
- c.$table
948
- .unbind( txt.replace( ts.regex.spaces, ' ' ) )
949
- .bind( txt, function( event, columns ) {
950
- // only add processing to certain columns to all columns
951
- $header = ( columns ) ?
952
- c.$table
953
- .find( '.' + tscss.header )
954
- .filter( '[data-column]' )
955
- .filter( function() {
956
- return columns[ $( this ).data( 'column' ) ] !== '';
957
- }) : '';
958
- ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
959
- });
960
- }
961
-
962
- // set filtered rows count ( intially unfiltered )
963
- c.filteredRows = c.totalRows;
964
-
965
- // add default values
966
- txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
967
- c.$table
968
- .unbind( txt.replace( ts.regex.spaces, ' ' ) )
969
- .bind( txt, function() {
970
- tsf.completeInit( this );
971
- });
972
- // if filter widget is added after pager has initialized; then set filter init flag
973
- if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
974
- c.$table.triggerHandler( 'filterFomatterUpdate' );
975
- setTimeout( function() {
976
- tsf.filterInitComplete( c );
977
- }, 100 );
978
- } else if ( !wo.filter_initialized ) {
979
- tsf.completeInit( table );
980
- }
981
- },
982
- completeInit: function( table ) {
983
- // redefine 'c' & 'wo' so they update properly inside this callback
984
- var c = table.config,
985
- wo = c.widgetOptions,
986
- filters = tsf.setDefaults( table, c, wo ) || [];
987
- if ( filters.length ) {
988
- // prevent delayInit from triggering a cache build if filters are empty
989
- if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
990
- ts.setFilters( table, filters, true );
991
- }
992
- }
993
- c.$table.triggerHandler( 'filterFomatterUpdate' );
994
- // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
995
- setTimeout( function() {
996
- if ( !wo.filter_initialized ) {
997
- tsf.filterInitComplete( c );
998
- }
999
- }, 100 );
1000
- },
1001
-
1002
- // $cell parameter, but not the config, is passed to the filter_formatters,
1003
- // so we have to work with it instead
1004
- formatterUpdated: function( $cell, column ) {
1005
- // prevent error if $cell is undefined - see #1056
1006
- var $table = $cell && $cell.closest( 'table' );
1007
- var config = $table.length && $table[0].config,
1008
- wo = config && config.widgetOptions;
1009
- if ( wo && !wo.filter_initialized ) {
1010
- // add updates by column since this function
1011
- // may be called numerous times before initialization
1012
- wo.filter_formatterInit[ column ] = 1;
1013
- }
1014
- },
1015
- filterInitComplete: function( c ) {
1016
- var indx, len,
1017
- wo = c.widgetOptions,
1018
- count = 0,
1019
- completed = function() {
1020
- wo.filter_initialized = true;
1021
- // update lastSearch - it gets cleared often
1022
- c.lastSearch = c.$table.data( 'lastSearch' );
1023
- c.$table.triggerHandler( 'filterInit', c );
1024
- tsf.findRows( c.table, c.lastSearch || [] );
1025
- if (ts.debug(c, 'filter')) {
1026
- console.log('Filter >> Widget initialized');
1027
- }
1028
- };
1029
- if ( $.isEmptyObject( wo.filter_formatter ) ) {
1030
- completed();
1031
- } else {
1032
- len = wo.filter_formatterInit.length;
1033
- for ( indx = 0; indx < len; indx++ ) {
1034
- if ( wo.filter_formatterInit[ indx ] === 1 ) {
1035
- count++;
1036
- }
1037
- }
1038
- clearTimeout( wo.filter_initTimer );
1039
- if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
1040
- // filter widget initialized
1041
- completed();
1042
- } else if ( !wo.filter_initialized ) {
1043
- // fall back in case a filter_formatter doesn't call
1044
- // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
1045
- wo.filter_initTimer = setTimeout( function() {
1046
- completed();
1047
- }, 500 );
1048
- }
1049
- }
1050
- },
1051
- // encode or decode filters for storage; see #1026
1052
- processFilters: function( filters, encode ) {
1053
- var indx,
1054
- // fixes #1237; previously returning an encoded "filters" value
1055
- result = [],
1056
- mode = encode ? encodeURIComponent : decodeURIComponent,
1057
- len = filters.length;
1058
- for ( indx = 0; indx < len; indx++ ) {
1059
- if ( filters[ indx ] ) {
1060
- result[ indx ] = mode( filters[ indx ] );
1061
- }
1062
- }
1063
- return result;
1064
- },
1065
- setDefaults: function( table, c, wo ) {
1066
- var isArray, saved, indx, col, $filters,
1067
- // get current ( default ) filters
1068
- filters = ts.getFilters( table ) || [];
1069
- if ( wo.filter_saveFilters && ts.storage ) {
1070
- saved = ts.storage( table, 'tablesorter-filters' ) || [];
1071
- isArray = $.isArray( saved );
1072
- // make sure we're not just getting an empty array
1073
- if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
1074
- filters = tsf.processFilters( saved );
1075
- }
1076
- }
1077
- // if no filters saved, then check default settings
1078
- if ( filters.join( '' ) === '' ) {
1079
- // allow adding default setting to external filters
1080
- $filters = c.$headers.add( wo.filter_$externalFilters )
1081
- .filter( '[' + wo.filter_defaultAttrib + ']' );
1082
- for ( indx = 0; indx <= c.columns; indx++ ) {
1083
- // include data-column='all' external filters
1084
- col = indx === c.columns ? 'all' : indx;
1085
- filters[ indx ] = $filters
1086
- .filter( '[data-column="' + col + '"]' )
1087
- .attr( wo.filter_defaultAttrib ) || filters[indx] || '';
1088
- }
1089
- }
1090
- c.$table.data( 'lastSearch', filters );
1091
- return filters;
1092
- },
1093
- parseFilter: function( c, filter, data, parsed ) {
1094
- return parsed || data.parsed[ data.index ] ?
1095
- c.parsers[ data.index ].format( filter, c.table, [], data.index ) :
1096
- filter;
1097
- },
1098
- buildRow: function( table, c, wo ) {
1099
- var $filter, col, column, $header, makeSelect, disabled, name, ffxn, tmp,
1100
- // c.columns defined in computeThIndexes()
1101
- cellFilter = wo.filter_cellFilter,
1102
- columns = c.columns,
1103
- arry = $.isArray( cellFilter ),
1104
- buildFilter = '<tr role="search" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
1105
- for ( column = 0; column < columns; column++ ) {
1106
- if ( c.$headerIndexed[ column ].length ) {
1107
- // account for entire column set with colspan. See #1047
1108
- tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
1109
- if ( tmp > 1 ) {
1110
- buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
1111
- } else {
1112
- buildFilter += '<td data-column="' + column + '"';
1113
- }
1114
- if ( arry ) {
1115
- buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
1116
- } else {
1117
- buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
1118
- }
1119
- buildFilter += '></td>';
1120
- }
1121
- }
1122
- c.$filters = $( buildFilter += '</tr>' )
1123
- .appendTo( c.$table.children( 'thead' ).eq( 0 ) )
1124
- .children( 'td' );
1125
- // build each filter input
1126
- for ( column = 0; column < columns; column++ ) {
1127
- disabled = false;
1128
- // assuming last cell of a column is the main column
1129
- $header = c.$headerIndexed[ column ];
1130
- if ( $header && $header.length ) {
1131
- // $filter = c.$filters.filter( '[data-column="' + column + '"]' );
1132
- $filter = tsf.getColumnElm( c, c.$filters, column );
1133
- ffxn = ts.getColumnData( table, wo.filter_functions, column );
1134
- makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
1135
- $header.hasClass( 'filter-select' );
1136
- // get data from jQuery data, metadata, headers option or header class name
1137
- col = ts.getColumnData( table, c.headers, column );
1138
- disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
1139
- ts.getData( $header[0], col, 'parser' ) === 'false';
1140
-
1141
- if ( makeSelect ) {
1142
- buildFilter = $( '<select>' ).appendTo( $filter );
1143
- } else {
1144
- ffxn = ts.getColumnData( table, wo.filter_formatter, column );
1145
- if ( ffxn ) {
1146
- wo.filter_formatterCount++;
1147
- buildFilter = ffxn( $filter, column );
1148
- // no element returned, so lets go find it
1149
- if ( buildFilter && buildFilter.length === 0 ) {
1150
- buildFilter = $filter.children( 'input' );
1151
- }
1152
- // element not in DOM, so lets attach it
1153
- if ( buildFilter && ( buildFilter.parent().length === 0 ||
1154
- ( buildFilter.parent().length && buildFilter.parent()[0] !== $filter[0] ) ) ) {
1155
- $filter.append( buildFilter );
1156
- }
1157
- } else {
1158
- buildFilter = $( '<input type="search">' ).appendTo( $filter );
1159
- }
1160
- if ( buildFilter ) {
1161
- tmp = $header.data( 'placeholder' ) ||
1162
- $header.attr( 'data-placeholder' ) ||
1163
- wo.filter_placeholder.search || '';
1164
- buildFilter.attr( 'placeholder', tmp );
1165
- }
1166
- }
1167
- if ( buildFilter ) {
1168
- // add filter class name
1169
- name = ( $.isArray( wo.filter_cssFilter ) ?
1170
- ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
1171
- wo.filter_cssFilter ) || '';
1172
- // copy data-column from table cell (it will include colspan)
1173
- buildFilter.addClass( tscss.filter + ' ' + name );
1174
- name = wo.filter_filterLabel;
1175
- tmp = name.match(/{{([^}]+?)}}/g);
1176
- if (!tmp) {
1177
- tmp = [ '{{label}}' ];
1178
- }
1179
- $.each(tmp, function(indx, attr) {
1180
- var regex = new RegExp(attr, 'g'),
1181
- data = $header.attr('data-' + attr.replace(/{{|}}/g, '')),
1182
- text = typeof data === 'undefined' ? $header.text() : data;
1183
- name = name.replace( regex, $.trim( text ) );
1184
- });
1185
- buildFilter.attr({
1186
- 'data-column': $filter.attr( 'data-column' ),
1187
- 'aria-label': name
1188
- });
1189
- if ( disabled ) {
1190
- buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
1191
- }
1192
- }
1193
- }
1194
- }
1195
- },
1196
- bindSearch: function( table, $el, internal ) {
1197
- table = $( table )[0];
1198
- $el = $( $el ); // allow passing a selector string
1199
- if ( !$el.length ) { return; }
1200
- var tmp,
1201
- c = table.config,
1202
- wo = c.widgetOptions,
1203
- namespace = c.namespace + 'filter',
1204
- $ext = wo.filter_$externalFilters;
1205
- if ( internal !== true ) {
1206
- // save anyMatch element
1207
- tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
1208
- wo.filter_$anyMatch = $el.filter( tmp );
1209
- if ( $ext && $ext.length ) {
1210
- wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
1211
- } else {
1212
- wo.filter_$externalFilters = $el;
1213
- }
1214
- // update values ( external filters added after table initialization )
1215
- ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
1216
- }
1217
- // unbind events
1218
- tmp = ( 'keypress keyup keydown search change input '.split( ' ' ).join( namespace + ' ' ) );
1219
- $el
1220
- // use data attribute instead of jQuery data since the head is cloned without including
1221
- // the data/binding
1222
- .attr( 'data-lastSearchTime', new Date().getTime() )
1223
- .unbind( tmp.replace( ts.regex.spaces, ' ' ) )
1224
- .bind( 'keydown' + namespace, function( event ) {
1225
- if ( event.which === tskeyCodes.escape && !table.config.widgetOptions.filter_resetOnEsc ) {
1226
- // prevent keypress event
1227
- return false;
1228
- }
1229
- })
1230
- .bind( 'keyup' + namespace, function( event ) {
1231
- wo = table.config.widgetOptions; // make sure "wo" isn't cached
1232
- var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
1233
- liveSearch = typeof wo.filter_liveSearch === 'boolean' ? wo.filter_liveSearch :
1234
- ts.getColumnData( table, wo.filter_liveSearch, column );
1235
- if ( typeof liveSearch === 'undefined' ) {
1236
- liveSearch = wo.filter_liveSearch.fallback || false;
1237
- }
1238
- $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
1239
- // emulate what webkit does.... escape clears the filter
1240
- if ( event.which === tskeyCodes.escape ) {
1241
- // make sure to restore the last value on escape
1242
- this.value = wo.filter_resetOnEsc ? '' : c.lastSearch[column];
1243
- // don't return if the search value is empty ( all rows need to be revealed )
1244
- } else if ( this.value !== '' && (
1245
- // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
1246
- ( typeof liveSearch === 'number' && this.value.length < liveSearch ) ||
1247
- // let return & backspace continue on, but ignore arrows & non-valid characters
1248
- ( event.which !== tskeyCodes.enter && event.which !== tskeyCodes.backSpace &&
1249
- ( event.which < tskeyCodes.space || ( event.which >= tskeyCodes.left && event.which <= tskeyCodes.down ) ) ) ) ) {
1250
- return;
1251
- // live search
1252
- } else if ( liveSearch === false ) {
1253
- if ( this.value !== '' && event.which !== tskeyCodes.enter ) {
1254
- return;
1255
- }
1256
- }
1257
- // change event = no delay; last true flag tells getFilters to skip newest timed input
1258
- tsf.searching( table, true, true, column );
1259
- })
1260
- // include change for select - fixes #473
1261
- .bind( 'search change keypress input blur '.split( ' ' ).join( namespace + ' ' ), function( event ) {
1262
- // don't get cached data, in case data-column changes dynamically
1263
- var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
1264
- eventType = event.type,
1265
- liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
1266
- wo.filter_liveSearch :
1267
- ts.getColumnData( table, wo.filter_liveSearch, column );
1268
- if ( table.config.widgetOptions.filter_initialized &&
1269
- // immediate search if user presses enter
1270
- ( event.which === tskeyCodes.enter ||
1271
- // immediate search if a "search" or "blur" is triggered on the input
1272
- ( eventType === 'search' || eventType === 'blur' ) ||
1273
- // change & input events must be ignored if liveSearch !== true
1274
- ( eventType === 'change' || eventType === 'input' ) &&
1275
- // prevent search if liveSearch is a number
1276
- ( liveSearch === true || liveSearch !== true && event.target.nodeName !== 'INPUT' ) &&
1277
- // don't allow 'change' or 'input' event to process if the input value
1278
- // is the same - fixes #685
1279
- this.value !== c.lastSearch[column]
1280
- )
1281
- ) {
1282
- event.preventDefault();
1283
- // init search with no delay
1284
- $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
1285
- tsf.searching( table, eventType !== 'keypress', true, column );
1286
- }
1287
- });
1288
- },
1289
- searching: function( table, filter, skipFirst, column ) {
1290
- var liveSearch,
1291
- wo = table.config.widgetOptions;
1292
- if (typeof column === 'undefined') {
1293
- // no delay
1294
- liveSearch = false;
1295
- } else {
1296
- liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
1297
- wo.filter_liveSearch :
1298
- // get column setting, or set to fallback value, or default to false
1299
- ts.getColumnData( table, wo.filter_liveSearch, column );
1300
- if ( typeof liveSearch === 'undefined' ) {
1301
- liveSearch = wo.filter_liveSearch.fallback || false;
1302
- }
1303
- }
1304
- clearTimeout( wo.filter_searchTimer );
1305
- if ( typeof filter === 'undefined' || filter === true ) {
1306
- // delay filtering
1307
- wo.filter_searchTimer = setTimeout( function() {
1308
- tsf.checkFilters( table, filter, skipFirst );
1309
- }, liveSearch ? wo.filter_searchDelay : 10 );
1310
- } else {
1311
- // skip delay
1312
- tsf.checkFilters( table, filter, skipFirst );
1313
- }
1314
- },
1315
- equalFilters: function (c, filter1, filter2) {
1316
- var indx,
1317
- f1 = [],
1318
- f2 = [],
1319
- len = c.columns + 1; // add one to include anyMatch filter
1320
- filter1 = $.isArray(filter1) ? filter1 : [];
1321
- filter2 = $.isArray(filter2) ? filter2 : [];
1322
- for (indx = 0; indx < len; indx++) {
1323
- f1[indx] = filter1[indx] || '';
1324
- f2[indx] = filter2[indx] || '';
1325
- }
1326
- return f1.join(',') === f2.join(',');
1327
- },
1328
- checkFilters: function( table, filter, skipFirst ) {
1329
- var c = table.config,
1330
- wo = c.widgetOptions,
1331
- filterArray = $.isArray( filter ),
1332
- filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
1333
- currentFilters = filters || []; // current filter values
1334
- // prevent errors if delay init is set
1335
- if ( $.isEmptyObject( c.cache ) ) {
1336
- // update cache if delayInit set & pager has initialized ( after user initiates a search )
1337
- if ( c.delayInit && ( !c.pager || c.pager && c.pager.initialized ) ) {
1338
- ts.updateCache( c, function() {
1339
- tsf.checkFilters( table, false, skipFirst );
1340
- });
1341
- }
1342
- return;
1343
- }
1344
- // add filter array back into inputs
1345
- if ( filterArray ) {
1346
- ts.setFilters( table, filters, false, skipFirst !== true );
1347
- if ( !wo.filter_initialized ) {
1348
- c.lastSearch = [];
1349
- c.lastCombinedFilter = '';
1350
- }
1351
- }
1352
- if ( wo.filter_hideFilters ) {
1353
- // show/hide filter row as needed
1354
- c.$table
1355
- .find( '.' + tscss.filterRow )
1356
- .triggerHandler( tsf.hideFiltersCheck( c ) ? 'mouseleave' : 'mouseenter' );
1357
- }
1358
- // return if the last search is the same; but filter === false when updating the search
1359
- // see example-widget-filter.html filter toggle buttons
1360
- if ( tsf.equalFilters(c, c.lastSearch, currentFilters) && filter !== false ) {
1361
- return;
1362
- } else if ( filter === false ) {
1363
- // force filter refresh
1364
- c.lastCombinedFilter = '';
1365
- c.lastSearch = [];
1366
- }
1367
- // define filter inside it is false
1368
- filters = filters || [];
1369
- // convert filters to strings - see #1070
1370
- filters = Array.prototype.map ?
1371
- filters.map( String ) :
1372
- // for IE8 & older browsers - maybe not the best method
1373
- filters.join( '\ufffd' ).split( '\ufffd' );
1374
-
1375
- if ( wo.filter_initialized ) {
1376
- c.$table.triggerHandler( 'filterStart', [ filters ] );
1377
- }
1378
- if ( c.showProcessing ) {
1379
- // give it time for the processing icon to kick in
1380
- setTimeout( function() {
1381
- tsf.findRows( table, filters, currentFilters );
1382
- return false;
1383
- }, 30 );
1384
- } else {
1385
- tsf.findRows( table, filters, currentFilters );
1386
- return false;
1387
- }
1388
- },
1389
- hideFiltersCheck: function( c ) {
1390
- if (typeof c.widgetOptions.filter_hideFilters === 'function') {
1391
- var val = c.widgetOptions.filter_hideFilters( c );
1392
- if (typeof val === 'boolean') {
1393
- return val;
1394
- }
1395
- }
1396
- return ts.getFilters( c.$table ).join( '' ) === '';
1397
- },
1398
- hideFilters: function( c, $table ) {
1399
- var timer;
1400
- ( $table || c.$table )
1401
- .find( '.' + tscss.filterRow )
1402
- .addClass( tscss.filterRowHide )
1403
- .bind( 'mouseenter mouseleave', function( e ) {
1404
- // save event object - http://bugs.jquery.com/ticket/12140
1405
- var event = e,
1406
- $row = $( this );
1407
- clearTimeout( timer );
1408
- timer = setTimeout( function() {
1409
- if ( /enter|over/.test( event.type ) ) {
1410
- $row.removeClass( tscss.filterRowHide );
1411
- } else {
1412
- // don't hide if input has focus
1413
- // $( ':focus' ) needs jQuery 1.6+
1414
- if ( $( document.activeElement ).closest( 'tr' )[0] !== $row[0] ) {
1415
- // don't hide row if any filter has a value
1416
- $row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) );
1417
- }
1418
- }
1419
- }, 200 );
1420
- })
1421
- .find( 'input, select' ).bind( 'focus blur', function( e ) {
1422
- var event = e,
1423
- $row = $( this ).closest( 'tr' );
1424
- clearTimeout( timer );
1425
- timer = setTimeout( function() {
1426
- clearTimeout( timer );
1427
- // don't hide row if any filter has a value
1428
- $row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) && event.type !== 'focus' );
1429
- }, 200 );
1430
- });
1431
- },
1432
- defaultFilter: function( filter, mask ) {
1433
- if ( filter === '' ) { return filter; }
1434
- var regex = tsfRegex.iQuery,
1435
- maskLen = mask.match( tsfRegex.igQuery ).length,
1436
- query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
1437
- len = query.length - 1,
1438
- indx = 0,
1439
- val = mask;
1440
- if ( len < 1 && maskLen > 1 ) {
1441
- // only one 'word' in query but mask has >1 slots
1442
- query[1] = query[0];
1443
- }
1444
- // replace all {query} with query words...
1445
- // if query = 'Bob', then convert mask from '!{query}' to '!Bob'
1446
- // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank'
1447
- while ( regex.test( val ) ) {
1448
- val = val.replace( regex, query[indx++] || '' );
1449
- if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
1450
- val = mask.replace( regex, val );
1451
- }
1452
- }
1453
- return val;
1454
- },
1455
- getLatestSearch: function( $input ) {
1456
- if ( $input ) {
1457
- return $input.sort( function( a, b ) {
1458
- return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
1459
- });
1460
- }
1461
- return $input || $();
1462
- },
1463
- findRange: function( c, val, ignoreRanges ) {
1464
- // look for multiple columns '1-3,4-6,8' in data-column
1465
- var temp, ranges, range, start, end, singles, i, indx, len,
1466
- columns = [];
1467
- if ( /^[0-9]+$/.test( val ) ) {
1468
- // always return an array
1469
- return [ parseInt( val, 10 ) ];
1470
- }
1471
- // process column range
1472
- if ( !ignoreRanges && /-/.test( val ) ) {
1473
- ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
1474
- len = ranges ? ranges.length : 0;
1475
- for ( indx = 0; indx < len; indx++ ) {
1476
- range = ranges[indx].split( /\s*-\s*/ );
1477
- start = parseInt( range[0], 10 ) || 0;
1478
- end = parseInt( range[1], 10 ) || ( c.columns - 1 );
1479
- if ( start > end ) {
1480
- temp = start; start = end; end = temp; // swap
1481
- }
1482
- if ( end >= c.columns ) {
1483
- end = c.columns - 1;
1484
- }
1485
- for ( ; start <= end; start++ ) {
1486
- columns[ columns.length ] = start;
1487
- }
1488
- // remove processed range from val
1489
- val = val.replace( ranges[ indx ], '' );
1490
- }
1491
- }
1492
- // process single columns
1493
- if ( !ignoreRanges && /,/.test( val ) ) {
1494
- singles = val.split( /\s*,\s*/ );
1495
- len = singles.length;
1496
- for ( i = 0; i < len; i++ ) {
1497
- if ( singles[ i ] !== '' ) {
1498
- indx = parseInt( singles[ i ], 10 );
1499
- if ( indx < c.columns ) {
1500
- columns[ columns.length ] = indx;
1501
- }
1502
- }
1503
- }
1504
- }
1505
- // return all columns
1506
- if ( !columns.length ) {
1507
- for ( indx = 0; indx < c.columns; indx++ ) {
1508
- columns[ columns.length ] = indx;
1509
- }
1510
- }
1511
- return columns;
1512
- },
1513
- getColumnElm: function( c, $elements, column ) {
1514
- // data-column may contain multiple columns '1-3,5-6,8'
1515
- // replaces: c.$filters.filter( '[data-column="' + column + '"]' );
1516
- return $elements.filter( function() {
1517
- var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
1518
- return $.inArray( column, cols ) > -1;
1519
- });
1520
- },
1521
- multipleColumns: function( c, $input ) {
1522
- // look for multiple columns '1-3,4-6,8' in data-column
1523
- var wo = c.widgetOptions,
1524
- // only target 'all' column inputs on initialization
1525
- // & don't target 'all' column inputs if they don't exist
1526
- targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
1527
- val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
1528
- return tsf.findRange( c, val, !targets );
1529
- },
1530
- processTypes: function( c, data, vars ) {
1531
- var ffxn,
1532
- filterMatched = null,
1533
- matches = null;
1534
- for ( ffxn in tsf.types ) {
1535
- if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
1536
- matches = tsf.types[ffxn]( c, data, vars );
1537
- if ( matches !== null ) {
1538
- data.matchedOn = ffxn;
1539
- filterMatched = matches;
1540
- }
1541
- }
1542
- }
1543
- return filterMatched;
1544
- },
1545
- matchType: function( c, columnIndex ) {
1546
- var isMatch,
1547
- wo = c.widgetOptions,
1548
- $el = c.$headerIndexed[ columnIndex ];
1549
- // filter-exact > filter-match > filter_matchType for type
1550
- if ( $el.hasClass( 'filter-exact' ) ) {
1551
- isMatch = false;
1552
- } else if ( $el.hasClass( 'filter-match' ) ) {
1553
- isMatch = true;
1554
- } else {
1555
- // filter-select is not applied when filter_functions are used, so look for a select
1556
- if ( wo.filter_columnFilters ) {
1557
- $el = c.$filters
1558
- .find( '.' + tscss.filter )
1559
- .add( wo.filter_$externalFilters )
1560
- .filter( '[data-column="' + columnIndex + '"]' );
1561
- } else if ( wo.filter_$externalFilters ) {
1562
- $el = wo.filter_$externalFilters.filter( '[data-column="' + columnIndex + '"]' );
1563
- }
1564
- isMatch = $el.length ?
1565
- c.widgetOptions.filter_matchType[ ( $el[ 0 ].nodeName || '' ).toLowerCase() ] === 'match' :
1566
- // default to exact, if no inputs found
1567
- false;
1568
- }
1569
- return isMatch;
1570
- },
1571
- processRow: function( c, data, vars ) {
1572
- var result, filterMatched,
1573
- fxn, ffxn, txt,
1574
- wo = c.widgetOptions,
1575
- showRow = true,
1576
- hasAnyMatchInput = wo.filter_$anyMatch && wo.filter_$anyMatch.length,
1577
-
1578
- // if wo.filter_$anyMatch data-column attribute is changed dynamically
1579
- // we don't want to do an "anyMatch" search on one column using data
1580
- // for the entire row - see #998
1581
- columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
1582
- // look for multiple columns '1-3,4-6,8'
1583
- tsf.multipleColumns( c, wo.filter_$anyMatch ) :
1584
- [];
1585
- data.$cells = data.$row.children();
1586
- data.matchedOn = null;
1587
- if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
1588
- data.anyMatch = true;
1589
- data.isMatch = true;
1590
- data.rowArray = data.$cells.map( function( i ) {
1591
- if ( $.inArray( i, columnIndex ) > -1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
1592
- if ( data.parsed[ i ] ) {
1593
- txt = data.cacheArray[ i ];
1594
- } else {
1595
- txt = data.rawArray[ i ];
1596
- txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
1597
- if ( c.sortLocaleCompare ) {
1598
- txt = ts.replaceAccents( txt );
1599
- }
1600
- }
1601
- return txt;
1602
- }
1603
- }).get();
1604
- data.filter = data.anyMatchFilter;
1605
- data.iFilter = data.iAnyMatchFilter;
1606
- data.exact = data.rowArray.join( ' ' );
1607
- data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
1608
- data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
1609
- vars.excludeMatch = vars.noAnyMatch;
1610
- filterMatched = tsf.processTypes( c, data, vars );
1611
- if ( filterMatched !== null ) {
1612
- showRow = filterMatched;
1613
- } else {
1614
- if ( wo.filter_startsWith ) {
1615
- showRow = false;
1616
- // data.rowArray may not contain all columns
1617
- columnIndex = Math.min( c.columns, data.rowArray.length );
1618
- while ( !showRow && columnIndex > 0 ) {
1619
- columnIndex--;
1620
- showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
1621
- }
1622
- } else {
1623
- showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
1624
- }
1625
- }
1626
- data.anyMatch = false;
1627
- // no other filters to process
1628
- if ( data.filters.join( '' ) === data.filter ) {
1629
- return showRow;
1630
- }
1631
- }
1632
-
1633
- for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
1634
- data.filter = data.filters[ columnIndex ];
1635
- data.index = columnIndex;
1636
-
1637
- // filter types to exclude, per column
1638
- vars.excludeMatch = vars.excludeFilter[ columnIndex ];
1639
-
1640
- // ignore if filter is empty or disabled
1641
- if ( data.filter ) {
1642
- data.cache = data.cacheArray[ columnIndex ];
1643
- result = data.parsed[ columnIndex ] ? data.cache : data.rawArray[ columnIndex ] || '';
1644
- data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
1645
- data.iExact = !tsfRegex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
1646
- data.exact.toLowerCase() : data.exact;
1647
- data.isMatch = tsf.matchType( c, columnIndex );
1648
-
1649
- result = showRow; // if showRow is true, show that row
1650
-
1651
- // in case select filter option has a different value vs text 'a - z|A through Z'
1652
- ffxn = wo.filter_columnFilters ?
1653
- c.$filters.add( wo.filter_$externalFilters )
1654
- .filter( '[data-column="' + columnIndex + '"]' )
1655
- .find( 'select option:selected' )
1656
- .attr( 'data-function-name' ) || '' : '';
1657
- // replace accents - see #357
1658
- if ( c.sortLocaleCompare ) {
1659
- data.filter = ts.replaceAccents( data.filter );
1660
- }
1661
-
1662
- // replace column specific default filters - see #1088
1663
- if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
1664
- data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
1665
- }
1666
-
1667
- // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
1668
- // data.filter = case sensitive
1669
- data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
1670
- fxn = vars.functions[ columnIndex ];
1671
- filterMatched = null;
1672
- if ( fxn ) {
1673
- if ( typeof fxn === 'function' ) {
1674
- // filter callback( exact cell content, parser normalized content,
1675
- // filter input value, column index, jQuery row object )
1676
- filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
1677
- } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
1678
- // selector option function
1679
- txt = ffxn || data.filter;
1680
- filterMatched =
1681
- fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
1682
- }
1683
- }
1684
- if ( filterMatched === null ) {
1685
- // cycle through the different filters
1686
- // filters return a boolean or null if nothing matches
1687
- filterMatched = tsf.processTypes( c, data, vars );
1688
- // select with exact match; ignore "and" or "or" within the text; fixes #1486
1689
- txt = fxn === true && (data.matchedOn === 'and' || data.matchedOn === 'or');
1690
- if ( filterMatched !== null && !txt) {
1691
- result = filterMatched;
1692
- // Look for match, and add child row data for matching
1693
- } else {
1694
- // check fxn (filter-select in header) after filter types are checked
1695
- // without this, the filter + jQuery UI selectmenu demo was breaking
1696
- if ( fxn === true ) {
1697
- // default selector uses exact match unless 'filter-match' class is found
1698
- result = data.isMatch ?
1699
- // data.iExact may be a number
1700
- ( '' + data.iExact ).search( data.iFilter ) >= 0 :
1701
- data.filter === data.exact;
1702
- } else {
1703
- txt = ( data.iExact + data.childRowText ).indexOf( tsf.parseFilter( c, data.iFilter, data ) );
1704
- result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
1705
- }
1706
- }
1707
- } else {
1708
- result = filterMatched;
1709
- }
1710
- showRow = ( result ) ? showRow : false;
1711
- }
1712
- }
1713
- return showRow;
1714
- },
1715
- findRows: function( table, filters, currentFilters ) {
1716
- if (
1717
- tsf.equalFilters(table.config, table.config.lastSearch, currentFilters) ||
1718
- !table.config.widgetOptions.filter_initialized
1719
- ) {
1720
- return;
1721
- }
1722
- var len, norm_rows, rowData, $rows, $row, rowIndex, tbodyIndex, $tbody, columnIndex,
1723
- isChild, childRow, lastSearch, showRow, showParent, time, val, indx,
1724
- notFiltered, searchFiltered, query, injected, res, id, txt,
1725
- storedFilters = $.extend( [], filters ),
1726
- c = table.config,
1727
- wo = c.widgetOptions,
1728
- debug = ts.debug(c, 'filter'),
1729
- // data object passed to filters; anyMatch is a flag for the filters
1730
- data = {
1731
- anyMatch: false,
1732
- filters: filters,
1733
- // regex filter type cache
1734
- filter_regexCache : []
1735
- },
1736
- vars = {
1737
- // anyMatch really screws up with these types of filters
1738
- noAnyMatch: [ 'range', 'operators' ],
1739
- // cache filter variables that use ts.getColumnData in the main loop
1740
- functions : [],
1741
- excludeFilter : [],
1742
- defaultColFilter : [],
1743
- defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
1744
- };
1745
- // parse columns after formatter, in case the class is added at that point
1746
- data.parsed = [];
1747
- for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
1748
- data.parsed[ columnIndex ] = wo.filter_useParsedData ||
1749
- // parser has a "parsed" parameter
1750
- ( c.parsers && c.parsers[ columnIndex ] && c.parsers[ columnIndex ].parsed ||
1751
- // getData may not return 'parsed' if other 'filter-' class names exist
1752
- // ( e.g. <th class="filter-select filter-parsed"> )
1753
- ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
1754
- ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
1755
- c.$headerIndexed[ columnIndex ].hasClass( 'filter-parsed' ) );
1756
-
1757
- vars.functions[ columnIndex ] =
1758
- ts.getColumnData( table, wo.filter_functions, columnIndex ) ||
1759
- c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
1760
- vars.defaultColFilter[ columnIndex ] =
1761
- ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
1762
- vars.excludeFilter[ columnIndex ] =
1763
- ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
1764
- }
1765
-
1766
- if ( debug ) {
1767
- console.log( 'Filter >> Starting filter widget search', filters );
1768
- time = new Date();
1769
- }
1770
- // filtered rows count
1771
- c.filteredRows = 0;
1772
- c.totalRows = 0;
1773
- currentFilters = ( storedFilters || [] );
1774
-
1775
- for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
1776
- $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
1777
- // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
1778
- // $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
1779
- columnIndex = c.columns;
1780
- // convert stored rows into a jQuery object
1781
- norm_rows = c.cache[ tbodyIndex ].normalized;
1782
- $rows = $( $.map( norm_rows, function( el ) {
1783
- return el[ columnIndex ].$row.get();
1784
- }) );
1785
-
1786
- if ( currentFilters.join('') === '' || wo.filter_serversideFiltering ) {
1787
- $rows
1788
- .removeClass( wo.filter_filteredRow )
1789
- .not( '.' + c.cssChildRow )
1790
- .css( 'display', '' );
1791
- } else {
1792
- // filter out child rows
1793
- $rows = $rows.not( '.' + c.cssChildRow );
1794
- len = $rows.length;
1795
-
1796
- if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
1797
- typeof filters[c.columns] !== 'undefined' ) {
1798
- data.anyMatchFlag = true;
1799
- data.anyMatchFilter = '' + (
1800
- filters[ c.columns ] ||
1801
- wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
1802
- ''
1803
- );
1804
- if ( wo.filter_columnAnyMatch ) {
1805
- // specific columns search
1806
- query = data.anyMatchFilter.split( tsfRegex.andSplit );
1807
- injected = false;
1808
- for ( indx = 0; indx < query.length; indx++ ) {
1809
- res = query[ indx ].split( ':' );
1810
- if ( res.length > 1 ) {
1811
- // make the column a one-based index ( non-developers start counting from one :P )
1812
- if ( isNaN( res[0] ) ) {
1813
- $.each( c.headerContent, function( i, txt ) {
1814
- // multiple matches are possible
1815
- if ( txt.toLowerCase().indexOf( res[0] ) > -1 ) {
1816
- id = i;
1817
- filters[ id ] = res[1];
1818
- }
1819
- });
1820
- } else {
1821
- id = parseInt( res[0], 10 ) - 1;
1822
- }
1823
- if ( id >= 0 && id < c.columns ) { // if id is an integer
1824
- filters[ id ] = res[1];
1825
- query.splice( indx, 1 );
1826
- indx--;
1827
- injected = true;
1828
- }
1829
- }
1830
- }
1831
- if ( injected ) {
1832
- data.anyMatchFilter = query.join( ' && ' );
1833
- }
1834
- }
1835
- }
1836
-
1837
- // optimize searching only through already filtered rows - see #313
1838
- searchFiltered = wo.filter_searchFiltered;
1839
- lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
1840
- if ( searchFiltered ) {
1841
- // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
1842
- for ( indx = 0; indx < columnIndex + 1; indx++ ) {
1843
- val = filters[indx] || '';
1844
- // break out of loop if we've already determined not to search filtered rows
1845
- if ( !searchFiltered ) { indx = columnIndex; }
1846
- // search already filtered rows if...
1847
- searchFiltered = searchFiltered && lastSearch.length &&
1848
- // there are no changes from beginning of filter
1849
- val.indexOf( lastSearch[indx] || '' ) === 0 &&
1850
- // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
1851
- !tsfRegex.alreadyFiltered.test( val ) &&
1852
- // if we are not doing exact matches, using '|' ( logical or ) or not '!'
1853
- !tsfRegex.exactTest.test( val ) &&
1854
- // don't search only filtered if the value is negative
1855
- // ( '> -10' => '> -100' will ignore hidden rows )
1856
- !( tsfRegex.isNeg1.test( val ) || tsfRegex.isNeg2.test( val ) ) &&
1857
- // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
1858
- !( val !== '' && c.$filters && c.$filters.filter( '[data-column="' + indx + '"]' ).find( 'select' ).length &&
1859
- !tsf.matchType( c, indx ) );
1860
- }
1861
- }
1862
- notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
1863
- // can't search when all rows are hidden - this happens when looking for exact matches
1864
- if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
1865
- if ( debug ) {
1866
- console.log( 'Filter >> Searching through ' +
1867
- ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
1868
- }
1869
- if ( data.anyMatchFlag ) {
1870
- if ( c.sortLocaleCompare ) {
1871
- // replace accents
1872
- data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
1873
- }
1874
- if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultAnyFilter ) ) {
1875
- data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
1876
- // clear search filtered flag because default filters are not saved to the last search
1877
- searchFiltered = false;
1878
- }
1879
- // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
1880
- // when c.ignoreCase is true, the cache contains all lower case data
1881
- data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
1882
- data.anyMatchFilter :
1883
- data.anyMatchFilter.toLowerCase();
1884
- }
1885
-
1886
- // loop through the rows
1887
- for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
1888
-
1889
- txt = $rows[ rowIndex ].className;
1890
- // the first row can never be a child row
1891
- isChild = rowIndex && tsfRegex.child.test( txt );
1892
- // skip child rows & already filtered rows
1893
- if ( isChild || ( searchFiltered && tsfRegex.filtered.test( txt ) ) ) {
1894
- continue;
1895
- }
1896
-
1897
- data.$row = $rows.eq( rowIndex );
1898
- data.rowIndex = rowIndex;
1899
- data.cacheArray = norm_rows[ rowIndex ];
1900
- rowData = data.cacheArray[ c.columns ];
1901
- data.rawArray = rowData.raw;
1902
- data.childRowText = '';
1903
-
1904
- if ( !wo.filter_childByColumn ) {
1905
- txt = '';
1906
- // child row cached text
1907
- childRow = rowData.child;
1908
- // so, if 'table.config.widgetOptions.filter_childRows' is true and there is
1909
- // a match anywhere in the child row, then it will make the row visible
1910
- // checked here so the option can be changed dynamically
1911
- for ( indx = 0; indx < childRow.length; indx++ ) {
1912
- txt += ' ' + childRow[indx].join( ' ' ) || '';
1913
- }
1914
- data.childRowText = wo.filter_childRows ?
1915
- ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
1916
- '';
1917
- }
1918
-
1919
- showRow = false;
1920
- showParent = tsf.processRow( c, data, vars );
1921
- $row = rowData.$row;
1922
-
1923
- // don't pass reference to val
1924
- val = showParent ? true : false;
1925
- childRow = rowData.$row.filter( ':gt(0)' );
1926
- if ( wo.filter_childRows && childRow.length ) {
1927
- if ( wo.filter_childByColumn ) {
1928
- if ( !wo.filter_childWithSibs ) {
1929
- // hide all child rows
1930
- childRow.addClass( wo.filter_filteredRow );
1931
- // if only showing resulting child row, only include parent
1932
- $row = $row.eq( 0 );
1933
- }
1934
- // cycle through each child row
1935
- for ( indx = 0; indx < childRow.length; indx++ ) {
1936
- data.$row = childRow.eq( indx );
1937
- data.cacheArray = rowData.child[ indx ];
1938
- data.rawArray = data.cacheArray;
1939
- val = tsf.processRow( c, data, vars );
1940
- // use OR comparison on child rows
1941
- showRow = showRow || val;
1942
- if ( !wo.filter_childWithSibs && val ) {
1943
- childRow.eq( indx ).removeClass( wo.filter_filteredRow );
1944
- }
1945
- }
1946
- }
1947
- // keep parent row match even if no child matches... see #1020
1948
- showRow = showRow || showParent;
1949
- } else {
1950
- showRow = val;
1951
- }
1952
- $row
1953
- .toggleClass( wo.filter_filteredRow, !showRow )[0]
1954
- .display = showRow ? '' : 'none';
1955
- }
1956
- }
1957
- c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
1958
- c.totalRows += $rows.length;
1959
- ts.processTbody( table, $tbody, false );
1960
- }
1961
- // lastCombinedFilter is no longer used internally
1962
- c.lastCombinedFilter = storedFilters.join(''); // save last search
1963
- // don't save 'filters' directly since it may have altered ( AnyMatch column searches )
1964
- c.lastSearch = storedFilters;
1965
- c.$table.data( 'lastSearch', storedFilters );
1966
- if ( wo.filter_saveFilters && ts.storage ) {
1967
- ts.storage( table, 'tablesorter-filters', tsf.processFilters( storedFilters, true ) );
1968
- }
1969
- if ( debug ) {
1970
- console.log( 'Filter >> Completed search' + ts.benchmark(time) );
1971
- }
1972
- if ( wo.filter_initialized ) {
1973
- c.$table.triggerHandler( 'filterBeforeEnd', c );
1974
- c.$table.triggerHandler( 'filterEnd', c );
1975
- }
1976
- setTimeout( function() {
1977
- ts.applyWidget( c.table ); // make sure zebra widget is applied
1978
- }, 0 );
1979
- },
1980
- getOptionSource: function( table, column, onlyAvail ) {
1981
- table = $( table )[0];
1982
- var c = table.config,
1983
- wo = c.widgetOptions,
1984
- arry = false,
1985
- source = wo.filter_selectSource,
1986
- last = c.$table.data( 'lastSearch' ) || [],
1987
- fxn = typeof source === 'function' ? true : ts.getColumnData( table, source, column );
1988
-
1989
- if ( onlyAvail && last[column] !== '' ) {
1990
- onlyAvail = false;
1991
- }
1992
-
1993
- // filter select source option
1994
- if ( fxn === true ) {
1995
- // OVERALL source
1996
- arry = source( table, column, onlyAvail );
1997
- } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
1998
- // selectSource is a jQuery object or string of options
1999
- return fxn;
2000
- } else if ( $.isArray( fxn ) ) {
2001
- arry = fxn;
2002
- } else if ( $.type( source ) === 'object' && fxn ) {
2003
- // custom select source function for a SPECIFIC COLUMN
2004
- arry = fxn( table, column, onlyAvail );
2005
- // abort - updating the selects from an external method
2006
- if (arry === null) {
2007
- return null;
2008
- }
2009
- }
2010
- if ( arry === false ) {
2011
- // fall back to original method
2012
- arry = tsf.getOptions( table, column, onlyAvail );
2013
- }
2014
-
2015
- return tsf.processOptions( table, column, arry );
2016
-
2017
- },
2018
- processOptions: function( table, column, arry ) {
2019
- if ( !$.isArray( arry ) ) {
2020
- return false;
2021
- }
2022
- table = $( table )[0];
2023
- var cts, txt, indx, len, parsedTxt, str,
2024
- c = table.config,
2025
- validColumn = typeof column !== 'undefined' && column !== null && column >= 0 && column < c.columns,
2026
- direction = validColumn ? c.$headerIndexed[ column ].hasClass( 'filter-select-sort-desc' ) : false,
2027
- parsed = [];
2028
- // get unique elements and sort the list
2029
- // if $.tablesorter.sortText exists ( not in the original tablesorter ),
2030
- // then natural sort the list otherwise use a basic sort
2031
- arry = $.grep( arry, function( value, indx ) {
2032
- if ( value.text ) {
2033
- return true;
2034
- }
2035
- return $.inArray( value, arry ) === indx;
2036
- });
2037
- if ( validColumn && c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
2038
- // unsorted select options
2039
- return arry;
2040
- } else {
2041
- len = arry.length;
2042
- // parse select option values
2043
- for ( indx = 0; indx < len; indx++ ) {
2044
- txt = arry[ indx ];
2045
- // check for object
2046
- str = txt.text ? txt.text : txt;
2047
- // sortNatural breaks if you don't pass it strings
2048
- parsedTxt = ( validColumn && c.parsers && c.parsers.length &&
2049
- c.parsers[ column ].format( str, table, [], column ) || str ).toString();
2050
- parsedTxt = c.widgetOptions.filter_ignoreCase ? parsedTxt.toLowerCase() : parsedTxt;
2051
- // parse array data using set column parser; this DOES NOT pass the original
2052
- // table cell to the parser format function
2053
- if ( txt.text ) {
2054
- txt.parsed = parsedTxt;
2055
- parsed[ parsed.length ] = txt;
2056
- } else {
2057
- parsed[ parsed.length ] = {
2058
- text : txt,
2059
- // check parser length - fixes #934
2060
- parsed : parsedTxt
2061
- };
2062
- }
2063
- }
2064
- // sort parsed select options
2065
- cts = c.textSorter || '';
2066
- parsed.sort( function( a, b ) {
2067
- var x = direction ? b.parsed : a.parsed,
2068
- y = direction ? a.parsed : b.parsed;
2069
- if ( validColumn && typeof cts === 'function' ) {
2070
- // custom OVERALL text sorter
2071
- return cts( x, y, true, column, table );
2072
- } else if ( validColumn && typeof cts === 'object' && cts.hasOwnProperty( column ) ) {
2073
- // custom text sorter for a SPECIFIC COLUMN
2074
- return cts[column]( x, y, true, column, table );
2075
- } else if ( ts.sortNatural ) {
2076
- // fall back to natural sort
2077
- return ts.sortNatural( x, y );
2078
- }
2079
- // using an older version! do a basic sort
2080
- return true;
2081
- });
2082
- // rebuild arry from sorted parsed data
2083
- arry = [];
2084
- len = parsed.length;
2085
- for ( indx = 0; indx < len; indx++ ) {
2086
- arry[ arry.length ] = parsed[indx];
2087
- }
2088
- return arry;
2089
- }
2090
- },
2091
- getOptions: function( table, column, onlyAvail ) {
2092
- table = $( table )[0];
2093
- var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen,
2094
- c = table.config,
2095
- wo = c.widgetOptions,
2096
- arry = [];
2097
- for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
2098
- cache = c.cache[tbodyIndex];
2099
- len = c.cache[tbodyIndex].normalized.length;
2100
- // loop through the rows
2101
- for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
2102
- // get cached row from cache.row ( old ) or row data object
2103
- // ( new; last item in normalized array )
2104
- row = cache.row ?
2105
- cache.row[ rowIndex ] :
2106
- cache.normalized[ rowIndex ][ c.columns ].$row[0];
2107
- // check if has class filtered
2108
- if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
2109
- continue;
2110
- }
2111
- // get non-normalized cell content
2112
- if ( wo.filter_useParsedData ||
2113
- c.parsers[column].parsed ||
2114
- c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
2115
- arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ column ];
2116
- // child row parsed data
2117
- if ( wo.filter_childRows && wo.filter_childByColumn ) {
2118
- childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length - 1;
2119
- for ( indx = 0; indx < childLen; indx++ ) {
2120
- arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ c.columns ].child[ indx ][ column ];
2121
- }
2122
- }
2123
- } else {
2124
- // get raw cached data instead of content directly from the cells
2125
- arry[ arry.length ] = cache.normalized[ rowIndex ][ c.columns ].raw[ column ];
2126
- // child row unparsed data
2127
- if ( wo.filter_childRows && wo.filter_childByColumn ) {
2128
- childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length;
2129
- for ( indx = 1; indx < childLen; indx++ ) {
2130
- child = cache.normalized[ rowIndex ][ c.columns ].$row.eq( indx ).children().eq( column );
2131
- arry[ arry.length ] = '' + ts.getElementText( c, child, column );
2132
- }
2133
- }
2134
- }
2135
- }
2136
- }
2137
- return arry;
2138
- },
2139
- buildSelect: function( table, column, arry, updating, onlyAvail ) {
2140
- table = $( table )[0];
2141
- column = parseInt( column, 10 );
2142
- if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
2143
- return;
2144
- }
2145
-
2146
- var indx, val, txt, t, $filters, $filter, option,
2147
- c = table.config,
2148
- wo = c.widgetOptions,
2149
- node = c.$headerIndexed[ column ],
2150
- // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
2151
- options = '<option value="">' +
2152
- ( node.data( 'placeholder' ) ||
2153
- node.attr( 'data-placeholder' ) ||
2154
- wo.filter_placeholder.select || ''
2155
- ) + '</option>',
2156
- // Get curent filter value
2157
- currentValue = c.$table
2158
- .find( 'thead' )
2159
- .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
2160
- .val();
2161
-
2162
- // nothing included in arry ( external source ), so get the options from
2163
- // filter_selectSource or column data
2164
- if ( typeof arry === 'undefined' || arry === '' ) {
2165
- arry = tsf.getOptionSource( table, column, onlyAvail );
2166
- // abort, selects are updated by an external method
2167
- if (arry === null) {
2168
- return;
2169
- }
2170
- }
2171
-
2172
- if ( $.isArray( arry ) ) {
2173
- // build option list
2174
- for ( indx = 0; indx < arry.length; indx++ ) {
2175
- option = arry[ indx ];
2176
- if ( option.text ) {
2177
- // OBJECT!! add data-function-name in case the value is set in filter_functions
2178
- option['data-function-name'] = typeof option.value === 'undefined' ? option.text : option.value;
2179
-
2180
- // support jQuery < v1.8, otherwise the below code could be shortened to
2181
- // options += $( '<option>', option )[ 0 ].outerHTML;
2182
- options += '<option';
2183
- for ( val in option ) {
2184
- if ( option.hasOwnProperty( val ) && val !== 'text' ) {
2185
- options += ' ' + val + '="' + option[ val ].replace( tsfRegex.quote, '&quot;' ) + '"';
2186
- }
2187
- }
2188
- if ( !option.value ) {
2189
- options += ' value="' + option.text.replace( tsfRegex.quote, '&quot;' ) + '"';
2190
- }
2191
- options += '>' + option.text.replace( tsfRegex.quote, '&quot;' ) + '</option>';
2192
- // above code is needed in jQuery < v1.8
2193
-
2194
- // make sure we don't turn an object into a string (objects without a "text" property)
2195
- } else if ( '' + option !== '[object Object]' ) {
2196
- txt = option = ( '' + option ).replace( tsfRegex.quote, '&quot;' );
2197
- val = txt;
2198
- // allow including a symbol in the selectSource array
2199
- // 'a-z|A through Z' so that 'a-z' becomes the option value
2200
- // and 'A through Z' becomes the option text
2201
- if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
2202
- t = txt.split( wo.filter_selectSourceSeparator );
2203
- val = t[0];
2204
- txt = t[1];
2205
- }
2206
- // replace quotes - fixes #242 & ignore empty strings
2207
- // see http://stackoverflow.com/q/14990971/145346
2208
- options += option !== '' ?
2209
- '<option ' +
2210
- ( val === txt ? '' : 'data-function-name="' + option + '" ' ) +
2211
- 'value="' + val + '">' + txt +
2212
- '</option>' : '';
2213
- }
2214
- }
2215
- // clear arry so it doesn't get appended twice
2216
- arry = [];
2217
- }
2218
-
2219
- // update all selects in the same column ( clone thead in sticky headers &
2220
- // any external selects ) - fixes 473
2221
- $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
2222
- .find( '.' + tscss.filter );
2223
- if ( wo.filter_$externalFilters ) {
2224
- $filters = $filters && $filters.length ?
2225
- $filters.add( wo.filter_$externalFilters ) :
2226
- wo.filter_$externalFilters;
2227
- }
2228
- $filter = $filters.filter( 'select[data-column="' + column + '"]' );
2229
-
2230
- // make sure there is a select there!
2231
- if ( $filter.length ) {
2232
- $filter[ updating ? 'html' : 'append' ]( options );
2233
- if ( !$.isArray( arry ) ) {
2234
- // append options if arry is provided externally as a string or jQuery object
2235
- // options ( default value ) was already added
2236
- $filter.append( arry ).val( currentValue );
2237
- }
2238
- $filter.val( currentValue );
2239
- }
2240
- },
2241
- buildDefault: function( table, updating ) {
2242
- var columnIndex, $header, noSelect,
2243
- c = table.config,
2244
- wo = c.widgetOptions,
2245
- columns = c.columns;
2246
- // build default select dropdown
2247
- for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
2248
- $header = c.$headerIndexed[columnIndex];
2249
- noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
2250
- // look for the filter-select class; build/update it if found
2251
- if ( ( $header.hasClass( 'filter-select' ) ||
2252
- ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
2253
- tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
2254
- }
2255
- }
2256
- }
2257
- };
2258
-
2259
- // filter regex variable
2260
- tsfRegex = tsf.regex;
2261
-
2262
- ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
2263
- var i, $filters, $column, cols,
2264
- filters = [],
2265
- c = table ? $( table )[0].config : '',
2266
- wo = c ? c.widgetOptions : '';
2267
- if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
2268
- // setFilters called, but last search is exactly the same as the current
2269
- // fixes issue #733 & #903 where calling update causes the input values to reset
2270
- ( $.isArray(setFilters) && tsf.equalFilters(c, setFilters, c.lastSearch) )
2271
- ) {
2272
- return $( table ).data( 'lastSearch' ) || [];
2273
- }
2274
- if ( c ) {
2275
- if ( c.$filters ) {
2276
- $filters = c.$filters.find( '.' + tscss.filter );
2277
- }
2278
- if ( wo.filter_$externalFilters ) {
2279
- $filters = $filters && $filters.length ?
2280
- $filters.add( wo.filter_$externalFilters ) :
2281
- wo.filter_$externalFilters;
2282
- }
2283
- if ( $filters && $filters.length ) {
2284
- filters = setFilters || [];
2285
- for ( i = 0; i < c.columns + 1; i++ ) {
2286
- cols = ( i === c.columns ?
2287
- // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
2288
- wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
2289
- '[data-column="' + i + '"]' );
2290
- $column = $filters.filter( cols );
2291
- if ( $column.length ) {
2292
- // move the latest search to the first slot in the array
2293
- $column = tsf.getLatestSearch( $column );
2294
- if ( $.isArray( setFilters ) ) {
2295
- // skip first ( latest input ) to maintain cursor position while typing
2296
- if ( skipFirst && $column.length > 1 ) {
2297
- $column = $column.slice( 1 );
2298
- }
2299
- if ( i === c.columns ) {
2300
- // prevent data-column='all' from filling data-column='0,1' ( etc )
2301
- cols = $column.filter( wo.filter_anyColumnSelector );
2302
- $column = cols.length ? cols : $column;
2303
- }
2304
- $column
2305
- .val( setFilters[ i ] )
2306
- // must include a namespace here; but not c.namespace + 'filter'?
2307
- .trigger( 'change' + c.namespace );
2308
- } else {
2309
- filters[i] = $column.val() || '';
2310
- // don't change the first... it will move the cursor
2311
- if ( i === c.columns ) {
2312
- // don't update range columns from 'all' setting
2313
- $column
2314
- .slice( 1 )
2315
- .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
2316
- .val( filters[ i ] );
2317
- } else {
2318
- $column
2319
- .slice( 1 )
2320
- .val( filters[ i ] );
2321
- }
2322
- }
2323
- // save any match input dynamically
2324
- if ( i === c.columns && $column.length ) {
2325
- wo.filter_$anyMatch = $column;
2326
- }
2327
- }
2328
- }
2329
- }
2330
- }
2331
- return filters;
2332
- };
2333
-
2334
- ts.setFilters = function( table, filter, apply, skipFirst ) {
2335
- var c = table ? $( table )[0].config : '',
2336
- valid = ts.getFilters( table, true, filter, skipFirst );
2337
- // default apply to "true"
2338
- if ( typeof apply === 'undefined' ) {
2339
- apply = true;
2340
- }
2341
- if ( c && apply ) {
2342
- // ensure new set filters are applied, even if the search is the same
2343
- c.lastCombinedFilter = null;
2344
- c.lastSearch = [];
2345
- tsf.searching( c.table, filter, skipFirst );
2346
- c.$table.triggerHandler( 'filterFomatterUpdate' );
2347
- }
2348
- return valid.length !== 0;
2349
- };
2350
-
2351
- })( jQuery );
2352
-
2353
- /*! Widget: stickyHeaders - updated 9/27/2017 (v2.29.0) *//*
2354
- * Requires tablesorter v2.8+ and jQuery 1.4.3+
2355
- * by Rob Garrison
2356
- */
2357
- ;(function ($, window) {
2358
- 'use strict';
2359
- var ts = $.tablesorter || {};
2360
-
2361
- $.extend(ts.css, {
2362
- sticky : 'tablesorter-stickyHeader', // stickyHeader
2363
- stickyVis : 'tablesorter-sticky-visible',
2364
- stickyHide: 'tablesorter-sticky-hidden',
2365
- stickyWrap: 'tablesorter-sticky-wrapper'
2366
- });
2367
-
2368
- // Add a resize event to table headers
2369
- ts.addHeaderResizeEvent = function(table, disable, settings) {
2370
- table = $(table)[0]; // make sure we're using a dom element
2371
- if ( !table.config ) { return; }
2372
- var defaults = {
2373
- timer : 250
2374
- },
2375
- options = $.extend({}, defaults, settings),
2376
- c = table.config,
2377
- wo = c.widgetOptions,
2378
- checkSizes = function( triggerEvent ) {
2379
- var index, headers, $header, sizes, width, height,
2380
- len = c.$headers.length;
2381
- wo.resize_flag = true;
2382
- headers = [];
2383
- for ( index = 0; index < len; index++ ) {
2384
- $header = c.$headers.eq( index );
2385
- sizes = $header.data( 'savedSizes' ) || [ 0, 0 ]; // fixes #394
2386
- width = $header[0].offsetWidth;
2387
- height = $header[0].offsetHeight;
2388
- if ( width !== sizes[0] || height !== sizes[1] ) {
2389
- $header.data( 'savedSizes', [ width, height ] );
2390
- headers.push( $header[0] );
2391
- }
2392
- }
2393
- if ( headers.length && triggerEvent !== false ) {
2394
- c.$table.triggerHandler( 'resize', [ headers ] );
2395
- }
2396
- wo.resize_flag = false;
2397
- };
2398
- clearInterval(wo.resize_timer);
2399
- if (disable) {
2400
- wo.resize_flag = false;
2401
- return false;
2402
- }
2403
- checkSizes( false );
2404
- wo.resize_timer = setInterval(function() {
2405
- if (wo.resize_flag) { return; }
2406
- checkSizes();
2407
- }, options.timer);
2408
- };
2409
-
2410
- function getStickyOffset(c, wo) {
2411
- var $el = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : [];
2412
- return $el.length ?
2413
- $el.height() || 0 :
2414
- parseInt(wo.stickyHeaders_offset, 10) || 0;
2415
- }
2416
-
2417
- // Sticky headers based on this awesome article:
2418
- // http://css-tricks.com/13465-persistent-headers/
2419
- // and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
2420
- // **************************
2421
- ts.addWidget({
2422
- id: 'stickyHeaders',
2423
- priority: 54, // sticky widget must be initialized after the filter & before pager widget!
2424
- options: {
2425
- stickyHeaders : '', // extra class name added to the sticky header row
2426
- stickyHeaders_appendTo : null, // jQuery selector or object to phycially attach the sticky headers
2427
- stickyHeaders_attachTo : null, // jQuery selector or object to attach scroll listener to (overridden by xScroll & yScroll settings)
2428
- stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
2429
- stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
2430
- stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element
2431
- stickyHeaders_filteredToTop: true, // scroll table top into view after filtering
2432
- stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
2433
- stickyHeaders_addResizeEvent : true, // trigger 'resize' event on headers
2434
- stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
2435
- stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
2436
- },
2437
- format: function(table, c, wo) {
2438
- // filter widget doesn't initialize on an empty table. Fixes #449
2439
- if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
2440
- return;
2441
- }
2442
- var index, len, $t,
2443
- $table = c.$table,
2444
- // add position: relative to attach element, hopefully it won't cause trouble.
2445
- $attach = $(wo.stickyHeaders_attachTo || wo.stickyHeaders_appendTo),
2446
- namespace = c.namespace + 'stickyheaders ',
2447
- // element to watch for the scroll event
2448
- $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
2449
- $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
2450
- $thead = $table.children('thead:first'),
2451
- $header = $thead.children('tr').not('.sticky-false').children(),
2452
- $tfoot = $table.children('tfoot'),
2453
- stickyOffset = getStickyOffset(c, wo),
2454
- // is this table nested? If so, find parent sticky header wrapper (div, not table)
2455
- $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
2456
- $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
2457
- nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
2458
- // clone table, then wrap to make sticky header
2459
- $stickyTable = wo.$sticky = $table.clone()
2460
- .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' )
2461
- .wrap('<div class="' + ts.css.stickyWrap + '">'),
2462
- $stickyWrap = $stickyTable.parent()
2463
- .addClass(ts.css.stickyHide)
2464
- .css({
2465
- position : $attach.length ? 'absolute' : 'fixed',
2466
- padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
2467
- top : stickyOffset + nestedStickyTop,
2468
- left : 0,
2469
- visibility : 'hidden',
2470
- zIndex : wo.stickyHeaders_zIndex || 2
2471
- }),
2472
- $stickyThead = $stickyTable.children('thead:first'),
2473
- $stickyCells,
2474
- laststate = '',
2475
- setWidth = function($orig, $clone) {
2476
- var index, width, border, $cell, $this,
2477
- $cells = $orig.filter(':visible'),
2478
- len = $cells.length;
2479
- for ( index = 0; index < len; index++ ) {
2480
- $cell = $clone.filter(':visible').eq(index);
2481
- $this = $cells.eq(index);
2482
- // code from https://github.com/jmosbech/StickyTableHeaders
2483
- if ($this.css('box-sizing') === 'border-box') {
2484
- width = $this.outerWidth();
2485
- } else {
2486
- if ($cell.css('border-collapse') === 'collapse') {
2487
- if (window.getComputedStyle) {
2488
- width = parseFloat( window.getComputedStyle($this[0], null).width );
2489
- } else {
2490
- // ie8 only
2491
- border = parseFloat( $this.css('border-width') );
2492
- width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
2493
- }
2494
- } else {
2495
- width = $this.width();
2496
- }
2497
- }
2498
- $cell.css({
2499
- 'width': width,
2500
- 'min-width': width,
2501
- 'max-width': width
2502
- });
2503
- }
2504
- },
2505
- getLeftPosition = function(yWindow) {
2506
- if (yWindow === false && $nestedSticky.length) {
2507
- return $table.position().left;
2508
- }
2509
- return $attach.length ?
2510
- parseInt($attach.css('padding-left'), 10) || 0 :
2511
- $table.offset().left - parseInt($table.css('margin-left'), 10) - $(window).scrollLeft();
2512
- },
2513
- resizeHeader = function() {
2514
- $stickyWrap.css({
2515
- left : getLeftPosition(),
2516
- width: $table.outerWidth()
2517
- });
2518
- setWidth( $table, $stickyTable );
2519
- setWidth( $header, $stickyCells );
2520
- },
2521
- scrollSticky = function( resizing ) {
2522
- if (!$table.is(':visible')) { return; } // fixes #278
2523
- // Detect nested tables - fixes #724
2524
- nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
2525
- var tmp,
2526
- offset = $table.offset(),
2527
- stickyOffset = getStickyOffset(c, wo),
2528
- yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
2529
- yScroll = yWindow ?
2530
- $yScroll.scrollTop() :
2531
- // use parent sticky position if nested AND inside of a scrollable element - see #1512
2532
- $nestedSticky.length ? parseInt($nestedSticky[0].style.top, 10) : $yScroll.offset().top,
2533
- attachTop = $attach.length ? yScroll : $yScroll.scrollTop(),
2534
- captionHeight = wo.stickyHeaders_includeCaption ? 0 : $table.children( 'caption' ).height() || 0,
2535
- scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
2536
- tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
2537
- isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
2538
- state = isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide,
2539
- needsUpdating = !$stickyWrap.hasClass( state ),
2540
- cssSettings = { visibility : isVisible };
2541
- if ($attach.length) {
2542
- // attached sticky headers always need updating
2543
- needsUpdating = true;
2544
- cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
2545
- }
2546
- // adjust when scrolling horizontally - fixes issue #143
2547
- tmp = getLeftPosition(yWindow);
2548
- if (tmp !== parseInt($stickyWrap.css('left'), 10)) {
2549
- needsUpdating = true;
2550
- cssSettings.left = tmp;
2551
- }
2552
- cssSettings.top = ( cssSettings.top || 0 ) +
2553
- // If nested AND inside of a scrollable element, only add parent sticky height
2554
- (!yWindow && $nestedSticky.length ? $nestedSticky.height() : stickyOffset + nestedStickyTop);
2555
- if (needsUpdating) {
2556
- $stickyWrap
2557
- .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
2558
- .addClass( state )
2559
- .css(cssSettings);
2560
- }
2561
- if (isVisible !== laststate || resizing) {
2562
- // make sure the column widths match
2563
- resizeHeader();
2564
- laststate = isVisible;
2565
- }
2566
- };
2567
- // only add a position relative if a position isn't already defined
2568
- if ($attach.length && !$attach.css('position')) {
2569
- $attach.css('position', 'relative');
2570
- }
2571
- // fix clone ID, if it exists - fixes #271
2572
- if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; }
2573
- // clear out cloned table, except for sticky header
2574
- // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
2575
- $stickyTable.find('> thead:gt(0), tr.sticky-false').hide();
2576
- $stickyTable.find('> tbody, > tfoot').remove();
2577
- $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
2578
- // issue #172 - find td/th in sticky header
2579
- $stickyCells = $stickyThead.children().children();
2580
- $stickyTable.css({ height:0, width:0, margin: 0 });
2581
- // remove resizable block
2582
- $stickyCells.find('.' + ts.css.resizer).remove();
2583
- // update sticky header class names to match real header after sorting
2584
- $table
2585
- .addClass('hasStickyHeaders')
2586
- .bind('pagerComplete' + namespace, function() {
2587
- resizeHeader();
2588
- });
2589
-
2590
- ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header));
2591
-
2592
- if (wo.stickyHeaders_appendTo) {
2593
- $(wo.stickyHeaders_appendTo).append( $stickyWrap );
2594
- } else {
2595
- // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
2596
- $table.after( $stickyWrap );
2597
- }
2598
-
2599
- // onRenderHeader is defined, we need to do something about it (fixes #641)
2600
- if (c.onRenderHeader) {
2601
- $t = $stickyThead.children('tr').children();
2602
- len = $t.length;
2603
- for ( index = 0; index < len; index++ ) {
2604
- // send second parameter
2605
- c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
2606
- }
2607
- }
2608
- // make it sticky!
2609
- $xScroll.add($yScroll)
2610
- .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
2611
- .bind('scroll resize '.split(' ').join( namespace ), function( event ) {
2612
- scrollSticky( event.type === 'resize' );
2613
- });
2614
- c.$table
2615
- .unbind('stickyHeadersUpdate' + namespace)
2616
- .bind('stickyHeadersUpdate' + namespace, function() {
2617
- scrollSticky( true );
2618
- });
2619
-
2620
- if (wo.stickyHeaders_addResizeEvent) {
2621
- ts.addHeaderResizeEvent(table);
2622
- }
2623
-
2624
- // look for filter widget
2625
- if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
2626
- // scroll table into view after filtering, if sticky header is active - #482
2627
- $table.bind('filterEnd' + namespace, function() {
2628
- // $(':focus') needs jQuery 1.6+
2629
- var $td = $(document.activeElement).closest('td'),
2630
- column = $td.parent().children().index($td);
2631
- // only scroll if sticky header is active
2632
- if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
2633
- // scroll to original table (not sticky clone)
2634
- window.scrollTo(0, $table.position().top);
2635
- // give same input/select focus; check if c.$filters exists; fixes #594
2636
- if (column >= 0 && c.$filters) {
2637
- c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
2638
- }
2639
- }
2640
- });
2641
- ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
2642
- // support hideFilters
2643
- if (wo.filter_hideFilters) {
2644
- ts.filter.hideFilters(c, $stickyTable);
2645
- }
2646
- }
2647
-
2648
- // resize table (Firefox)
2649
- if (wo.stickyHeaders_addResizeEvent) {
2650
- $table.bind('resize' + c.namespace + 'stickyheaders', function() {
2651
- resizeHeader();
2652
- });
2653
- }
2654
-
2655
- // make sure sticky is visible if page is partially scrolled
2656
- scrollSticky( true );
2657
- $table.triggerHandler('stickyHeadersInit');
2658
-
2659
- },
2660
- remove: function(table, c, wo) {
2661
- var namespace = c.namespace + 'stickyheaders ';
2662
- c.$table
2663
- .removeClass('hasStickyHeaders')
2664
- .unbind( ('pagerComplete resize filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
2665
- .next('.' + ts.css.stickyWrap).remove();
2666
- if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
2667
- $(window)
2668
- .add(wo.stickyHeaders_xScroll)
2669
- .add(wo.stickyHeaders_yScroll)
2670
- .add(wo.stickyHeaders_attachTo)
2671
- .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
2672
- ts.addHeaderResizeEvent(table, true);
2673
- }
2674
- });
2675
-
2676
- })(jQuery, window);
2677
-
2678
- /*! Widget: resizable - updated 2018-03-26 (v2.30.2) */
2679
- /*jshint browser:true, jquery:true, unused:false */
2680
- ;(function ($, window) {
2681
- 'use strict';
2682
- var ts = $.tablesorter || {};
2683
-
2684
- $.extend(ts.css, {
2685
- resizableContainer : 'tablesorter-resizable-container',
2686
- resizableHandle : 'tablesorter-resizable-handle',
2687
- resizableNoSelect : 'tablesorter-disableSelection',
2688
- resizableStorage : 'tablesorter-resizable'
2689
- });
2690
-
2691
- // Add extra scroller css
2692
- $(function() {
2693
- var s = '<style>' +
2694
- 'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
2695
- '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
2696
- '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
2697
- // make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
2698
- '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px;' +
2699
- 'top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
2700
- '</style>';
2701
- $('head').append(s);
2702
- });
2703
-
2704
- ts.resizable = {
2705
- init : function( c, wo ) {
2706
- if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
2707
- c.$table.addClass( 'hasResizable' );
2708
-
2709
- var noResize, $header, column, storedSizes, tmp,
2710
- $table = c.$table,
2711
- $parent = $table.parent(),
2712
- marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
2713
-
2714
- // internal variables
2715
- vars = wo.resizable_vars = {
2716
- useStorage : ts.storage && wo.resizable !== false,
2717
- $wrap : $parent,
2718
- mouseXPosition : 0,
2719
- $target : null,
2720
- $next : null,
2721
- overflow : $parent.css('overflow') === 'auto' ||
2722
- $parent.css('overflow') === 'scroll' ||
2723
- $parent.css('overflow-x') === 'auto' ||
2724
- $parent.css('overflow-x') === 'scroll',
2725
- storedSizes : []
2726
- };
2727
-
2728
- // set default widths
2729
- ts.resizableReset( c.table, true );
2730
-
2731
- // now get measurements!
2732
- vars.tableWidth = $table.width();
2733
- // attempt to autodetect
2734
- vars.fullWidth = Math.abs( $parent.width() - vars.tableWidth ) < 20;
2735
-
2736
- /*
2737
- // Hacky method to determine if table width is set to 'auto'
2738
- // http://stackoverflow.com/a/20892048/145346
2739
- if ( !vars.fullWidth ) {
2740
- tmp = $table.width();
2741
- $header = $table.wrap('<span>').parent(); // temp variable
2742
- storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
2743
- $table.css( 'margin-left', storedSizes + 50 );
2744
- vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
2745
- $table.css( 'margin-left', storedSizes ? storedSizes : '' );
2746
- $header = null;
2747
- $table.unwrap('<span>');
2748
- }
2749
- */
2750
-
2751
- if ( vars.useStorage && vars.overflow ) {
2752
- // save table width
2753
- ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
2754
- tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
2755
- ts.resizable.setWidth( $table, tmp, true );
2756
- }
2757
- wo.resizable_vars.storedSizes = storedSizes = ( vars.useStorage ?
2758
- ts.storage( c.table, ts.css.resizableStorage ) :
2759
- [] ) || [];
2760
- ts.resizable.setWidths( c, wo, storedSizes );
2761
- ts.resizable.updateStoredSizes( c, wo );
2762
-
2763
- wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
2764
- .css({ top : marginTop })
2765
- .insertBefore( $table );
2766
- // add container
2767
- for ( column = 0; column < c.columns; column++ ) {
2768
- $header = c.$headerIndexed[ column ];
2769
- tmp = ts.getColumnData( c.table, c.headers, column );
2770
- noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
2771
- if ( !noResize ) {
2772
- $( '<div class="' + ts.css.resizableHandle + '">' )
2773
- .appendTo( wo.$resizable_container )
2774
- .attr({
2775
- 'data-column' : column,
2776
- 'unselectable' : 'on'
2777
- })
2778
- .data( 'header', $header )
2779
- .bind( 'selectstart', false );
2780
- }
2781
- }
2782
- ts.resizable.bindings( c, wo );
2783
- },
2784
-
2785
- updateStoredSizes : function( c, wo ) {
2786
- var column, $header,
2787
- len = c.columns,
2788
- vars = wo.resizable_vars;
2789
- vars.storedSizes = [];
2790
- for ( column = 0; column < len; column++ ) {
2791
- $header = c.$headerIndexed[ column ];
2792
- vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
2793
- }
2794
- },
2795
-
2796
- setWidth : function( $el, width, overflow ) {
2797
- // overflow tables need min & max width set as well
2798
- $el.css({
2799
- 'width' : width,
2800
- 'min-width' : overflow ? width : '',
2801
- 'max-width' : overflow ? width : ''
2802
- });
2803
- },
2804
-
2805
- setWidths : function( c, wo, storedSizes ) {
2806
- var column, $temp,
2807
- vars = wo.resizable_vars,
2808
- $extra = $( c.namespace + '_extra_headers' ),
2809
- $col = c.$table.children( 'colgroup' ).children( 'col' );
2810
- storedSizes = storedSizes || vars.storedSizes || [];
2811
- // process only if table ID or url match
2812
- if ( storedSizes.length ) {
2813
- for ( column = 0; column < c.columns; column++ ) {
2814
- // set saved resizable widths
2815
- ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
2816
- if ( $extra.length ) {
2817
- // stickyHeaders needs to modify min & max width as well
2818
- $temp = $extra.eq( column ).add( $col.eq( column ) );
2819
- ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
2820
- }
2821
- }
2822
- $temp = $( c.namespace + '_extra_table' );
2823
- if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
2824
- ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
2825
- }
2826
- }
2827
- },
2828
-
2829
- setHandlePosition : function( c, wo ) {
2830
- var startPosition,
2831
- tableHeight = c.$table.height(),
2832
- $handles = wo.$resizable_container.children(),
2833
- handleCenter = Math.floor( $handles.width() / 2 );
2834
-
2835
- if ( ts.hasWidget( c.table, 'scroller' ) ) {
2836
- tableHeight = 0;
2837
- c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function() {
2838
- var $this = $(this);
2839
- // center table has a max-height set
2840
- tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
2841
- });
2842
- }
2843
-
2844
- if ( !wo.resizable_includeFooter && c.$table.children('tfoot').length ) {
2845
- tableHeight -= c.$table.children('tfoot').height();
2846
- }
2847
- // subtract out table left position from resizable handles. Fixes #864
2848
- // jQuery v3.3.0+ appears to include the start position with the $header.position().left; see #1544
2849
- startPosition = parseFloat($.fn.jquery) >= 3.3 ? 0 : c.$table.position().left;
2850
- $handles.each( function() {
2851
- var $this = $(this),
2852
- column = parseInt( $this.attr( 'data-column' ), 10 ),
2853
- columns = c.columns - 1,
2854
- $header = $this.data( 'header' );
2855
- if ( !$header ) { return; } // see #859
2856
- if (
2857
- !$header.is(':visible') ||
2858
- ( !wo.resizable_addLastColumn && ts.resizable.checkVisibleColumns(c, column) )
2859
- ) {
2860
- $this.hide();
2861
- } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
2862
- $this.css({
2863
- display: 'inline-block',
2864
- height : tableHeight,
2865
- left : $header.position().left - startPosition + $header.outerWidth() - handleCenter
2866
- });
2867
- }
2868
- });
2869
- },
2870
-
2871
- // Fixes #1485
2872
- checkVisibleColumns: function( c, column ) {
2873
- var i,
2874
- len = 0;
2875
- for ( i = column + 1; i < c.columns; i++ ) {
2876
- len += c.$headerIndexed[i].is( ':visible' ) ? 1 : 0;
2877
- }
2878
- return len === 0;
2879
- },
2880
-
2881
- // prevent text selection while dragging resize bar
2882
- toggleTextSelection : function( c, wo, toggle ) {
2883
- var namespace = c.namespace + 'tsresize';
2884
- wo.resizable_vars.disabled = toggle;
2885
- $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
2886
- if ( toggle ) {
2887
- $( 'body' )
2888
- .attr( 'unselectable', 'on' )
2889
- .bind( 'selectstart' + namespace, false );
2890
- } else {
2891
- $( 'body' )
2892
- .removeAttr( 'unselectable' )
2893
- .unbind( 'selectstart' + namespace );
2894
- }
2895
- },
2896
-
2897
- bindings : function( c, wo ) {
2898
- var namespace = c.namespace + 'tsresize';
2899
- wo.$resizable_container.children().bind( 'mousedown', function( event ) {
2900
- // save header cell and mouse position
2901
- var column,
2902
- vars = wo.resizable_vars,
2903
- $extras = $( c.namespace + '_extra_headers' ),
2904
- $header = $( event.target ).data( 'header' );
2905
-
2906
- column = parseInt( $header.attr( 'data-column' ), 10 );
2907
- vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
2908
- vars.target = column;
2909
-
2910
- // if table is not as wide as it's parent, then resize the table
2911
- vars.$next = event.shiftKey || wo.resizable_targetLast ?
2912
- $header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
2913
- $header.nextAll( ':not(.resizable-false)' ).eq( 0 );
2914
-
2915
- column = parseInt( vars.$next.attr( 'data-column' ), 10 );
2916
- vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
2917
- vars.next = column;
2918
-
2919
- vars.mouseXPosition = event.pageX;
2920
- ts.resizable.updateStoredSizes( c, wo );
2921
- ts.resizable.toggleTextSelection(c, wo, true );
2922
- });
2923
-
2924
- $( document )
2925
- .bind( 'mousemove' + namespace, function( event ) {
2926
- var vars = wo.resizable_vars;
2927
- // ignore mousemove if no mousedown
2928
- if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
2929
- if ( wo.resizable_throttle ) {
2930
- clearTimeout( vars.timer );
2931
- vars.timer = setTimeout( function() {
2932
- ts.resizable.mouseMove( c, wo, event );
2933
- }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
2934
- } else {
2935
- ts.resizable.mouseMove( c, wo, event );
2936
- }
2937
- })
2938
- .bind( 'mouseup' + namespace, function() {
2939
- if (!wo.resizable_vars.disabled) { return; }
2940
- ts.resizable.toggleTextSelection( c, wo, false );
2941
- ts.resizable.stopResize( c, wo );
2942
- ts.resizable.setHandlePosition( c, wo );
2943
- });
2944
-
2945
- // resizeEnd event triggered by scroller widget
2946
- $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
2947
- ts.resizable.setHandlePosition( c, wo );
2948
- });
2949
-
2950
- // right click to reset columns to default widths
2951
- c.$table
2952
- .bind( 'columnUpdate pagerComplete resizableUpdate '.split( ' ' ).join( namespace + ' ' ), function() {
2953
- ts.resizable.setHandlePosition( c, wo );
2954
- })
2955
- .bind( 'resizableReset' + namespace, function() {
2956
- ts.resizableReset( c.table );
2957
- })
2958
- .find( 'thead:first' )
2959
- .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
2960
- .bind( 'contextmenu' + namespace, function() {
2961
- // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
2962
- var allowClick = wo.resizable_vars.storedSizes.length === 0;
2963
- ts.resizableReset( c.table );
2964
- ts.resizable.setHandlePosition( c, wo );
2965
- wo.resizable_vars.storedSizes = [];
2966
- return allowClick;
2967
- });
2968
-
2969
- },
2970
-
2971
- mouseMove : function( c, wo, event ) {
2972
- if ( wo.resizable_vars.mouseXPosition === 0 || !wo.resizable_vars.$target ) { return; }
2973
- // resize columns
2974
- var column,
2975
- total = 0,
2976
- vars = wo.resizable_vars,
2977
- $next = vars.$next,
2978
- tar = vars.storedSizes[ vars.target ],
2979
- leftEdge = event.pageX - vars.mouseXPosition;
2980
- if ( vars.overflow ) {
2981
- if ( tar + leftEdge > 0 ) {
2982
- vars.storedSizes[ vars.target ] += leftEdge;
2983
- ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
2984
- // update the entire table width
2985
- for ( column = 0; column < c.columns; column++ ) {
2986
- total += vars.storedSizes[ column ];
2987
- }
2988
- ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
2989
- }
2990
- if ( !$next.length ) {
2991
- // if expanding right-most column, scroll the wrapper
2992
- vars.$wrap[0].scrollLeft = c.$table.width();
2993
- }
2994
- } else if ( vars.fullWidth ) {
2995
- vars.storedSizes[ vars.target ] += leftEdge;
2996
- vars.storedSizes[ vars.next ] -= leftEdge;
2997
- ts.resizable.setWidths( c, wo );
2998
- } else {
2999
- vars.storedSizes[ vars.target ] += leftEdge;
3000
- ts.resizable.setWidths( c, wo );
3001
- }
3002
- vars.mouseXPosition = event.pageX;
3003
- // dynamically update sticky header widths
3004
- c.$table.triggerHandler('stickyHeadersUpdate');
3005
- },
3006
-
3007
- stopResize : function( c, wo ) {
3008
- var vars = wo.resizable_vars;
3009
- ts.resizable.updateStoredSizes( c, wo );
3010
- if ( vars.useStorage ) {
3011
- // save all column widths
3012
- ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
3013
- ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
3014
- }
3015
- vars.mouseXPosition = 0;
3016
- vars.$target = vars.$next = null;
3017
- // will update stickyHeaders, just in case, see #912
3018
- c.$table.triggerHandler('stickyHeadersUpdate');
3019
- c.$table.triggerHandler('resizableComplete');
3020
- }
3021
- };
3022
-
3023
- // this widget saves the column widths if
3024
- // $.tablesorter.storage function is included
3025
- // **************************
3026
- ts.addWidget({
3027
- id: 'resizable',
3028
- priority: 40,
3029
- options: {
3030
- resizable : true, // save column widths to storage
3031
- resizable_addLastColumn : false,
3032
- resizable_includeFooter: true,
3033
- resizable_widths : [],
3034
- resizable_throttle : false, // set to true (5ms) or any number 0-10 range
3035
- resizable_targetLast : false
3036
- },
3037
- init: function(table, thisWidget, c, wo) {
3038
- ts.resizable.init( c, wo );
3039
- },
3040
- format: function( table, c, wo ) {
3041
- ts.resizable.setHandlePosition( c, wo );
3042
- },
3043
- remove: function( table, c, wo, refreshing ) {
3044
- if (wo.$resizable_container) {
3045
- var namespace = c.namespace + 'tsresize';
3046
- c.$table.add( $( c.namespace + '_extra_table' ) )
3047
- .removeClass('hasResizable')
3048
- .children( 'thead' )
3049
- .unbind( 'contextmenu' + namespace );
3050
-
3051
- wo.$resizable_container.remove();
3052
- ts.resizable.toggleTextSelection( c, wo, false );
3053
- ts.resizableReset( table, refreshing );
3054
- $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
3055
- }
3056
- }
3057
- });
3058
-
3059
- ts.resizableReset = function( table, refreshing ) {
3060
- $( table ).each(function() {
3061
- var index, $t,
3062
- c = this.config,
3063
- wo = c && c.widgetOptions,
3064
- vars = wo.resizable_vars;
3065
- if ( table && c && c.$headerIndexed.length ) {
3066
- // restore the initial table width
3067
- if ( vars.overflow && vars.tableWidth ) {
3068
- ts.resizable.setWidth( c.$table, vars.tableWidth, true );
3069
- if ( vars.useStorage ) {
3070
- ts.storage( table, 'tablesorter-table-resized-width', vars.tableWidth );
3071
- }
3072
- }
3073
- for ( index = 0; index < c.columns; index++ ) {
3074
- $t = c.$headerIndexed[ index ];
3075
- if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
3076
- ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
3077
- } else if ( !$t.hasClass( 'resizable-false' ) ) {
3078
- // don't clear the width of any column that is not resizable
3079
- ts.resizable.setWidth( $t, '', vars.overflow );
3080
- }
3081
- }
3082
-
3083
- // reset stickyHeader widths
3084
- c.$table.triggerHandler( 'stickyHeadersUpdate' );
3085
- if ( ts.storage && !refreshing ) {
3086
- ts.storage( this, ts.css.resizableStorage, [] );
3087
- }
3088
- }
3089
- });
3090
- };
3091
-
3092
- })( jQuery, window );
3093
-
3094
- /*! Widget: saveSort - updated 2018-03-19 (v2.30.1) *//*
3095
- * Requires tablesorter v2.16+
3096
- * by Rob Garrison
3097
- */
3098
- ;(function ($) {
3099
- 'use strict';
3100
- var ts = $.tablesorter || {};
3101
-
3102
- function getStoredSortList(c) {
3103
- var stored = ts.storage( c.table, 'tablesorter-savesort' );
3104
- return (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : [];
3105
- }
3106
-
3107
- function sortListChanged(c, sortList) {
3108
- return (sortList || getStoredSortList(c)).join(',') !== c.sortList.join(',');
3109
- }
3110
-
3111
- // this widget saves the last sort only if the
3112
- // saveSort widget option is true AND the
3113
- // $.tablesorter.storage function is included
3114
- // **************************
3115
- ts.addWidget({
3116
- id: 'saveSort',
3117
- priority: 20,
3118
- options: {
3119
- saveSort : true
3120
- },
3121
- init: function(table, thisWidget, c, wo) {
3122
- // run widget format before all other widgets are applied to the table
3123
- thisWidget.format(table, c, wo, true);
3124
- },
3125
- format: function(table, c, wo, init) {
3126
- var time,
3127
- $table = c.$table,
3128
- saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
3129
- sortList = { 'sortList' : c.sortList },
3130
- debug = ts.debug(c, 'saveSort');
3131
- if (debug) {
3132
- time = new Date();
3133
- }
3134
- if ($table.hasClass('hasSaveSort')) {
3135
- if (saveSort && table.hasInitialized && ts.storage && sortListChanged(c)) {
3136
- ts.storage( table, 'tablesorter-savesort', sortList );
3137
- if (debug) {
3138
- console.log('saveSort >> Saving last sort: ' + c.sortList + ts.benchmark(time));
3139
- }
3140
- }
3141
- } else {
3142
- // set table sort on initial run of the widget
3143
- $table.addClass('hasSaveSort');
3144
- sortList = '';
3145
- // get data
3146
- if (ts.storage) {
3147
- sortList = getStoredSortList(c);
3148
- if (debug) {
3149
- console.log('saveSort >> Last sort loaded: "' + sortList + '"' + ts.benchmark(time));
3150
- }
3151
- $table.bind('saveSortReset', function(event) {
3152
- event.stopPropagation();
3153
- ts.storage( table, 'tablesorter-savesort', '' );
3154
- });
3155
- }
3156
- // init is true when widget init is run, this will run this widget before all other widgets have initialized
3157
- // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
3158
- if (init && sortList && sortList.length > 0) {
3159
- c.sortList = sortList;
3160
- } else if (table.hasInitialized && sortList && sortList.length > 0) {
3161
- // update sort change
3162
- if (sortListChanged(c, sortList)) {
3163
- ts.sortOn(c, sortList);
3164
- }
3165
- }
3166
- }
3167
- },
3168
- remove: function(table, c) {
3169
- c.$table.removeClass('hasSaveSort');
3170
- // clear storage
3171
- if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
3172
- }
3173
- });
3174
-
3175
- })(jQuery);
3176
- return jQuery.tablesorter;}));
1
+ /*! tablesorter (FORK) - updated 2018-11-20 (v2.31.1)*/
2
+ /* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
3
+ (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery) {
4
+ /*! Widget: storage - updated 2018-03-18 (v2.30.0) */
5
+ /*global JSON:false */
6
+ ;(function ($, window, document) {
7
+ 'use strict';
8
+
9
+ var ts = $.tablesorter || {};
10
+
11
+ // update defaults for validator; these values must be falsy!
12
+ $.extend(true, ts.defaults, {
13
+ fixedUrl: '',
14
+ widgetOptions: {
15
+ storage_fixedUrl: '',
16
+ storage_group: '',
17
+ storage_page: '',
18
+ storage_storageType: '',
19
+ storage_tableId: '',
20
+ storage_useSessionStorage: ''
21
+ }
22
+ });
23
+
24
+ // *** Store data in local storage, with a cookie fallback ***
25
+ /* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
26
+ if you need it, then include https://github.com/douglascrockford/JSON-js
27
+
28
+ $.parseJSON is not available is jQuery versions older than 1.4.1, using older
29
+ versions will only allow storing information for one page at a time
30
+
31
+ // *** Save data (JSON format only) ***
32
+ // val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
33
+ var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
34
+ // $.tablesorter.storage(table, key, val);
35
+ $.tablesorter.storage(table, 'tablesorter-mywidget', val);
36
+
37
+ // *** Get data: $.tablesorter.storage(table, key); ***
38
+ v = $.tablesorter.storage(table, 'tablesorter-mywidget');
39
+ // val may be empty, so also check for your data
40
+ val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
41
+ alert(val); // 'data1' if saved, or '' if not
42
+ */
43
+ ts.storage = function(table, key, value, options) {
44
+ table = $(table)[0];
45
+ var cookieIndex, cookies, date,
46
+ hasStorage = false,
47
+ values = {},
48
+ c = table.config,
49
+ wo = c && c.widgetOptions,
50
+ debug = ts.debug(c, 'storage'),
51
+ storageType = (
52
+ ( options && options.storageType ) || ( wo && wo.storage_storageType )
53
+ ).toString().charAt(0).toLowerCase(),
54
+ // deprecating "useSessionStorage"; any storageType setting overrides it
55
+ session = storageType ? '' :
56
+ ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ),
57
+ $table = $(table),
58
+ // id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
59
+ // (4) table ID, then (5) table index
60
+ id = options && options.id ||
61
+ $table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') ||
62
+ wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ),
63
+ // url from (1) options url, (2) table 'data-table-page' attribute, (3) widgetOptions.storage_fixedUrl,
64
+ // (4) table.config.fixedUrl (deprecated), then (5) window location path
65
+ url = options && options.url ||
66
+ $table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') ||
67
+ wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname;
68
+
69
+ // skip if using cookies
70
+ if (storageType !== 'c') {
71
+ storageType = (storageType === 's' || session) ? 'sessionStorage' : 'localStorage';
72
+ // https://gist.github.com/paulirish/5558557
73
+ if (storageType in window) {
74
+ try {
75
+ window[storageType].setItem('_tmptest', 'temp');
76
+ hasStorage = true;
77
+ window[storageType].removeItem('_tmptest');
78
+ } catch (error) {
79
+ console.warn( storageType + ' is not supported in this browser' );
80
+ }
81
+ }
82
+ }
83
+ if (debug) {
84
+ console.log('Storage >> Using', hasStorage ? storageType : 'cookies');
85
+ }
86
+ // *** get value ***
87
+ if ($.parseJSON) {
88
+ if (hasStorage) {
89
+ values = $.parseJSON( window[storageType][key] || 'null' ) || {};
90
+ } else {
91
+ // old browser, using cookies
92
+ cookies = document.cookie.split(/[;\s|=]/);
93
+ // add one to get from the key to the value
94
+ cookieIndex = $.inArray(key, cookies) + 1;
95
+ values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
96
+ }
97
+ }
98
+ // allow value to be an empty string too
99
+ if (typeof value !== 'undefined' && window.JSON && JSON.hasOwnProperty('stringify')) {
100
+ // add unique identifiers = url pathname > table ID/index on page > data
101
+ if (!values[url]) {
102
+ values[url] = {};
103
+ }
104
+ values[url][id] = value;
105
+ // *** set value ***
106
+ if (hasStorage) {
107
+ window[storageType][key] = JSON.stringify(values);
108
+ } else {
109
+ date = new Date();
110
+ date.setTime(date.getTime() + (31536e+6)); // 365 days
111
+ document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g, '\"') + '; expires=' + date.toGMTString() + '; path=/';
112
+ }
113
+ } else {
114
+ return values && values[url] ? values[url][id] : '';
115
+ }
116
+ };
117
+
118
+ })(jQuery, window, document);
119
+
120
+ /*! Widget: uitheme - updated 2018-03-18 (v2.30.0) */
121
+ ;(function ($) {
122
+ 'use strict';
123
+ var ts = $.tablesorter || {};
124
+
125
+ ts.themes = {
126
+ 'bootstrap' : {
127
+ table : 'table table-bordered table-striped',
128
+ caption : 'caption',
129
+ // header class names
130
+ header : 'bootstrap-header', // give the header a gradient background (theme.bootstrap_2.css)
131
+ sortNone : '',
132
+ sortAsc : '',
133
+ sortDesc : '',
134
+ active : '', // applied when column is sorted
135
+ hover : '', // custom css required - a defined bootstrap style may not override other classes
136
+ // icon class names
137
+ icons : '', // add 'bootstrap-icon-white' to make them white; this icon class is added to the <i> in the header
138
+ iconSortNone : 'bootstrap-icon-unsorted', // class name added to icon when column is not sorted
139
+ iconSortAsc : 'glyphicon glyphicon-chevron-up', // class name added to icon when column has ascending sort
140
+ iconSortDesc : 'glyphicon glyphicon-chevron-down', // class name added to icon when column has descending sort
141
+ filterRow : '', // filter row class
142
+ footerRow : '',
143
+ footerCells : '',
144
+ even : '', // even row zebra striping
145
+ odd : '' // odd row zebra striping
146
+ },
147
+ 'jui' : {
148
+ table : 'ui-widget ui-widget-content ui-corner-all', // table classes
149
+ caption : 'ui-widget-content',
150
+ // header class names
151
+ header : 'ui-widget-header ui-corner-all ui-state-default', // header classes
152
+ sortNone : '',
153
+ sortAsc : '',
154
+ sortDesc : '',
155
+ active : 'ui-state-active', // applied when column is sorted
156
+ hover : 'ui-state-hover', // hover class
157
+ // icon class names
158
+ icons : 'ui-icon', // icon class added to the <i> in the header
159
+ iconSortNone : 'ui-icon-carat-2-n-s ui-icon-caret-2-n-s', // class name added to icon when column is not sorted
160
+ iconSortAsc : 'ui-icon-carat-1-n ui-icon-caret-1-n', // class name added to icon when column has ascending sort
161
+ iconSortDesc : 'ui-icon-carat-1-s ui-icon-caret-1-s', // class name added to icon when column has descending sort
162
+ filterRow : '',
163
+ footerRow : '',
164
+ footerCells : '',
165
+ even : 'ui-widget-content', // even row zebra striping
166
+ odd : 'ui-state-default' // odd row zebra striping
167
+ }
168
+ };
169
+
170
+ $.extend(ts.css, {
171
+ wrapper : 'tablesorter-wrapper' // ui theme & resizable
172
+ });
173
+
174
+ ts.addWidget({
175
+ id: 'uitheme',
176
+ priority: 10,
177
+ format: function(table, c, wo) {
178
+ var i, tmp, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
179
+ themesAll = ts.themes,
180
+ $table = c.$table.add( $( c.namespace + '_extra_table' ) ),
181
+ $headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ),
182
+ theme = c.theme || 'jui',
183
+ themes = themesAll[theme] || {},
184
+ remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
185
+ iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) ),
186
+ debug = ts.debug(c, 'uitheme');
187
+ if (debug) { time = new Date(); }
188
+ // initialization code - run once
189
+ if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
190
+ wo.uitheme_applied = true;
191
+ oldtheme = themesAll[c.appliedTheme] || {};
192
+ hasOldTheme = !$.isEmptyObject(oldtheme);
193
+ oldremove = hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
194
+ oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
195
+ if (hasOldTheme) {
196
+ wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
197
+ wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
198
+ c.$tbodies.children().removeClass( [ oldtheme.even, oldtheme.odd ].join(' ') );
199
+ }
200
+ // update zebra stripes
201
+ if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
202
+ if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
203
+ // add caption style
204
+ $table.children('caption')
205
+ .removeClass(oldtheme.caption || '')
206
+ .addClass(themes.caption);
207
+ // add table/footer class names
208
+ $tfoot = $table
209
+ // remove other selected themes
210
+ .removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
211
+ .addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
212
+ .children('tfoot');
213
+ c.appliedTheme = c.theme;
214
+
215
+ if ($tfoot.length) {
216
+ $tfoot
217
+ // if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
218
+ .children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
219
+ .children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
220
+ }
221
+ // update header classes
222
+ $headers
223
+ .removeClass( (hasOldTheme ? [ oldtheme.header, oldtheme.hover, oldremove ].join(' ') : '') || '' )
224
+ .addClass(themes.header)
225
+ .not('.sorter-false')
226
+ .unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
227
+ .bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
228
+ // toggleClass with switch added in jQuery 1.3
229
+ $(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
230
+ });
231
+
232
+ $headers.each(function() {
233
+ var $this = $(this);
234
+ if (!$this.find('.' + ts.css.wrapper).length) {
235
+ // Firefox needs this inner div to position the icon & resizer correctly
236
+ $this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
237
+ }
238
+ });
239
+ if (c.cssIcon) {
240
+ // if c.cssIcon is '', then no <i> is added to the header
241
+ $headers
242
+ .find('.' + ts.css.icon)
243
+ .removeClass(hasOldTheme ? [ oldtheme.icons, oldIconRmv ].join(' ') : '')
244
+ .addClass(themes.icons || '');
245
+ }
246
+ // filter widget initializes after uitheme
247
+ if (ts.hasWidget( c.table, 'filter' )) {
248
+ tmp = function() {
249
+ $table.children('thead').children('.' + ts.css.filterRow)
250
+ .removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
251
+ .addClass(themes.filterRow || '');
252
+ };
253
+ if (wo.filter_initialized) {
254
+ tmp();
255
+ } else {
256
+ $table.one('filterInit', function() {
257
+ tmp();
258
+ });
259
+ }
260
+ }
261
+ }
262
+ for (i = 0; i < c.columns; i++) {
263
+ $header = c.$headers
264
+ .add($(c.namespace + '_extra_headers'))
265
+ .not('.sorter-false')
266
+ .filter('[data-column="' + i + '"]');
267
+ $icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
268
+ $h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
269
+ if ($h.length) {
270
+ $header.removeClass(remove);
271
+ $icon.removeClass(iconRmv);
272
+ if ($h[0].sortDisabled) {
273
+ // no sort arrows for disabled columns!
274
+ $icon.removeClass(themes.icons || '');
275
+ } else {
276
+ hdr = themes.sortNone;
277
+ icon = themes.iconSortNone;
278
+ if ($h.hasClass(ts.css.sortAsc)) {
279
+ hdr = [ themes.sortAsc, themes.active ].join(' ');
280
+ icon = themes.iconSortAsc;
281
+ } else if ($h.hasClass(ts.css.sortDesc)) {
282
+ hdr = [ themes.sortDesc, themes.active ].join(' ');
283
+ icon = themes.iconSortDesc;
284
+ }
285
+ $header.addClass(hdr);
286
+ $icon.addClass(icon || '');
287
+ }
288
+ }
289
+ }
290
+ if (debug) {
291
+ console.log('uitheme >> Applied ' + theme + ' theme' + ts.benchmark(time));
292
+ }
293
+ },
294
+ remove: function(table, c, wo, refreshing) {
295
+ if (!wo.uitheme_applied) { return; }
296
+ var $table = c.$table,
297
+ theme = c.appliedTheme || 'jui',
298
+ themes = ts.themes[ theme ] || ts.themes.jui,
299
+ $headers = $table.children('thead').children(),
300
+ remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
301
+ iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
302
+ $table.removeClass('tablesorter-' + theme + ' ' + themes.table);
303
+ wo.uitheme_applied = false;
304
+ if (refreshing) { return; }
305
+ $table.find(ts.css.header).removeClass(themes.header);
306
+ $headers
307
+ .unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
308
+ .removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
309
+ .filter('.' + ts.css.filterRow)
310
+ .removeClass(themes.filterRow);
311
+ $headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
312
+ }
313
+ });
314
+
315
+ })(jQuery);
316
+
317
+ /*! Widget: columns - updated 5/24/2017 (v2.28.11) */
318
+ ;(function ($) {
319
+ 'use strict';
320
+ var ts = $.tablesorter || {};
321
+
322
+ ts.addWidget({
323
+ id: 'columns',
324
+ priority: 65,
325
+ options : {
326
+ columns : [ 'primary', 'secondary', 'tertiary' ]
327
+ },
328
+ format: function(table, c, wo) {
329
+ var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
330
+ $table = c.$table,
331
+ $tbodies = c.$tbodies,
332
+ sortList = c.sortList,
333
+ len = sortList.length,
334
+ // removed c.widgetColumns support
335
+ css = wo && wo.columns || [ 'primary', 'secondary', 'tertiary' ],
336
+ last = css.length - 1;
337
+ remove = css.join(' ');
338
+ // check if there is a sort (on initialization there may not be one)
339
+ for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
340
+ $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
341
+ $rows = $tbody.children('tr');
342
+ // loop through the visible rows
343
+ $rows.each(function() {
344
+ $row = $(this);
345
+ if (this.style.display !== 'none') {
346
+ // remove all columns class names
347
+ $cells = $row.children().removeClass(remove);
348
+ // add appropriate column class names
349
+ if (sortList && sortList[0]) {
350
+ // primary sort column class
351
+ $cells.eq(sortList[0][0]).addClass(css[0]);
352
+ if (len > 1) {
353
+ for (indx = 1; indx < len; indx++) {
354
+ // secondary, tertiary, etc sort column classes
355
+ $cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
356
+ }
357
+ }
358
+ }
359
+ }
360
+ });
361
+ ts.processTbody(table, $tbody, false);
362
+ }
363
+ // add classes to thead and tfoot
364
+ rows = wo.columns_thead !== false ? [ 'thead tr' ] : [];
365
+ if (wo.columns_tfoot !== false) {
366
+ rows.push('tfoot tr');
367
+ }
368
+ if (rows.length) {
369
+ $rows = $table.find( rows.join(',') ).children().removeClass(remove);
370
+ if (len) {
371
+ for (indx = 0; indx < len; indx++) {
372
+ // add primary. secondary, tertiary, etc sort column classes
373
+ $rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
374
+ }
375
+ }
376
+ }
377
+ },
378
+ remove: function(table, c, wo) {
379
+ var tbodyIndex, $tbody,
380
+ $tbodies = c.$tbodies,
381
+ remove = (wo.columns || [ 'primary', 'secondary', 'tertiary' ]).join(' ');
382
+ c.$headers.removeClass(remove);
383
+ c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
384
+ for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
385
+ $tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
386
+ $tbody.children('tr').each(function() {
387
+ $(this).children().removeClass(remove);
388
+ });
389
+ ts.processTbody(table, $tbody, false); // restore tbody
390
+ }
391
+ }
392
+ });
393
+
394
+ })(jQuery);
395
+
396
+ /*! Widget: filter - updated 2018-03-18 (v2.30.0) *//*
397
+ * Requires tablesorter v2.8+ and jQuery 1.7+
398
+ * by Rob Garrison
399
+ */
400
+ ;( function ( $ ) {
401
+ 'use strict';
402
+ var tsf, tsfRegex,
403
+ ts = $.tablesorter || {},
404
+ tscss = ts.css,
405
+ tskeyCodes = ts.keyCodes;
406
+
407
+ $.extend( tscss, {
408
+ filterRow : 'tablesorter-filter-row',
409
+ filter : 'tablesorter-filter',
410
+ filterDisabled : 'disabled',
411
+ filterRowHide : 'hideme'
412
+ });
413
+
414
+ $.extend( tskeyCodes, {
415
+ backSpace : 8,
416
+ escape : 27,
417
+ space : 32,
418
+ left : 37,
419
+ down : 40
420
+ });
421
+
422
+ ts.addWidget({
423
+ id: 'filter',
424
+ priority: 50,
425
+ options : {
426
+ filter_cellFilter : '', // css class name added to the filter cell ( string or array )
427
+ filter_childRows : false, // if true, filter includes child row content in the search
428
+ filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
429
+ filter_childWithSibs : true, // if true, include matching child row siblings
430
+ filter_columnAnyMatch: true, // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
431
+ filter_columnFilters : true, // if true, a filter will be added to the top of each table column
432
+ filter_cssFilter : '', // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
433
+ filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
434
+ filter_defaultFilter : {}, // add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
435
+ filter_excludeFilter : {}, // filters to exclude, per column
436
+ filter_external : '', // jQuery selector string ( or jQuery object ) of external filters
437
+ filter_filteredRow : 'filtered', // class added to filtered rows; define in css with "display:none" to hide the filtered-out rows
438
+ filter_filterLabel : 'Filter "{{label}}" column by...', // Aria-label added to filter input/select; see #1495
439
+ filter_formatter : null, // add custom filter elements to the filter row
440
+ filter_functions : null, // add custom filter functions using this option
441
+ filter_hideEmpty : true, // hide filter row when table is empty
442
+ filter_hideFilters : false, // collapse filter row when mouse leaves the area
443
+ filter_ignoreCase : true, // if true, make all searches case-insensitive
444
+ filter_liveSearch : true, // if true, search column content while the user types ( with a delay )
445
+ filter_matchType : { 'input': 'exact', 'select': 'exact' }, // global query settings ('exact' or 'match'); overridden by "filter-match" or "filter-exact" class
446
+ filter_onlyAvail : 'filter-onlyAvail', // a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
447
+ filter_placeholder : { search : '', select : '' }, // default placeholder text ( overridden by any header 'data-placeholder' setting )
448
+ filter_reset : null, // jQuery selector string of an element used to reset the filters
449
+ filter_resetOnEsc : true, // Reset filter input when the user presses escape - normalized across browsers
450
+ filter_saveFilters : false, // Use the $.tablesorter.storage utility to save the most recent filters
451
+ filter_searchDelay : 300, // typing delay in milliseconds before starting a search
452
+ filter_searchFiltered: true, // allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
453
+ filter_selectSource : null, // include a function to return an array of values to be added to the column filter select
454
+ filter_selectSourceSeparator : '|', // filter_selectSource array text left of the separator is added to the option value, right into the option text
455
+ filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
456
+ filter_startsWith : false, // if true, filter start from the beginning of the cell contents
457
+ filter_useParsedData : false // filter all data using parsed content
458
+ },
459
+ format: function( table, c, wo ) {
460
+ if ( !c.$table.hasClass( 'hasFilters' ) ) {
461
+ tsf.init( table, c, wo );
462
+ }
463
+ },
464
+ remove: function( table, c, wo, refreshing ) {
465
+ var tbodyIndex, $tbody,
466
+ $table = c.$table,
467
+ $tbodies = c.$tbodies,
468
+ events = (
469
+ 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
470
+ 'filterAndSortReset filterFomatterUpdate filterEnd search stickyHeadersInit '
471
+ ).split( ' ' ).join( c.namespace + 'filter ' );
472
+ $table
473
+ .removeClass( 'hasFilters' )
474
+ // add filter namespace to all BUT search
475
+ .unbind( events.replace( ts.regex.spaces, ' ' ) )
476
+ // remove the filter row even if refreshing, because the column might have been moved
477
+ .find( '.' + tscss.filterRow ).remove();
478
+ wo.filter_initialized = false;
479
+ if ( refreshing ) { return; }
480
+ for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
481
+ $tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
482
+ $tbody.children().removeClass( wo.filter_filteredRow ).show();
483
+ ts.processTbody( table, $tbody, false ); // restore tbody
484
+ }
485
+ if ( wo.filter_reset ) {
486
+ $( document ).undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' );
487
+ }
488
+ }
489
+ });
490
+
491
+ tsf = ts.filter = {
492
+
493
+ // regex used in filter 'check' functions - not for general use and not documented
494
+ regex: {
495
+ regex : /^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/, // regex to test for regex
496
+ child : /tablesorter-childRow/, // child row class name; this gets updated in the script
497
+ filtered : /filtered/, // filtered (hidden) row class name; updated in the script
498
+ type : /undefined|number/, // check type
499
+ exact : /(^[\"\'=]+)|([\"\'=]+$)/g, // exact match (allow '==')
500
+ operators : /[<>=]/g, // replace operators
501
+ query : '(q|query)', // replace filter queries
502
+ wild01 : /\?/g, // wild card match 0 or 1
503
+ wild0More : /\*/g, // wild care match 0 or more
504
+ quote : /\"/g,
505
+ isNeg1 : /(>=?\s*-\d)/,
506
+ isNeg2 : /(<=?\s*\d)/
507
+ },
508
+ // function( c, data ) { }
509
+ // c = table.config
510
+ // data.$row = jQuery object of the row currently being processed
511
+ // data.$cells = jQuery object of all cells within the current row
512
+ // data.filters = array of filters for all columns ( some may be undefined )
513
+ // data.filter = filter for the current column
514
+ // data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true )
515
+ // data.exact = table cell text ( or parsed data if column parser enabled; may be a number & not a string )
516
+ // data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true; may be a number & not a string )
517
+ // data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true )
518
+ // data.cacheArray = An array of parsed content from each table cell in the row being processed
519
+ // data.index = column index; table = table element ( DOM )
520
+ // data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
521
+ types: {
522
+ or : function( c, data, vars ) {
523
+ // look for "|", but not if it is inside of a regular expression
524
+ if ( ( tsfRegex.orTest.test( data.iFilter ) || tsfRegex.orSplit.test( data.filter ) ) &&
525
+ // this test for regex has potential to slow down the overall search
526
+ !tsfRegex.regex.test( data.filter ) ) {
527
+ var indx, filterMatched, query, regex,
528
+ // duplicate data but split filter
529
+ data2 = $.extend( {}, data ),
530
+ filter = data.filter.split( tsfRegex.orSplit ),
531
+ iFilter = data.iFilter.split( tsfRegex.orSplit ),
532
+ len = filter.length;
533
+ for ( indx = 0; indx < len; indx++ ) {
534
+ data2.nestedFilters = true;
535
+ data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
536
+ data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
537
+ query = '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')';
538
+ try {
539
+ // use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
540
+ // e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
541
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
542
+ // filterMatched = data2.filter === '' && indx > 0 ? true
543
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
544
+ filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
545
+ if ( filterMatched ) {
546
+ return filterMatched;
547
+ }
548
+ } catch ( error ) {
549
+ return null;
550
+ }
551
+ }
552
+ // may be null from processing types
553
+ return filterMatched || false;
554
+ }
555
+ return null;
556
+ },
557
+ // Look for an AND or && operator ( logical and )
558
+ and : function( c, data, vars ) {
559
+ if ( tsfRegex.andTest.test( data.filter ) ) {
560
+ var indx, filterMatched, result, query, regex,
561
+ // duplicate data but split filter
562
+ data2 = $.extend( {}, data ),
563
+ filter = data.filter.split( tsfRegex.andSplit ),
564
+ iFilter = data.iFilter.split( tsfRegex.andSplit ),
565
+ len = filter.length;
566
+ for ( indx = 0; indx < len; indx++ ) {
567
+ data2.nestedFilters = true;
568
+ data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
569
+ data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
570
+ query = ( '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')' )
571
+ // replace wild cards since /(a*)/i will match anything
572
+ .replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' );
573
+ try {
574
+ // use try/catch just in case RegExp is invalid
575
+ regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
576
+ // look for an exact match with the 'and' unless the 'filter-match' class is found
577
+ result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
578
+ if ( indx === 0 ) {
579
+ filterMatched = result;
580
+ } else {
581
+ filterMatched = filterMatched && result;
582
+ }
583
+ } catch ( error ) {
584
+ return null;
585
+ }
586
+ }
587
+ // may be null from processing types
588
+ return filterMatched || false;
589
+ }
590
+ return null;
591
+ },
592
+ // Look for regex
593
+ regex: function( c, data ) {
594
+ if ( tsfRegex.regex.test( data.filter ) ) {
595
+ var matches,
596
+ // cache regex per column for optimal speed
597
+ regex = data.filter_regexCache[ data.index ] || tsfRegex.regex.exec( data.filter ),
598
+ isRegex = regex instanceof RegExp;
599
+ try {
600
+ if ( !isRegex ) {
601
+ // force case insensitive search if ignoreCase option set?
602
+ // if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
603
+ data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
604
+ }
605
+ matches = regex.test( data.exact );
606
+ } catch ( error ) {
607
+ matches = false;
608
+ }
609
+ return matches;
610
+ }
611
+ return null;
612
+ },
613
+ // Look for operators >, >=, < or <=
614
+ operators: function( c, data ) {
615
+ // ignore empty strings... because '' < 10 is true
616
+ if ( tsfRegex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
617
+ var cachedValue, result, txt,
618
+ table = c.table,
619
+ parsed = data.parsed[ data.index ],
620
+ query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
621
+ parser = c.parsers[ data.index ] || {},
622
+ savedSearch = query;
623
+ // parse filter value in case we're comparing numbers ( dates )
624
+ if ( parsed || parser.type === 'numeric' ) {
625
+ txt = $.trim( '' + data.iFilter.replace( tsfRegex.operators, '' ) );
626
+ result = tsf.parseFilter( c, txt, data, true );
627
+ query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
628
+ }
629
+ // iExact may be numeric - see issue #149;
630
+ // check if cached is defined, because sometimes j goes out of range? ( numeric columns )
631
+ if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
632
+ typeof data.cache !== 'undefined' ) {
633
+ cachedValue = data.cache;
634
+ } else {
635
+ txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
636
+ cachedValue = ts.formatFloat( txt, table );
637
+ }
638
+ if ( tsfRegex.gtTest.test( data.iFilter ) ) {
639
+ result = tsfRegex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
640
+ } else if ( tsfRegex.ltTest.test( data.iFilter ) ) {
641
+ result = tsfRegex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
642
+ }
643
+ // keep showing all rows if nothing follows the operator
644
+ if ( !result && savedSearch === '' ) {
645
+ result = true;
646
+ }
647
+ return result;
648
+ }
649
+ return null;
650
+ },
651
+ // Look for a not match
652
+ notMatch: function( c, data ) {
653
+ if ( tsfRegex.notTest.test( data.iFilter ) ) {
654
+ var indx,
655
+ txt = data.iFilter.replace( '!', '' ),
656
+ filter = tsf.parseFilter( c, txt, data ) || '';
657
+ if ( tsfRegex.exact.test( filter ) ) {
658
+ // look for exact not matches - see #628
659
+ filter = filter.replace( tsfRegex.exact, '' );
660
+ return filter === '' ? true : $.trim( filter ) !== data.iExact;
661
+ } else {
662
+ indx = data.iExact.search( $.trim( filter ) );
663
+ return filter === '' ? true :
664
+ // return true if not found
665
+ data.anyMatch ? indx < 0 :
666
+ // return false if found
667
+ !( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
668
+ }
669
+ }
670
+ return null;
671
+ },
672
+ // Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
673
+ exact: function( c, data ) {
674
+ /*jshint eqeqeq:false */
675
+ if ( tsfRegex.exact.test( data.iFilter ) ) {
676
+ var txt = data.iFilter.replace( tsfRegex.exact, '' ),
677
+ filter = tsf.parseFilter( c, txt, data ) || '';
678
+ // eslint-disable-next-line eqeqeq
679
+ return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
680
+ }
681
+ return null;
682
+ },
683
+ // Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
684
+ range : function( c, data ) {
685
+ if ( tsfRegex.toTest.test( data.iFilter ) ) {
686
+ var result, tmp, range1, range2,
687
+ table = c.table,
688
+ index = data.index,
689
+ parsed = data.parsed[index],
690
+ // make sure the dash is for a range and not indicating a negative number
691
+ query = data.iFilter.split( tsfRegex.toSplit );
692
+
693
+ tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
694
+ range1 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
695
+ tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
696
+ range2 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
697
+ // parse filter value in case we're comparing numbers ( dates )
698
+ if ( parsed || c.parsers[ index ].type === 'numeric' ) {
699
+ result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
700
+ range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
701
+ result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
702
+ range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
703
+ }
704
+ if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
705
+ result = data.cache;
706
+ } else {
707
+ tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
708
+ result = ts.formatFloat( tmp, table );
709
+ }
710
+ if ( range1 > range2 ) {
711
+ tmp = range1; range1 = range2; range2 = tmp; // swap
712
+ }
713
+ return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
714
+ }
715
+ return null;
716
+ },
717
+ // Look for wild card: ? = single, * = multiple, or | = logical OR
718
+ wild : function( c, data ) {
719
+ if ( tsfRegex.wildOrTest.test( data.iFilter ) ) {
720
+ var query = '' + ( tsf.parseFilter( c, data.iFilter, data ) || '' );
721
+ // look for an exact match with the 'or' unless the 'filter-match' class is found
722
+ if ( !tsfRegex.wildTest.test( query ) && data.nestedFilters ) {
723
+ query = data.isMatch ? query : '^(' + query + ')$';
724
+ }
725
+ // parsing the filter may not work properly when using wildcards =/
726
+ try {
727
+ return new RegExp(
728
+ query.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' ),
729
+ c.widgetOptions.filter_ignoreCase ? 'i' : ''
730
+ )
731
+ .test( data.exact );
732
+ } catch ( error ) {
733
+ return null;
734
+ }
735
+ }
736
+ return null;
737
+ },
738
+ // fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
739
+ fuzzy: function( c, data ) {
740
+ if ( tsfRegex.fuzzyTest.test( data.iFilter ) ) {
741
+ var indx,
742
+ patternIndx = 0,
743
+ len = data.iExact.length,
744
+ txt = data.iFilter.slice( 1 ),
745
+ pattern = tsf.parseFilter( c, txt, data ) || '';
746
+ for ( indx = 0; indx < len; indx++ ) {
747
+ if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
748
+ patternIndx += 1;
749
+ }
750
+ }
751
+ return patternIndx === pattern.length;
752
+ }
753
+ return null;
754
+ }
755
+ },
756
+ init: function( table ) {
757
+ // filter language options
758
+ ts.language = $.extend( true, {}, {
759
+ to : 'to',
760
+ or : 'or',
761
+ and : 'and'
762
+ }, ts.language );
763
+
764
+ var options, string, txt, $header, column, val, fxn, noSelect,
765
+ c = table.config,
766
+ wo = c.widgetOptions,
767
+ processStr = function(prefix, str, suffix) {
768
+ str = str.trim();
769
+ // don't include prefix/suffix if str is empty
770
+ return str === '' ? '' : (prefix || '') + str + (suffix || '');
771
+ };
772
+ c.$table.addClass( 'hasFilters' );
773
+ c.lastSearch = [];
774
+
775
+ // define timers so using clearTimeout won't cause an undefined error
776
+ wo.filter_searchTimer = null;
777
+ wo.filter_initTimer = null;
778
+ wo.filter_formatterCount = 0;
779
+ wo.filter_formatterInit = [];
780
+ wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
781
+ wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
782
+
783
+ val = '\\{' + tsfRegex.query + '\\}';
784
+ $.extend( tsfRegex, {
785
+ child : new RegExp( c.cssChildRow ),
786
+ filtered : new RegExp( wo.filter_filteredRow ),
787
+ alreadyFiltered : new RegExp( '(\\s+(-' + processStr('|', ts.language.or) + processStr('|', ts.language.to) + ')\\s+)', 'i' ),
788
+ toTest : new RegExp( '\\s+(-' + processStr('|', ts.language.to) + ')\\s+', 'i' ),
789
+ toSplit : new RegExp( '(?:\\s+(?:-' + processStr('|', ts.language.to) + ')\\s+)', 'gi' ),
790
+ andTest : new RegExp( '\\s+(' + processStr('', ts.language.and, '|') + '&&)\\s+', 'i' ),
791
+ andSplit : new RegExp( '(?:\\s+(?:' + processStr('', ts.language.and, '|') + '&&)\\s+)', 'gi' ),
792
+ orTest : new RegExp( '(\\|' + processStr('|\\s+', ts.language.or, '\\s+') + ')', 'i' ),
793
+ orSplit : new RegExp( '(?:\\|' + processStr('|\\s+(?:', ts.language.or, ')\\s+') + ')', 'gi' ),
794
+ iQuery : new RegExp( val, 'i' ),
795
+ igQuery : new RegExp( val, 'ig' ),
796
+ operTest : /^[<>]=?/,
797
+ gtTest : />/,
798
+ gteTest : />=/,
799
+ ltTest : /</,
800
+ lteTest : /<=/,
801
+ notTest : /^\!/,
802
+ wildOrTest : /[\?\*\|]/,
803
+ wildTest : /\?\*/,
804
+ fuzzyTest : /^~/,
805
+ exactTest : /[=\"\|!]/
806
+ });
807
+
808
+ // don't build filter row if columnFilters is false or all columns are set to 'filter-false'
809
+ // see issue #156
810
+ val = c.$headers.filter( '.filter-false, .parser-false' ).length;
811
+ if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
812
+ // build filter row
813
+ tsf.buildRow( table, c, wo );
814
+ }
815
+
816
+ txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
817
+ 'filterAndSortReset filterResetSaved filterEnd search '.split( ' ' ).join( c.namespace + 'filter ' );
818
+ c.$table.bind( txt, function( event, filter ) {
819
+ val = wo.filter_hideEmpty &&
820
+ $.isEmptyObject( c.cache ) &&
821
+ !( c.delayInit && event.type === 'appendCache' );
822
+ // hide filter row using the 'filtered' class name
823
+ c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
824
+ if ( !/(search|filter)/.test( event.type ) ) {
825
+ event.stopPropagation();
826
+ tsf.buildDefault( table, true );
827
+ }
828
+ // Add filterAndSortReset - see #1361
829
+ if ( event.type === 'filterReset' || event.type === 'filterAndSortReset' ) {
830
+ c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
831
+ if ( event.type === 'filterAndSortReset' ) {
832
+ ts.sortReset( this.config, function() {
833
+ tsf.searching( table, [] );
834
+ });
835
+ } else {
836
+ tsf.searching( table, [] );
837
+ }
838
+ } else if ( event.type === 'filterResetSaved' ) {
839
+ ts.storage( table, 'tablesorter-filters', '' );
840
+ } else if ( event.type === 'filterEnd' ) {
841
+ tsf.buildDefault( table, true );
842
+ } else {
843
+ // send false argument to force a new search; otherwise if the filter hasn't changed,
844
+ // it will return
845
+ filter = event.type === 'search' ? filter :
846
+ event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
847
+ if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
848
+ // force a new search since content has changed
849
+ c.lastCombinedFilter = null;
850
+ c.lastSearch = [];
851
+ // update filterFormatters after update (& small delay) - Fixes #1237
852
+ setTimeout(function() {
853
+ c.$table.triggerHandler( 'filterFomatterUpdate' );
854
+ }, 100);
855
+ }
856
+ // pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
857
+ // input ensures all inputs are updated when a search is triggered on the table
858
+ // $( 'table' ).trigger( 'search', [...] );
859
+ tsf.searching( table, filter, true );
860
+ }
861
+ return false;
862
+ });
863
+
864
+ // reset button/link
865
+ if ( wo.filter_reset ) {
866
+ if ( wo.filter_reset instanceof $ ) {
867
+ // reset contains a jQuery object, bind to it
868
+ wo.filter_reset.click( function() {
869
+ c.$table.triggerHandler( 'filterReset' );
870
+ });
871
+ } else if ( $( wo.filter_reset ).length ) {
872
+ // reset is a jQuery selector, use event delegation
873
+ $( document )
874
+ .undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' )
875
+ .delegate( wo.filter_reset, 'click' + c.namespace + 'filter', function() {
876
+ // trigger a reset event, so other functions ( filter_formatter ) know when to reset
877
+ c.$table.triggerHandler( 'filterReset' );
878
+ });
879
+ }
880
+ }
881
+ if ( wo.filter_functions ) {
882
+ for ( column = 0; column < c.columns; column++ ) {
883
+ fxn = ts.getColumnData( table, wo.filter_functions, column );
884
+ if ( fxn ) {
885
+ // remove 'filter-select' from header otherwise the options added here are replaced with
886
+ // all options
887
+ $header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
888
+ // don't build select if 'filter-false' or 'parser-false' set
889
+ noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
890
+ options = '';
891
+ if ( fxn === true && noSelect ) {
892
+ tsf.buildSelect( table, column );
893
+ } else if ( typeof fxn === 'object' && noSelect ) {
894
+ // add custom drop down list
895
+ for ( string in fxn ) {
896
+ if ( typeof string === 'string' ) {
897
+ options += options === '' ?
898
+ '<option value="">' +
899
+ ( $header.data( 'placeholder' ) ||
900
+ $header.attr( 'data-placeholder' ) ||
901
+ wo.filter_placeholder.select ||
902
+ ''
903
+ ) +
904
+ '</option>' : '';
905
+ val = string;
906
+ txt = string;
907
+ if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
908
+ val = string.split( wo.filter_selectSourceSeparator );
909
+ txt = val[1];
910
+ val = val[0];
911
+ }
912
+ options += '<option ' +
913
+ ( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
914
+ 'value="' + val + '">' + txt + '</option>';
915
+ }
916
+ }
917
+ c.$table
918
+ .find( 'thead' )
919
+ .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
920
+ .append( options );
921
+ txt = wo.filter_selectSource;
922
+ fxn = typeof txt === 'function' ? true : ts.getColumnData( table, txt, column );
923
+ if ( fxn ) {
924
+ // updating so the extra options are appended
925
+ tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.filter_onlyAvail ) );
926
+ }
927
+ }
928
+ }
929
+ }
930
+ }
931
+ // not really updating, but if the column has both the 'filter-select' class &
932
+ // filter_functions set to true, it would append the same options twice.
933
+ tsf.buildDefault( table, true );
934
+
935
+ tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
936
+ if ( wo.filter_external ) {
937
+ tsf.bindSearch( table, wo.filter_external );
938
+ }
939
+
940
+ if ( wo.filter_hideFilters ) {
941
+ tsf.hideFilters( c );
942
+ }
943
+
944
+ // show processing icon
945
+ if ( c.showProcessing ) {
946
+ txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter-sp ' );
947
+ c.$table
948
+ .unbind( txt.replace( ts.regex.spaces, ' ' ) )
949
+ .bind( txt, function( event, columns ) {
950
+ // only add processing to certain columns to all columns
951
+ $header = ( columns ) ?
952
+ c.$table
953
+ .find( '.' + tscss.header )
954
+ .filter( '[data-column]' )
955
+ .filter( function() {
956
+ return columns[ $( this ).data( 'column' ) ] !== '';
957
+ }) : '';
958
+ ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
959
+ });
960
+ }
961
+
962
+ // set filtered rows count ( intially unfiltered )
963
+ c.filteredRows = c.totalRows;
964
+
965
+ // add default values
966
+ txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
967
+ c.$table
968
+ .unbind( txt.replace( ts.regex.spaces, ' ' ) )
969
+ .bind( txt, function() {
970
+ tsf.completeInit( this );
971
+ });
972
+ // if filter widget is added after pager has initialized; then set filter init flag
973
+ if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
974
+ c.$table.triggerHandler( 'filterFomatterUpdate' );
975
+ setTimeout( function() {
976
+ tsf.filterInitComplete( c );
977
+ }, 100 );
978
+ } else if ( !wo.filter_initialized ) {
979
+ tsf.completeInit( table );
980
+ }
981
+ },
982
+ completeInit: function( table ) {
983
+ // redefine 'c' & 'wo' so they update properly inside this callback
984
+ var c = table.config,
985
+ wo = c.widgetOptions,
986
+ filters = tsf.setDefaults( table, c, wo ) || [];
987
+ if ( filters.length ) {
988
+ // prevent delayInit from triggering a cache build if filters are empty
989
+ if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
990
+ ts.setFilters( table, filters, true );
991
+ }
992
+ }
993
+ c.$table.triggerHandler( 'filterFomatterUpdate' );
994
+ // trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
995
+ setTimeout( function() {
996
+ if ( !wo.filter_initialized ) {
997
+ tsf.filterInitComplete( c );
998
+ }
999
+ }, 100 );
1000
+ },
1001
+
1002
+ // $cell parameter, but not the config, is passed to the filter_formatters,
1003
+ // so we have to work with it instead
1004
+ formatterUpdated: function( $cell, column ) {
1005
+ // prevent error if $cell is undefined - see #1056
1006
+ var $table = $cell && $cell.closest( 'table' );
1007
+ var config = $table.length && $table[0].config,
1008
+ wo = config && config.widgetOptions;
1009
+ if ( wo && !wo.filter_initialized ) {
1010
+ // add updates by column since this function
1011
+ // may be called numerous times before initialization
1012
+ wo.filter_formatterInit[ column ] = 1;
1013
+ }
1014
+ },
1015
+ filterInitComplete: function( c ) {
1016
+ var indx, len,
1017
+ wo = c.widgetOptions,
1018
+ count = 0,
1019
+ completed = function() {
1020
+ wo.filter_initialized = true;
1021
+ // update lastSearch - it gets cleared often
1022
+ c.lastSearch = c.$table.data( 'lastSearch' );
1023
+ c.$table.triggerHandler( 'filterInit', c );
1024
+ tsf.findRows( c.table, c.lastSearch || [] );
1025
+ if (ts.debug(c, 'filter')) {
1026
+ console.log('Filter >> Widget initialized');
1027
+ }
1028
+ };
1029
+ if ( $.isEmptyObject( wo.filter_formatter ) ) {
1030
+ completed();
1031
+ } else {
1032
+ len = wo.filter_formatterInit.length;
1033
+ for ( indx = 0; indx < len; indx++ ) {
1034
+ if ( wo.filter_formatterInit[ indx ] === 1 ) {
1035
+ count++;
1036
+ }
1037
+ }
1038
+ clearTimeout( wo.filter_initTimer );
1039
+ if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
1040
+ // filter widget initialized
1041
+ completed();
1042
+ } else if ( !wo.filter_initialized ) {
1043
+ // fall back in case a filter_formatter doesn't call
1044
+ // $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
1045
+ wo.filter_initTimer = setTimeout( function() {
1046
+ completed();
1047
+ }, 500 );
1048
+ }
1049
+ }
1050
+ },
1051
+ // encode or decode filters for storage; see #1026
1052
+ processFilters: function( filters, encode ) {
1053
+ var indx,
1054
+ // fixes #1237; previously returning an encoded "filters" value
1055
+ result = [],
1056
+ mode = encode ? encodeURIComponent : decodeURIComponent,
1057
+ len = filters.length;
1058
+ for ( indx = 0; indx < len; indx++ ) {
1059
+ if ( filters[ indx ] ) {
1060
+ result[ indx ] = mode( filters[ indx ] );
1061
+ }
1062
+ }
1063
+ return result;
1064
+ },
1065
+ setDefaults: function( table, c, wo ) {
1066
+ var isArray, saved, indx, col, $filters,
1067
+ // get current ( default ) filters
1068
+ filters = ts.getFilters( table ) || [];
1069
+ if ( wo.filter_saveFilters && ts.storage ) {
1070
+ saved = ts.storage( table, 'tablesorter-filters' ) || [];
1071
+ isArray = $.isArray( saved );
1072
+ // make sure we're not just getting an empty array
1073
+ if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
1074
+ filters = tsf.processFilters( saved );
1075
+ }
1076
+ }
1077
+ // if no filters saved, then check default settings
1078
+ if ( filters.join( '' ) === '' ) {
1079
+ // allow adding default setting to external filters
1080
+ $filters = c.$headers.add( wo.filter_$externalFilters )
1081
+ .filter( '[' + wo.filter_defaultAttrib + ']' );
1082
+ for ( indx = 0; indx <= c.columns; indx++ ) {
1083
+ // include data-column='all' external filters
1084
+ col = indx === c.columns ? 'all' : indx;
1085
+ filters[ indx ] = $filters
1086
+ .filter( '[data-column="' + col + '"]' )
1087
+ .attr( wo.filter_defaultAttrib ) || filters[indx] || '';
1088
+ }
1089
+ }
1090
+ c.$table.data( 'lastSearch', filters );
1091
+ return filters;
1092
+ },
1093
+ parseFilter: function( c, filter, data, parsed ) {
1094
+ return parsed || data.parsed[ data.index ] ?
1095
+ c.parsers[ data.index ].format( filter, c.table, [], data.index ) :
1096
+ filter;
1097
+ },
1098
+ buildRow: function( table, c, wo ) {
1099
+ var $filter, col, column, $header, makeSelect, disabled, name, ffxn, tmp,
1100
+ // c.columns defined in computeThIndexes()
1101
+ cellFilter = wo.filter_cellFilter,
1102
+ columns = c.columns,
1103
+ arry = $.isArray( cellFilter ),
1104
+ buildFilter = '<tr role="search" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
1105
+ for ( column = 0; column < columns; column++ ) {
1106
+ if ( c.$headerIndexed[ column ].length ) {
1107
+ // account for entire column set with colspan. See #1047
1108
+ tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
1109
+ if ( tmp > 1 ) {
1110
+ buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
1111
+ } else {
1112
+ buildFilter += '<td data-column="' + column + '"';
1113
+ }
1114
+ if ( arry ) {
1115
+ buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
1116
+ } else {
1117
+ buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
1118
+ }
1119
+ buildFilter += '></td>';
1120
+ }
1121
+ }
1122
+ c.$filters = $( buildFilter += '</tr>' )
1123
+ .appendTo( c.$table.children( 'thead' ).eq( 0 ) )
1124
+ .children( 'td' );
1125
+ // build each filter input
1126
+ for ( column = 0; column < columns; column++ ) {
1127
+ disabled = false;
1128
+ // assuming last cell of a column is the main column
1129
+ $header = c.$headerIndexed[ column ];
1130
+ if ( $header && $header.length ) {
1131
+ // $filter = c.$filters.filter( '[data-column="' + column + '"]' );
1132
+ $filter = tsf.getColumnElm( c, c.$filters, column );
1133
+ ffxn = ts.getColumnData( table, wo.filter_functions, column );
1134
+ makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
1135
+ $header.hasClass( 'filter-select' );
1136
+ // get data from jQuery data, metadata, headers option or header class name
1137
+ col = ts.getColumnData( table, c.headers, column );
1138
+ disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
1139
+ ts.getData( $header[0], col, 'parser' ) === 'false';
1140
+
1141
+ if ( makeSelect ) {
1142
+ buildFilter = $( '<select>' ).appendTo( $filter );
1143
+ } else {
1144
+ ffxn = ts.getColumnData( table, wo.filter_formatter, column );
1145
+ if ( ffxn ) {
1146
+ wo.filter_formatterCount++;
1147
+ buildFilter = ffxn( $filter, column );
1148
+ // no element returned, so lets go find it
1149
+ if ( buildFilter && buildFilter.length === 0 ) {
1150
+ buildFilter = $filter.children( 'input' );
1151
+ }
1152
+ // element not in DOM, so lets attach it
1153
+ if ( buildFilter && ( buildFilter.parent().length === 0 ||
1154
+ ( buildFilter.parent().length && buildFilter.parent()[0] !== $filter[0] ) ) ) {
1155
+ $filter.append( buildFilter );
1156
+ }
1157
+ } else {
1158
+ buildFilter = $( '<input type="search">' ).appendTo( $filter );
1159
+ }
1160
+ if ( buildFilter ) {
1161
+ tmp = $header.data( 'placeholder' ) ||
1162
+ $header.attr( 'data-placeholder' ) ||
1163
+ wo.filter_placeholder.search || '';
1164
+ buildFilter.attr( 'placeholder', tmp );
1165
+ }
1166
+ }
1167
+ if ( buildFilter ) {
1168
+ // add filter class name
1169
+ name = ( $.isArray( wo.filter_cssFilter ) ?
1170
+ ( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
1171
+ wo.filter_cssFilter ) || '';
1172
+ // copy data-column from table cell (it will include colspan)
1173
+ buildFilter.addClass( tscss.filter + ' ' + name );
1174
+ name = wo.filter_filterLabel;
1175
+ tmp = name.match(/{{([^}]+?)}}/g);
1176
+ if (!tmp) {
1177
+ tmp = [ '{{label}}' ];
1178
+ }
1179
+ $.each(tmp, function(indx, attr) {
1180
+ var regex = new RegExp(attr, 'g'),
1181
+ data = $header.attr('data-' + attr.replace(/{{|}}/g, '')),
1182
+ text = typeof data === 'undefined' ? $header.text() : data;
1183
+ name = name.replace( regex, $.trim( text ) );
1184
+ });
1185
+ buildFilter.attr({
1186
+ 'data-column': $filter.attr( 'data-column' ),
1187
+ 'aria-label': name
1188
+ });
1189
+ if ( disabled ) {
1190
+ buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ },
1196
+ bindSearch: function( table, $el, internal ) {
1197
+ table = $( table )[0];
1198
+ $el = $( $el ); // allow passing a selector string
1199
+ if ( !$el.length ) { return; }
1200
+ var tmp,
1201
+ c = table.config,
1202
+ wo = c.widgetOptions,
1203
+ namespace = c.namespace + 'filter',
1204
+ $ext = wo.filter_$externalFilters;
1205
+ if ( internal !== true ) {
1206
+ // save anyMatch element
1207
+ tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
1208
+ wo.filter_$anyMatch = $el.filter( tmp );
1209
+ if ( $ext && $ext.length ) {
1210
+ wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
1211
+ } else {
1212
+ wo.filter_$externalFilters = $el;
1213
+ }
1214
+ // update values ( external filters added after table initialization )
1215
+ ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
1216
+ }
1217
+ // unbind events
1218
+ tmp = ( 'keypress keyup keydown search change input '.split( ' ' ).join( namespace + ' ' ) );
1219
+ $el
1220
+ // use data attribute instead of jQuery data since the head is cloned without including
1221
+ // the data/binding
1222
+ .attr( 'data-lastSearchTime', new Date().getTime() )
1223
+ .unbind( tmp.replace( ts.regex.spaces, ' ' ) )
1224
+ .bind( 'keydown' + namespace, function( event ) {
1225
+ if ( event.which === tskeyCodes.escape && !table.config.widgetOptions.filter_resetOnEsc ) {
1226
+ // prevent keypress event
1227
+ return false;
1228
+ }
1229
+ })
1230
+ .bind( 'keyup' + namespace, function( event ) {
1231
+ wo = table.config.widgetOptions; // make sure "wo" isn't cached
1232
+ var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
1233
+ liveSearch = typeof wo.filter_liveSearch === 'boolean' ? wo.filter_liveSearch :
1234
+ ts.getColumnData( table, wo.filter_liveSearch, column );
1235
+ if ( typeof liveSearch === 'undefined' ) {
1236
+ liveSearch = wo.filter_liveSearch.fallback || false;
1237
+ }
1238
+ $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
1239
+ // emulate what webkit does.... escape clears the filter
1240
+ if ( event.which === tskeyCodes.escape ) {
1241
+ // make sure to restore the last value on escape
1242
+ this.value = wo.filter_resetOnEsc ? '' : c.lastSearch[column];
1243
+ // don't return if the search value is empty ( all rows need to be revealed )
1244
+ } else if ( this.value !== '' && (
1245
+ // liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
1246
+ ( typeof liveSearch === 'number' && this.value.length < liveSearch ) ||
1247
+ // let return & backspace continue on, but ignore arrows & non-valid characters
1248
+ ( event.which !== tskeyCodes.enter && event.which !== tskeyCodes.backSpace &&
1249
+ ( event.which < tskeyCodes.space || ( event.which >= tskeyCodes.left && event.which <= tskeyCodes.down ) ) ) ) ) {
1250
+ return;
1251
+ // live search
1252
+ } else if ( liveSearch === false ) {
1253
+ if ( this.value !== '' && event.which !== tskeyCodes.enter ) {
1254
+ return;
1255
+ }
1256
+ }
1257
+ // change event = no delay; last true flag tells getFilters to skip newest timed input
1258
+ tsf.searching( table, true, true, column );
1259
+ })
1260
+ // include change for select - fixes #473
1261
+ .bind( 'search change keypress input blur '.split( ' ' ).join( namespace + ' ' ), function( event ) {
1262
+ // don't get cached data, in case data-column changes dynamically
1263
+ var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
1264
+ eventType = event.type,
1265
+ liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
1266
+ wo.filter_liveSearch :
1267
+ ts.getColumnData( table, wo.filter_liveSearch, column );
1268
+ if ( table.config.widgetOptions.filter_initialized &&
1269
+ // immediate search if user presses enter
1270
+ ( event.which === tskeyCodes.enter ||
1271
+ // immediate search if a "search" or "blur" is triggered on the input
1272
+ ( eventType === 'search' || eventType === 'blur' ) ||
1273
+ // change & input events must be ignored if liveSearch !== true
1274
+ ( eventType === 'change' || eventType === 'input' ) &&
1275
+ // prevent search if liveSearch is a number
1276
+ ( liveSearch === true || liveSearch !== true && event.target.nodeName !== 'INPUT' ) &&
1277
+ // don't allow 'change' or 'input' event to process if the input value
1278
+ // is the same - fixes #685
1279
+ this.value !== c.lastSearch[column]
1280
+ )
1281
+ ) {
1282
+ event.preventDefault();
1283
+ // init search with no delay
1284
+ $( this ).attr( 'data-lastSearchTime', new Date().getTime() );
1285
+ tsf.searching( table, eventType !== 'keypress', true, column );
1286
+ }
1287
+ });
1288
+ },
1289
+ searching: function( table, filter, skipFirst, column ) {
1290
+ var liveSearch,
1291
+ wo = table.config.widgetOptions;
1292
+ if (typeof column === 'undefined') {
1293
+ // no delay
1294
+ liveSearch = false;
1295
+ } else {
1296
+ liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
1297
+ wo.filter_liveSearch :
1298
+ // get column setting, or set to fallback value, or default to false
1299
+ ts.getColumnData( table, wo.filter_liveSearch, column );
1300
+ if ( typeof liveSearch === 'undefined' ) {
1301
+ liveSearch = wo.filter_liveSearch.fallback || false;
1302
+ }
1303
+ }
1304
+ clearTimeout( wo.filter_searchTimer );
1305
+ if ( typeof filter === 'undefined' || filter === true ) {
1306
+ // delay filtering
1307
+ wo.filter_searchTimer = setTimeout( function() {
1308
+ tsf.checkFilters( table, filter, skipFirst );
1309
+ }, liveSearch ? wo.filter_searchDelay : 10 );
1310
+ } else {
1311
+ // skip delay
1312
+ tsf.checkFilters( table, filter, skipFirst );
1313
+ }
1314
+ },
1315
+ equalFilters: function (c, filter1, filter2) {
1316
+ var indx,
1317
+ f1 = [],
1318
+ f2 = [],
1319
+ len = c.columns + 1; // add one to include anyMatch filter
1320
+ filter1 = $.isArray(filter1) ? filter1 : [];
1321
+ filter2 = $.isArray(filter2) ? filter2 : [];
1322
+ for (indx = 0; indx < len; indx++) {
1323
+ f1[indx] = filter1[indx] || '';
1324
+ f2[indx] = filter2[indx] || '';
1325
+ }
1326
+ return f1.join(',') === f2.join(',');
1327
+ },
1328
+ checkFilters: function( table, filter, skipFirst ) {
1329
+ var c = table.config,
1330
+ wo = c.widgetOptions,
1331
+ filterArray = $.isArray( filter ),
1332
+ filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
1333
+ currentFilters = filters || []; // current filter values
1334
+ // prevent errors if delay init is set
1335
+ if ( $.isEmptyObject( c.cache ) ) {
1336
+ // update cache if delayInit set & pager has initialized ( after user initiates a search )
1337
+ if ( c.delayInit && ( !c.pager || c.pager && c.pager.initialized ) ) {
1338
+ ts.updateCache( c, function() {
1339
+ tsf.checkFilters( table, false, skipFirst );
1340
+ });
1341
+ }
1342
+ return;
1343
+ }
1344
+ // add filter array back into inputs
1345
+ if ( filterArray ) {
1346
+ ts.setFilters( table, filters, false, skipFirst !== true );
1347
+ if ( !wo.filter_initialized ) {
1348
+ c.lastSearch = [];
1349
+ c.lastCombinedFilter = '';
1350
+ }
1351
+ }
1352
+ if ( wo.filter_hideFilters ) {
1353
+ // show/hide filter row as needed
1354
+ c.$table
1355
+ .find( '.' + tscss.filterRow )
1356
+ .triggerHandler( tsf.hideFiltersCheck( c ) ? 'mouseleave' : 'mouseenter' );
1357
+ }
1358
+ // return if the last search is the same; but filter === false when updating the search
1359
+ // see example-widget-filter.html filter toggle buttons
1360
+ if ( tsf.equalFilters(c, c.lastSearch, currentFilters) && filter !== false ) {
1361
+ return;
1362
+ } else if ( filter === false ) {
1363
+ // force filter refresh
1364
+ c.lastCombinedFilter = '';
1365
+ c.lastSearch = [];
1366
+ }
1367
+ // define filter inside it is false
1368
+ filters = filters || [];
1369
+ // convert filters to strings - see #1070
1370
+ filters = Array.prototype.map ?
1371
+ filters.map( String ) :
1372
+ // for IE8 & older browsers - maybe not the best method
1373
+ filters.join( '\ufffd' ).split( '\ufffd' );
1374
+
1375
+ if ( wo.filter_initialized ) {
1376
+ c.$table.triggerHandler( 'filterStart', [ filters ] );
1377
+ }
1378
+ if ( c.showProcessing ) {
1379
+ // give it time for the processing icon to kick in
1380
+ setTimeout( function() {
1381
+ tsf.findRows( table, filters, currentFilters );
1382
+ return false;
1383
+ }, 30 );
1384
+ } else {
1385
+ tsf.findRows( table, filters, currentFilters );
1386
+ return false;
1387
+ }
1388
+ },
1389
+ hideFiltersCheck: function( c ) {
1390
+ if (typeof c.widgetOptions.filter_hideFilters === 'function') {
1391
+ var val = c.widgetOptions.filter_hideFilters( c );
1392
+ if (typeof val === 'boolean') {
1393
+ return val;
1394
+ }
1395
+ }
1396
+ return ts.getFilters( c.$table ).join( '' ) === '';
1397
+ },
1398
+ hideFilters: function( c, $table ) {
1399
+ var timer;
1400
+ ( $table || c.$table )
1401
+ .find( '.' + tscss.filterRow )
1402
+ .addClass( tscss.filterRowHide )
1403
+ .bind( 'mouseenter mouseleave', function( e ) {
1404
+ // save event object - http://bugs.jquery.com/ticket/12140
1405
+ var event = e,
1406
+ $row = $( this );
1407
+ clearTimeout( timer );
1408
+ timer = setTimeout( function() {
1409
+ if ( /enter|over/.test( event.type ) ) {
1410
+ $row.removeClass( tscss.filterRowHide );
1411
+ } else {
1412
+ // don't hide if input has focus
1413
+ // $( ':focus' ) needs jQuery 1.6+
1414
+ if ( $( document.activeElement ).closest( 'tr' )[0] !== $row[0] ) {
1415
+ // don't hide row if any filter has a value
1416
+ $row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) );
1417
+ }
1418
+ }
1419
+ }, 200 );
1420
+ })
1421
+ .find( 'input, select' ).bind( 'focus blur', function( e ) {
1422
+ var event = e,
1423
+ $row = $( this ).closest( 'tr' );
1424
+ clearTimeout( timer );
1425
+ timer = setTimeout( function() {
1426
+ clearTimeout( timer );
1427
+ // don't hide row if any filter has a value
1428
+ $row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) && event.type !== 'focus' );
1429
+ }, 200 );
1430
+ });
1431
+ },
1432
+ defaultFilter: function( filter, mask ) {
1433
+ if ( filter === '' ) { return filter; }
1434
+ var regex = tsfRegex.iQuery,
1435
+ maskLen = mask.match( tsfRegex.igQuery ).length,
1436
+ query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
1437
+ len = query.length - 1,
1438
+ indx = 0,
1439
+ val = mask;
1440
+ if ( len < 1 && maskLen > 1 ) {
1441
+ // only one 'word' in query but mask has >1 slots
1442
+ query[1] = query[0];
1443
+ }
1444
+ // replace all {query} with query words...
1445
+ // if query = 'Bob', then convert mask from '!{query}' to '!Bob'
1446
+ // if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank'
1447
+ while ( regex.test( val ) ) {
1448
+ val = val.replace( regex, query[indx++] || '' );
1449
+ if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
1450
+ val = mask.replace( regex, val );
1451
+ }
1452
+ }
1453
+ return val;
1454
+ },
1455
+ getLatestSearch: function( $input ) {
1456
+ if ( $input ) {
1457
+ return $input.sort( function( a, b ) {
1458
+ return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
1459
+ });
1460
+ }
1461
+ return $input || $();
1462
+ },
1463
+ findRange: function( c, val, ignoreRanges ) {
1464
+ // look for multiple columns '1-3,4-6,8' in data-column
1465
+ var temp, ranges, range, start, end, singles, i, indx, len,
1466
+ columns = [];
1467
+ if ( /^[0-9]+$/.test( val ) ) {
1468
+ // always return an array
1469
+ return [ parseInt( val, 10 ) ];
1470
+ }
1471
+ // process column range
1472
+ if ( !ignoreRanges && /-/.test( val ) ) {
1473
+ ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
1474
+ len = ranges ? ranges.length : 0;
1475
+ for ( indx = 0; indx < len; indx++ ) {
1476
+ range = ranges[indx].split( /\s*-\s*/ );
1477
+ start = parseInt( range[0], 10 ) || 0;
1478
+ end = parseInt( range[1], 10 ) || ( c.columns - 1 );
1479
+ if ( start > end ) {
1480
+ temp = start; start = end; end = temp; // swap
1481
+ }
1482
+ if ( end >= c.columns ) {
1483
+ end = c.columns - 1;
1484
+ }
1485
+ for ( ; start <= end; start++ ) {
1486
+ columns[ columns.length ] = start;
1487
+ }
1488
+ // remove processed range from val
1489
+ val = val.replace( ranges[ indx ], '' );
1490
+ }
1491
+ }
1492
+ // process single columns
1493
+ if ( !ignoreRanges && /,/.test( val ) ) {
1494
+ singles = val.split( /\s*,\s*/ );
1495
+ len = singles.length;
1496
+ for ( i = 0; i < len; i++ ) {
1497
+ if ( singles[ i ] !== '' ) {
1498
+ indx = parseInt( singles[ i ], 10 );
1499
+ if ( indx < c.columns ) {
1500
+ columns[ columns.length ] = indx;
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ // return all columns
1506
+ if ( !columns.length ) {
1507
+ for ( indx = 0; indx < c.columns; indx++ ) {
1508
+ columns[ columns.length ] = indx;
1509
+ }
1510
+ }
1511
+ return columns;
1512
+ },
1513
+ getColumnElm: function( c, $elements, column ) {
1514
+ // data-column may contain multiple columns '1-3,5-6,8'
1515
+ // replaces: c.$filters.filter( '[data-column="' + column + '"]' );
1516
+ return $elements.filter( function() {
1517
+ var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
1518
+ return $.inArray( column, cols ) > -1;
1519
+ });
1520
+ },
1521
+ multipleColumns: function( c, $input ) {
1522
+ // look for multiple columns '1-3,4-6,8' in data-column
1523
+ var wo = c.widgetOptions,
1524
+ // only target 'all' column inputs on initialization
1525
+ // & don't target 'all' column inputs if they don't exist
1526
+ targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
1527
+ val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
1528
+ return tsf.findRange( c, val, !targets );
1529
+ },
1530
+ processTypes: function( c, data, vars ) {
1531
+ var ffxn,
1532
+ filterMatched = null,
1533
+ matches = null;
1534
+ for ( ffxn in tsf.types ) {
1535
+ if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
1536
+ matches = tsf.types[ffxn]( c, data, vars );
1537
+ if ( matches !== null ) {
1538
+ data.matchedOn = ffxn;
1539
+ filterMatched = matches;
1540
+ }
1541
+ }
1542
+ }
1543
+ return filterMatched;
1544
+ },
1545
+ matchType: function( c, columnIndex ) {
1546
+ var isMatch,
1547
+ wo = c.widgetOptions,
1548
+ $el = c.$headerIndexed[ columnIndex ];
1549
+ // filter-exact > filter-match > filter_matchType for type
1550
+ if ( $el.hasClass( 'filter-exact' ) ) {
1551
+ isMatch = false;
1552
+ } else if ( $el.hasClass( 'filter-match' ) ) {
1553
+ isMatch = true;
1554
+ } else {
1555
+ // filter-select is not applied when filter_functions are used, so look for a select
1556
+ if ( wo.filter_columnFilters ) {
1557
+ $el = c.$filters
1558
+ .find( '.' + tscss.filter )
1559
+ .add( wo.filter_$externalFilters )
1560
+ .filter( '[data-column="' + columnIndex + '"]' );
1561
+ } else if ( wo.filter_$externalFilters ) {
1562
+ $el = wo.filter_$externalFilters.filter( '[data-column="' + columnIndex + '"]' );
1563
+ }
1564
+ isMatch = $el.length ?
1565
+ c.widgetOptions.filter_matchType[ ( $el[ 0 ].nodeName || '' ).toLowerCase() ] === 'match' :
1566
+ // default to exact, if no inputs found
1567
+ false;
1568
+ }
1569
+ return isMatch;
1570
+ },
1571
+ processRow: function( c, data, vars ) {
1572
+ var result, filterMatched,
1573
+ fxn, ffxn, txt,
1574
+ wo = c.widgetOptions,
1575
+ showRow = true,
1576
+ hasAnyMatchInput = wo.filter_$anyMatch && wo.filter_$anyMatch.length,
1577
+
1578
+ // if wo.filter_$anyMatch data-column attribute is changed dynamically
1579
+ // we don't want to do an "anyMatch" search on one column using data
1580
+ // for the entire row - see #998
1581
+ columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
1582
+ // look for multiple columns '1-3,4-6,8'
1583
+ tsf.multipleColumns( c, wo.filter_$anyMatch ) :
1584
+ [];
1585
+ data.$cells = data.$row.children();
1586
+ data.matchedOn = null;
1587
+ if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
1588
+ data.anyMatch = true;
1589
+ data.isMatch = true;
1590
+ data.rowArray = data.$cells.map( function( i ) {
1591
+ if ( $.inArray( i, columnIndex ) > -1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
1592
+ if ( data.parsed[ i ] ) {
1593
+ txt = data.cacheArray[ i ];
1594
+ } else {
1595
+ txt = data.rawArray[ i ];
1596
+ txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
1597
+ if ( c.sortLocaleCompare ) {
1598
+ txt = ts.replaceAccents( txt );
1599
+ }
1600
+ }
1601
+ return txt;
1602
+ }
1603
+ }).get();
1604
+ data.filter = data.anyMatchFilter;
1605
+ data.iFilter = data.iAnyMatchFilter;
1606
+ data.exact = data.rowArray.join( ' ' );
1607
+ data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
1608
+ data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
1609
+ vars.excludeMatch = vars.noAnyMatch;
1610
+ filterMatched = tsf.processTypes( c, data, vars );
1611
+ if ( filterMatched !== null ) {
1612
+ showRow = filterMatched;
1613
+ } else {
1614
+ if ( wo.filter_startsWith ) {
1615
+ showRow = false;
1616
+ // data.rowArray may not contain all columns
1617
+ columnIndex = Math.min( c.columns, data.rowArray.length );
1618
+ while ( !showRow && columnIndex > 0 ) {
1619
+ columnIndex--;
1620
+ showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
1621
+ }
1622
+ } else {
1623
+ showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
1624
+ }
1625
+ }
1626
+ data.anyMatch = false;
1627
+ // no other filters to process
1628
+ if ( data.filters.join( '' ) === data.filter ) {
1629
+ return showRow;
1630
+ }
1631
+ }
1632
+
1633
+ for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
1634
+ data.filter = data.filters[ columnIndex ];
1635
+ data.index = columnIndex;
1636
+
1637
+ // filter types to exclude, per column
1638
+ vars.excludeMatch = vars.excludeFilter[ columnIndex ];
1639
+
1640
+ // ignore if filter is empty or disabled
1641
+ if ( data.filter ) {
1642
+ data.cache = data.cacheArray[ columnIndex ];
1643
+ result = data.parsed[ columnIndex ] ? data.cache : data.rawArray[ columnIndex ] || '';
1644
+ data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
1645
+ data.iExact = !tsfRegex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
1646
+ data.exact.toLowerCase() : data.exact;
1647
+ data.isMatch = tsf.matchType( c, columnIndex );
1648
+
1649
+ result = showRow; // if showRow is true, show that row
1650
+
1651
+ // in case select filter option has a different value vs text 'a - z|A through Z'
1652
+ ffxn = wo.filter_columnFilters ?
1653
+ c.$filters.add( wo.filter_$externalFilters )
1654
+ .filter( '[data-column="' + columnIndex + '"]' )
1655
+ .find( 'select option:selected' )
1656
+ .attr( 'data-function-name' ) || '' : '';
1657
+ // replace accents - see #357
1658
+ if ( c.sortLocaleCompare ) {
1659
+ data.filter = ts.replaceAccents( data.filter );
1660
+ }
1661
+
1662
+ // replace column specific default filters - see #1088
1663
+ if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
1664
+ data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
1665
+ }
1666
+
1667
+ // data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
1668
+ // data.filter = case sensitive
1669
+ data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
1670
+ fxn = vars.functions[ columnIndex ];
1671
+ filterMatched = null;
1672
+ if ( fxn ) {
1673
+ if ( typeof fxn === 'function' ) {
1674
+ // filter callback( exact cell content, parser normalized content,
1675
+ // filter input value, column index, jQuery row object )
1676
+ filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
1677
+ } else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
1678
+ // selector option function
1679
+ txt = ffxn || data.filter;
1680
+ filterMatched =
1681
+ fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
1682
+ }
1683
+ }
1684
+ if ( filterMatched === null ) {
1685
+ // cycle through the different filters
1686
+ // filters return a boolean or null if nothing matches
1687
+ filterMatched = tsf.processTypes( c, data, vars );
1688
+ // select with exact match; ignore "and" or "or" within the text; fixes #1486
1689
+ txt = fxn === true && (data.matchedOn === 'and' || data.matchedOn === 'or');
1690
+ if ( filterMatched !== null && !txt) {
1691
+ result = filterMatched;
1692
+ // Look for match, and add child row data for matching
1693
+ } else {
1694
+ // check fxn (filter-select in header) after filter types are checked
1695
+ // without this, the filter + jQuery UI selectmenu demo was breaking
1696
+ if ( fxn === true ) {
1697
+ // default selector uses exact match unless 'filter-match' class is found
1698
+ result = data.isMatch ?
1699
+ // data.iExact may be a number
1700
+ ( '' + data.iExact ).search( data.iFilter ) >= 0 :
1701
+ data.filter === data.exact;
1702
+ } else {
1703
+ txt = ( data.iExact + data.childRowText ).indexOf( tsf.parseFilter( c, data.iFilter, data ) );
1704
+ result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
1705
+ }
1706
+ }
1707
+ } else {
1708
+ result = filterMatched;
1709
+ }
1710
+ showRow = ( result ) ? showRow : false;
1711
+ }
1712
+ }
1713
+ return showRow;
1714
+ },
1715
+ findRows: function( table, filters, currentFilters ) {
1716
+ if (
1717
+ tsf.equalFilters(table.config, table.config.lastSearch, currentFilters) ||
1718
+ !table.config.widgetOptions.filter_initialized
1719
+ ) {
1720
+ return;
1721
+ }
1722
+ var len, norm_rows, rowData, $rows, $row, rowIndex, tbodyIndex, $tbody, columnIndex,
1723
+ isChild, childRow, lastSearch, showRow, showParent, time, val, indx,
1724
+ notFiltered, searchFiltered, query, injected, res, id, txt,
1725
+ storedFilters = $.extend( [], filters ),
1726
+ c = table.config,
1727
+ wo = c.widgetOptions,
1728
+ debug = ts.debug(c, 'filter'),
1729
+ // data object passed to filters; anyMatch is a flag for the filters
1730
+ data = {
1731
+ anyMatch: false,
1732
+ filters: filters,
1733
+ // regex filter type cache
1734
+ filter_regexCache : []
1735
+ },
1736
+ vars = {
1737
+ // anyMatch really screws up with these types of filters
1738
+ noAnyMatch: [ 'range', 'operators' ],
1739
+ // cache filter variables that use ts.getColumnData in the main loop
1740
+ functions : [],
1741
+ excludeFilter : [],
1742
+ defaultColFilter : [],
1743
+ defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
1744
+ };
1745
+ // parse columns after formatter, in case the class is added at that point
1746
+ data.parsed = [];
1747
+ for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
1748
+ data.parsed[ columnIndex ] = wo.filter_useParsedData ||
1749
+ // parser has a "parsed" parameter
1750
+ ( c.parsers && c.parsers[ columnIndex ] && c.parsers[ columnIndex ].parsed ||
1751
+ // getData may not return 'parsed' if other 'filter-' class names exist
1752
+ // ( e.g. <th class="filter-select filter-parsed"> )
1753
+ ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
1754
+ ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
1755
+ c.$headerIndexed[ columnIndex ].hasClass( 'filter-parsed' ) );
1756
+
1757
+ vars.functions[ columnIndex ] =
1758
+ ts.getColumnData( table, wo.filter_functions, columnIndex ) ||
1759
+ c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
1760
+ vars.defaultColFilter[ columnIndex ] =
1761
+ ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
1762
+ vars.excludeFilter[ columnIndex ] =
1763
+ ( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
1764
+ }
1765
+
1766
+ if ( debug ) {
1767
+ console.log( 'Filter >> Starting filter widget search', filters );
1768
+ time = new Date();
1769
+ }
1770
+ // filtered rows count
1771
+ c.filteredRows = 0;
1772
+ c.totalRows = 0;
1773
+ currentFilters = ( storedFilters || [] );
1774
+
1775
+ for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
1776
+ $tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
1777
+ // skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
1778
+ // $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
1779
+ columnIndex = c.columns;
1780
+ // convert stored rows into a jQuery object
1781
+ norm_rows = c.cache[ tbodyIndex ].normalized;
1782
+ $rows = $( $.map( norm_rows, function( el ) {
1783
+ return el[ columnIndex ].$row.get();
1784
+ }) );
1785
+
1786
+ if ( currentFilters.join('') === '' || wo.filter_serversideFiltering ) {
1787
+ $rows
1788
+ .removeClass( wo.filter_filteredRow )
1789
+ .not( '.' + c.cssChildRow )
1790
+ .css( 'display', '' );
1791
+ } else {
1792
+ // filter out child rows
1793
+ $rows = $rows.not( '.' + c.cssChildRow );
1794
+ len = $rows.length;
1795
+
1796
+ if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
1797
+ typeof filters[c.columns] !== 'undefined' ) {
1798
+ data.anyMatchFlag = true;
1799
+ data.anyMatchFilter = '' + (
1800
+ filters[ c.columns ] ||
1801
+ wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
1802
+ ''
1803
+ );
1804
+ if ( wo.filter_columnAnyMatch ) {
1805
+ // specific columns search
1806
+ query = data.anyMatchFilter.split( tsfRegex.andSplit );
1807
+ injected = false;
1808
+ for ( indx = 0; indx < query.length; indx++ ) {
1809
+ res = query[ indx ].split( ':' );
1810
+ if ( res.length > 1 ) {
1811
+ // make the column a one-based index ( non-developers start counting from one :P )
1812
+ if ( isNaN( res[0] ) ) {
1813
+ $.each( c.headerContent, function( i, txt ) {
1814
+ // multiple matches are possible
1815
+ if ( txt.toLowerCase().indexOf( res[0] ) > -1 ) {
1816
+ id = i;
1817
+ filters[ id ] = res[1];
1818
+ }
1819
+ });
1820
+ } else {
1821
+ id = parseInt( res[0], 10 ) - 1;
1822
+ }
1823
+ if ( id >= 0 && id < c.columns ) { // if id is an integer
1824
+ filters[ id ] = res[1];
1825
+ query.splice( indx, 1 );
1826
+ indx--;
1827
+ injected = true;
1828
+ }
1829
+ }
1830
+ }
1831
+ if ( injected ) {
1832
+ data.anyMatchFilter = query.join( ' && ' );
1833
+ }
1834
+ }
1835
+ }
1836
+
1837
+ // optimize searching only through already filtered rows - see #313
1838
+ searchFiltered = wo.filter_searchFiltered;
1839
+ lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
1840
+ if ( searchFiltered ) {
1841
+ // cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
1842
+ for ( indx = 0; indx < columnIndex + 1; indx++ ) {
1843
+ val = filters[indx] || '';
1844
+ // break out of loop if we've already determined not to search filtered rows
1845
+ if ( !searchFiltered ) { indx = columnIndex; }
1846
+ // search already filtered rows if...
1847
+ searchFiltered = searchFiltered && lastSearch.length &&
1848
+ // there are no changes from beginning of filter
1849
+ val.indexOf( lastSearch[indx] || '' ) === 0 &&
1850
+ // if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
1851
+ !tsfRegex.alreadyFiltered.test( val ) &&
1852
+ // if we are not doing exact matches, using '|' ( logical or ) or not '!'
1853
+ !tsfRegex.exactTest.test( val ) &&
1854
+ // don't search only filtered if the value is negative
1855
+ // ( '> -10' => '> -100' will ignore hidden rows )
1856
+ !( tsfRegex.isNeg1.test( val ) || tsfRegex.isNeg2.test( val ) ) &&
1857
+ // if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
1858
+ !( val !== '' && c.$filters && c.$filters.filter( '[data-column="' + indx + '"]' ).find( 'select' ).length &&
1859
+ !tsf.matchType( c, indx ) );
1860
+ }
1861
+ }
1862
+ notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
1863
+ // can't search when all rows are hidden - this happens when looking for exact matches
1864
+ if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
1865
+ if ( debug ) {
1866
+ console.log( 'Filter >> Searching through ' +
1867
+ ( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
1868
+ }
1869
+ if ( data.anyMatchFlag ) {
1870
+ if ( c.sortLocaleCompare ) {
1871
+ // replace accents
1872
+ data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
1873
+ }
1874
+ if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultAnyFilter ) ) {
1875
+ data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
1876
+ // clear search filtered flag because default filters are not saved to the last search
1877
+ searchFiltered = false;
1878
+ }
1879
+ // make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
1880
+ // when c.ignoreCase is true, the cache contains all lower case data
1881
+ data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
1882
+ data.anyMatchFilter :
1883
+ data.anyMatchFilter.toLowerCase();
1884
+ }
1885
+
1886
+ // loop through the rows
1887
+ for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
1888
+
1889
+ txt = $rows[ rowIndex ].className;
1890
+ // the first row can never be a child row
1891
+ isChild = rowIndex && tsfRegex.child.test( txt );
1892
+ // skip child rows & already filtered rows
1893
+ if ( isChild || ( searchFiltered && tsfRegex.filtered.test( txt ) ) ) {
1894
+ continue;
1895
+ }
1896
+
1897
+ data.$row = $rows.eq( rowIndex );
1898
+ data.rowIndex = rowIndex;
1899
+ data.cacheArray = norm_rows[ rowIndex ];
1900
+ rowData = data.cacheArray[ c.columns ];
1901
+ data.rawArray = rowData.raw;
1902
+ data.childRowText = '';
1903
+
1904
+ if ( !wo.filter_childByColumn ) {
1905
+ txt = '';
1906
+ // child row cached text
1907
+ childRow = rowData.child;
1908
+ // so, if 'table.config.widgetOptions.filter_childRows' is true and there is
1909
+ // a match anywhere in the child row, then it will make the row visible
1910
+ // checked here so the option can be changed dynamically
1911
+ for ( indx = 0; indx < childRow.length; indx++ ) {
1912
+ txt += ' ' + childRow[indx].join( ' ' ) || '';
1913
+ }
1914
+ data.childRowText = wo.filter_childRows ?
1915
+ ( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
1916
+ '';
1917
+ }
1918
+
1919
+ showRow = false;
1920
+ showParent = tsf.processRow( c, data, vars );
1921
+ $row = rowData.$row;
1922
+
1923
+ // don't pass reference to val
1924
+ val = showParent ? true : false;
1925
+ childRow = rowData.$row.filter( ':gt(0)' );
1926
+ if ( wo.filter_childRows && childRow.length ) {
1927
+ if ( wo.filter_childByColumn ) {
1928
+ if ( !wo.filter_childWithSibs ) {
1929
+ // hide all child rows
1930
+ childRow.addClass( wo.filter_filteredRow );
1931
+ // if only showing resulting child row, only include parent
1932
+ $row = $row.eq( 0 );
1933
+ }
1934
+ // cycle through each child row
1935
+ for ( indx = 0; indx < childRow.length; indx++ ) {
1936
+ data.$row = childRow.eq( indx );
1937
+ data.cacheArray = rowData.child[ indx ];
1938
+ data.rawArray = data.cacheArray;
1939
+ val = tsf.processRow( c, data, vars );
1940
+ // use OR comparison on child rows
1941
+ showRow = showRow || val;
1942
+ if ( !wo.filter_childWithSibs && val ) {
1943
+ childRow.eq( indx ).removeClass( wo.filter_filteredRow );
1944
+ }
1945
+ }
1946
+ }
1947
+ // keep parent row match even if no child matches... see #1020
1948
+ showRow = showRow || showParent;
1949
+ } else {
1950
+ showRow = val;
1951
+ }
1952
+ $row
1953
+ .toggleClass( wo.filter_filteredRow, !showRow )[0]
1954
+ .display = showRow ? '' : 'none';
1955
+ }
1956
+ }
1957
+ c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
1958
+ c.totalRows += $rows.length;
1959
+ ts.processTbody( table, $tbody, false );
1960
+ }
1961
+ // lastCombinedFilter is no longer used internally
1962
+ c.lastCombinedFilter = storedFilters.join(''); // save last search
1963
+ // don't save 'filters' directly since it may have altered ( AnyMatch column searches )
1964
+ c.lastSearch = storedFilters;
1965
+ c.$table.data( 'lastSearch', storedFilters );
1966
+ if ( wo.filter_saveFilters && ts.storage ) {
1967
+ ts.storage( table, 'tablesorter-filters', tsf.processFilters( storedFilters, true ) );
1968
+ }
1969
+ if ( debug ) {
1970
+ console.log( 'Filter >> Completed search' + ts.benchmark(time) );
1971
+ }
1972
+ if ( wo.filter_initialized ) {
1973
+ c.$table.triggerHandler( 'filterBeforeEnd', c );
1974
+ c.$table.triggerHandler( 'filterEnd', c );
1975
+ }
1976
+ setTimeout( function() {
1977
+ ts.applyWidget( c.table ); // make sure zebra widget is applied
1978
+ }, 0 );
1979
+ },
1980
+ getOptionSource: function( table, column, onlyAvail ) {
1981
+ table = $( table )[0];
1982
+ var c = table.config,
1983
+ wo = c.widgetOptions,
1984
+ arry = false,
1985
+ source = wo.filter_selectSource,
1986
+ last = c.$table.data( 'lastSearch' ) || [],
1987
+ fxn = typeof source === 'function' ? true : ts.getColumnData( table, source, column );
1988
+
1989
+ if ( onlyAvail && last[column] !== '' ) {
1990
+ onlyAvail = false;
1991
+ }
1992
+
1993
+ // filter select source option
1994
+ if ( fxn === true ) {
1995
+ // OVERALL source
1996
+ arry = source( table, column, onlyAvail );
1997
+ } else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
1998
+ // selectSource is a jQuery object or string of options
1999
+ return fxn;
2000
+ } else if ( $.isArray( fxn ) ) {
2001
+ arry = fxn;
2002
+ } else if ( $.type( source ) === 'object' && fxn ) {
2003
+ // custom select source function for a SPECIFIC COLUMN
2004
+ arry = fxn( table, column, onlyAvail );
2005
+ // abort - updating the selects from an external method
2006
+ if (arry === null) {
2007
+ return null;
2008
+ }
2009
+ }
2010
+ if ( arry === false ) {
2011
+ // fall back to original method
2012
+ arry = tsf.getOptions( table, column, onlyAvail );
2013
+ }
2014
+
2015
+ return tsf.processOptions( table, column, arry );
2016
+
2017
+ },
2018
+ processOptions: function( table, column, arry ) {
2019
+ if ( !$.isArray( arry ) ) {
2020
+ return false;
2021
+ }
2022
+ table = $( table )[0];
2023
+ var cts, txt, indx, len, parsedTxt, str,
2024
+ c = table.config,
2025
+ validColumn = typeof column !== 'undefined' && column !== null && column >= 0 && column < c.columns,
2026
+ direction = validColumn ? c.$headerIndexed[ column ].hasClass( 'filter-select-sort-desc' ) : false,
2027
+ parsed = [];
2028
+ // get unique elements and sort the list
2029
+ // if $.tablesorter.sortText exists ( not in the original tablesorter ),
2030
+ // then natural sort the list otherwise use a basic sort
2031
+ arry = $.grep( arry, function( value, indx ) {
2032
+ if ( value.text ) {
2033
+ return true;
2034
+ }
2035
+ return $.inArray( value, arry ) === indx;
2036
+ });
2037
+ if ( validColumn && c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
2038
+ // unsorted select options
2039
+ return arry;
2040
+ } else {
2041
+ len = arry.length;
2042
+ // parse select option values
2043
+ for ( indx = 0; indx < len; indx++ ) {
2044
+ txt = arry[ indx ];
2045
+ // check for object
2046
+ str = txt.text ? txt.text : txt;
2047
+ // sortNatural breaks if you don't pass it strings
2048
+ parsedTxt = ( validColumn && c.parsers && c.parsers.length &&
2049
+ c.parsers[ column ].format( str, table, [], column ) || str ).toString();
2050
+ parsedTxt = c.widgetOptions.filter_ignoreCase ? parsedTxt.toLowerCase() : parsedTxt;
2051
+ // parse array data using set column parser; this DOES NOT pass the original
2052
+ // table cell to the parser format function
2053
+ if ( txt.text ) {
2054
+ txt.parsed = parsedTxt;
2055
+ parsed[ parsed.length ] = txt;
2056
+ } else {
2057
+ parsed[ parsed.length ] = {
2058
+ text : txt,
2059
+ // check parser length - fixes #934
2060
+ parsed : parsedTxt
2061
+ };
2062
+ }
2063
+ }
2064
+ // sort parsed select options
2065
+ cts = c.textSorter || '';
2066
+ parsed.sort( function( a, b ) {
2067
+ var x = direction ? b.parsed : a.parsed,
2068
+ y = direction ? a.parsed : b.parsed;
2069
+ if ( validColumn && typeof cts === 'function' ) {
2070
+ // custom OVERALL text sorter
2071
+ return cts( x, y, true, column, table );
2072
+ } else if ( validColumn && typeof cts === 'object' && cts.hasOwnProperty( column ) ) {
2073
+ // custom text sorter for a SPECIFIC COLUMN
2074
+ return cts[column]( x, y, true, column, table );
2075
+ } else if ( ts.sortNatural ) {
2076
+ // fall back to natural sort
2077
+ return ts.sortNatural( x, y );
2078
+ }
2079
+ // using an older version! do a basic sort
2080
+ return true;
2081
+ });
2082
+ // rebuild arry from sorted parsed data
2083
+ arry = [];
2084
+ len = parsed.length;
2085
+ for ( indx = 0; indx < len; indx++ ) {
2086
+ arry[ arry.length ] = parsed[indx];
2087
+ }
2088
+ return arry;
2089
+ }
2090
+ },
2091
+ getOptions: function( table, column, onlyAvail ) {
2092
+ table = $( table )[0];
2093
+ var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen,
2094
+ c = table.config,
2095
+ wo = c.widgetOptions,
2096
+ arry = [];
2097
+ for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
2098
+ cache = c.cache[tbodyIndex];
2099
+ len = c.cache[tbodyIndex].normalized.length;
2100
+ // loop through the rows
2101
+ for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
2102
+ // get cached row from cache.row ( old ) or row data object
2103
+ // ( new; last item in normalized array )
2104
+ row = cache.row ?
2105
+ cache.row[ rowIndex ] :
2106
+ cache.normalized[ rowIndex ][ c.columns ].$row[0];
2107
+ // check if has class filtered
2108
+ if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
2109
+ continue;
2110
+ }
2111
+ // get non-normalized cell content
2112
+ if ( wo.filter_useParsedData ||
2113
+ c.parsers[column].parsed ||
2114
+ c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
2115
+ arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ column ];
2116
+ // child row parsed data
2117
+ if ( wo.filter_childRows && wo.filter_childByColumn ) {
2118
+ childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length - 1;
2119
+ for ( indx = 0; indx < childLen; indx++ ) {
2120
+ arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ c.columns ].child[ indx ][ column ];
2121
+ }
2122
+ }
2123
+ } else {
2124
+ // get raw cached data instead of content directly from the cells
2125
+ arry[ arry.length ] = cache.normalized[ rowIndex ][ c.columns ].raw[ column ];
2126
+ // child row unparsed data
2127
+ if ( wo.filter_childRows && wo.filter_childByColumn ) {
2128
+ childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length;
2129
+ for ( indx = 1; indx < childLen; indx++ ) {
2130
+ child = cache.normalized[ rowIndex ][ c.columns ].$row.eq( indx ).children().eq( column );
2131
+ arry[ arry.length ] = '' + ts.getElementText( c, child, column );
2132
+ }
2133
+ }
2134
+ }
2135
+ }
2136
+ }
2137
+ return arry;
2138
+ },
2139
+ buildSelect: function( table, column, arry, updating, onlyAvail ) {
2140
+ table = $( table )[0];
2141
+ column = parseInt( column, 10 );
2142
+ if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
2143
+ return;
2144
+ }
2145
+
2146
+ var indx, val, txt, t, $filters, $filter, option,
2147
+ c = table.config,
2148
+ wo = c.widgetOptions,
2149
+ node = c.$headerIndexed[ column ],
2150
+ // t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
2151
+ options = '<option value="">' +
2152
+ ( node.data( 'placeholder' ) ||
2153
+ node.attr( 'data-placeholder' ) ||
2154
+ wo.filter_placeholder.select || ''
2155
+ ) + '</option>',
2156
+ // Get curent filter value
2157
+ currentValue = c.$table
2158
+ .find( 'thead' )
2159
+ .find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
2160
+ .val();
2161
+
2162
+ // nothing included in arry ( external source ), so get the options from
2163
+ // filter_selectSource or column data
2164
+ if ( typeof arry === 'undefined' || arry === '' ) {
2165
+ arry = tsf.getOptionSource( table, column, onlyAvail );
2166
+ // abort, selects are updated by an external method
2167
+ if (arry === null) {
2168
+ return;
2169
+ }
2170
+ }
2171
+
2172
+ if ( $.isArray( arry ) ) {
2173
+ // build option list
2174
+ for ( indx = 0; indx < arry.length; indx++ ) {
2175
+ option = arry[ indx ];
2176
+ if ( option.text ) {
2177
+ // OBJECT!! add data-function-name in case the value is set in filter_functions
2178
+ option['data-function-name'] = typeof option.value === 'undefined' ? option.text : option.value;
2179
+
2180
+ // support jQuery < v1.8, otherwise the below code could be shortened to
2181
+ // options += $( '<option>', option )[ 0 ].outerHTML;
2182
+ options += '<option';
2183
+ for ( val in option ) {
2184
+ if ( option.hasOwnProperty( val ) && val !== 'text' ) {
2185
+ options += ' ' + val + '="' + option[ val ].replace( tsfRegex.quote, '&quot;' ) + '"';
2186
+ }
2187
+ }
2188
+ if ( !option.value ) {
2189
+ options += ' value="' + option.text.replace( tsfRegex.quote, '&quot;' ) + '"';
2190
+ }
2191
+ options += '>' + option.text.replace( tsfRegex.quote, '&quot;' ) + '</option>';
2192
+ // above code is needed in jQuery < v1.8
2193
+
2194
+ // make sure we don't turn an object into a string (objects without a "text" property)
2195
+ } else if ( '' + option !== '[object Object]' ) {
2196
+ txt = option = ( '' + option ).replace( tsfRegex.quote, '&quot;' );
2197
+ val = txt;
2198
+ // allow including a symbol in the selectSource array
2199
+ // 'a-z|A through Z' so that 'a-z' becomes the option value
2200
+ // and 'A through Z' becomes the option text
2201
+ if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
2202
+ t = txt.split( wo.filter_selectSourceSeparator );
2203
+ val = t[0];
2204
+ txt = t[1];
2205
+ }
2206
+ // replace quotes - fixes #242 & ignore empty strings
2207
+ // see http://stackoverflow.com/q/14990971/145346
2208
+ options += option !== '' ?
2209
+ '<option ' +
2210
+ ( val === txt ? '' : 'data-function-name="' + option + '" ' ) +
2211
+ 'value="' + val + '">' + txt +
2212
+ '</option>' : '';
2213
+ }
2214
+ }
2215
+ // clear arry so it doesn't get appended twice
2216
+ arry = [];
2217
+ }
2218
+
2219
+ // update all selects in the same column ( clone thead in sticky headers &
2220
+ // any external selects ) - fixes 473
2221
+ $filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
2222
+ .find( '.' + tscss.filter );
2223
+ if ( wo.filter_$externalFilters ) {
2224
+ $filters = $filters && $filters.length ?
2225
+ $filters.add( wo.filter_$externalFilters ) :
2226
+ wo.filter_$externalFilters;
2227
+ }
2228
+ $filter = $filters.filter( 'select[data-column="' + column + '"]' );
2229
+
2230
+ // make sure there is a select there!
2231
+ if ( $filter.length ) {
2232
+ $filter[ updating ? 'html' : 'append' ]( options );
2233
+ if ( !$.isArray( arry ) ) {
2234
+ // append options if arry is provided externally as a string or jQuery object
2235
+ // options ( default value ) was already added
2236
+ $filter.append( arry ).val( currentValue );
2237
+ }
2238
+ $filter.val( currentValue );
2239
+ }
2240
+ },
2241
+ buildDefault: function( table, updating ) {
2242
+ var columnIndex, $header, noSelect,
2243
+ c = table.config,
2244
+ wo = c.widgetOptions,
2245
+ columns = c.columns;
2246
+ // build default select dropdown
2247
+ for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
2248
+ $header = c.$headerIndexed[columnIndex];
2249
+ noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
2250
+ // look for the filter-select class; build/update it if found
2251
+ if ( ( $header.hasClass( 'filter-select' ) ||
2252
+ ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
2253
+ tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
2254
+ }
2255
+ }
2256
+ }
2257
+ };
2258
+
2259
+ // filter regex variable
2260
+ tsfRegex = tsf.regex;
2261
+
2262
+ ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
2263
+ var i, $filters, $column, cols,
2264
+ filters = [],
2265
+ c = table ? $( table )[0].config : '',
2266
+ wo = c ? c.widgetOptions : '';
2267
+ if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
2268
+ // setFilters called, but last search is exactly the same as the current
2269
+ // fixes issue #733 & #903 where calling update causes the input values to reset
2270
+ ( $.isArray(setFilters) && tsf.equalFilters(c, setFilters, c.lastSearch) )
2271
+ ) {
2272
+ return $( table ).data( 'lastSearch' ) || [];
2273
+ }
2274
+ if ( c ) {
2275
+ if ( c.$filters ) {
2276
+ $filters = c.$filters.find( '.' + tscss.filter );
2277
+ }
2278
+ if ( wo.filter_$externalFilters ) {
2279
+ $filters = $filters && $filters.length ?
2280
+ $filters.add( wo.filter_$externalFilters ) :
2281
+ wo.filter_$externalFilters;
2282
+ }
2283
+ if ( $filters && $filters.length ) {
2284
+ filters = setFilters || [];
2285
+ for ( i = 0; i < c.columns + 1; i++ ) {
2286
+ cols = ( i === c.columns ?
2287
+ // 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
2288
+ wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
2289
+ '[data-column="' + i + '"]' );
2290
+ $column = $filters.filter( cols );
2291
+ if ( $column.length ) {
2292
+ // move the latest search to the first slot in the array
2293
+ $column = tsf.getLatestSearch( $column );
2294
+ if ( $.isArray( setFilters ) ) {
2295
+ // skip first ( latest input ) to maintain cursor position while typing
2296
+ if ( skipFirst && $column.length > 1 ) {
2297
+ $column = $column.slice( 1 );
2298
+ }
2299
+ if ( i === c.columns ) {
2300
+ // prevent data-column='all' from filling data-column='0,1' ( etc )
2301
+ cols = $column.filter( wo.filter_anyColumnSelector );
2302
+ $column = cols.length ? cols : $column;
2303
+ }
2304
+ $column
2305
+ .val( setFilters[ i ] )
2306
+ // must include a namespace here; but not c.namespace + 'filter'?
2307
+ .trigger( 'change' + c.namespace );
2308
+ } else {
2309
+ filters[i] = $column.val() || '';
2310
+ // don't change the first... it will move the cursor
2311
+ if ( i === c.columns ) {
2312
+ // don't update range columns from 'all' setting
2313
+ $column
2314
+ .slice( 1 )
2315
+ .filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
2316
+ .val( filters[ i ] );
2317
+ } else {
2318
+ $column
2319
+ .slice( 1 )
2320
+ .val( filters[ i ] );
2321
+ }
2322
+ }
2323
+ // save any match input dynamically
2324
+ if ( i === c.columns && $column.length ) {
2325
+ wo.filter_$anyMatch = $column;
2326
+ }
2327
+ }
2328
+ }
2329
+ }
2330
+ }
2331
+ return filters;
2332
+ };
2333
+
2334
+ ts.setFilters = function( table, filter, apply, skipFirst ) {
2335
+ var c = table ? $( table )[0].config : '',
2336
+ valid = ts.getFilters( table, true, filter, skipFirst );
2337
+ // default apply to "true"
2338
+ if ( typeof apply === 'undefined' ) {
2339
+ apply = true;
2340
+ }
2341
+ if ( c && apply ) {
2342
+ // ensure new set filters are applied, even if the search is the same
2343
+ c.lastCombinedFilter = null;
2344
+ c.lastSearch = [];
2345
+ tsf.searching( c.table, filter, skipFirst );
2346
+ c.$table.triggerHandler( 'filterFomatterUpdate' );
2347
+ }
2348
+ return valid.length !== 0;
2349
+ };
2350
+
2351
+ })( jQuery );
2352
+
2353
+ /*! Widget: stickyHeaders - updated 9/27/2017 (v2.29.0) *//*
2354
+ * Requires tablesorter v2.8+ and jQuery 1.4.3+
2355
+ * by Rob Garrison
2356
+ */
2357
+ ;(function ($, window) {
2358
+ 'use strict';
2359
+ var ts = $.tablesorter || {};
2360
+
2361
+ $.extend(ts.css, {
2362
+ sticky : 'tablesorter-stickyHeader', // stickyHeader
2363
+ stickyVis : 'tablesorter-sticky-visible',
2364
+ stickyHide: 'tablesorter-sticky-hidden',
2365
+ stickyWrap: 'tablesorter-sticky-wrapper'
2366
+ });
2367
+
2368
+ // Add a resize event to table headers
2369
+ ts.addHeaderResizeEvent = function(table, disable, settings) {
2370
+ table = $(table)[0]; // make sure we're using a dom element
2371
+ if ( !table.config ) { return; }
2372
+ var defaults = {
2373
+ timer : 250
2374
+ },
2375
+ options = $.extend({}, defaults, settings),
2376
+ c = table.config,
2377
+ wo = c.widgetOptions,
2378
+ checkSizes = function( triggerEvent ) {
2379
+ var index, headers, $header, sizes, width, height,
2380
+ len = c.$headers.length;
2381
+ wo.resize_flag = true;
2382
+ headers = [];
2383
+ for ( index = 0; index < len; index++ ) {
2384
+ $header = c.$headers.eq( index );
2385
+ sizes = $header.data( 'savedSizes' ) || [ 0, 0 ]; // fixes #394
2386
+ width = $header[0].offsetWidth;
2387
+ height = $header[0].offsetHeight;
2388
+ if ( width !== sizes[0] || height !== sizes[1] ) {
2389
+ $header.data( 'savedSizes', [ width, height ] );
2390
+ headers.push( $header[0] );
2391
+ }
2392
+ }
2393
+ if ( headers.length && triggerEvent !== false ) {
2394
+ c.$table.triggerHandler( 'resize', [ headers ] );
2395
+ }
2396
+ wo.resize_flag = false;
2397
+ };
2398
+ clearInterval(wo.resize_timer);
2399
+ if (disable) {
2400
+ wo.resize_flag = false;
2401
+ return false;
2402
+ }
2403
+ checkSizes( false );
2404
+ wo.resize_timer = setInterval(function() {
2405
+ if (wo.resize_flag) { return; }
2406
+ checkSizes();
2407
+ }, options.timer);
2408
+ };
2409
+
2410
+ function getStickyOffset(c, wo) {
2411
+ var $el = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : [];
2412
+ return $el.length ?
2413
+ $el.height() || 0 :
2414
+ parseInt(wo.stickyHeaders_offset, 10) || 0;
2415
+ }
2416
+
2417
+ // Sticky headers based on this awesome article:
2418
+ // http://css-tricks.com/13465-persistent-headers/
2419
+ // and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
2420
+ // **************************
2421
+ ts.addWidget({
2422
+ id: 'stickyHeaders',
2423
+ priority: 54, // sticky widget must be initialized after the filter & before pager widget!
2424
+ options: {
2425
+ stickyHeaders : '', // extra class name added to the sticky header row
2426
+ stickyHeaders_appendTo : null, // jQuery selector or object to phycially attach the sticky headers
2427
+ stickyHeaders_attachTo : null, // jQuery selector or object to attach scroll listener to (overridden by xScroll & yScroll settings)
2428
+ stickyHeaders_xScroll : null, // jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
2429
+ stickyHeaders_yScroll : null, // jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
2430
+ stickyHeaders_offset : 0, // number or jquery selector targeting the position:fixed element
2431
+ stickyHeaders_filteredToTop: true, // scroll table top into view after filtering
2432
+ stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
2433
+ stickyHeaders_addResizeEvent : true, // trigger 'resize' event on headers
2434
+ stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
2435
+ stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
2436
+ },
2437
+ format: function(table, c, wo) {
2438
+ // filter widget doesn't initialize on an empty table. Fixes #449
2439
+ if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
2440
+ return;
2441
+ }
2442
+ var index, len, $t,
2443
+ $table = c.$table,
2444
+ // add position: relative to attach element, hopefully it won't cause trouble.
2445
+ $attach = $(wo.stickyHeaders_attachTo || wo.stickyHeaders_appendTo),
2446
+ namespace = c.namespace + 'stickyheaders ',
2447
+ // element to watch for the scroll event
2448
+ $yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
2449
+ $xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
2450
+ $thead = $table.children('thead:first'),
2451
+ $header = $thead.children('tr').not('.sticky-false').children(),
2452
+ $tfoot = $table.children('tfoot'),
2453
+ stickyOffset = getStickyOffset(c, wo),
2454
+ // is this table nested? If so, find parent sticky header wrapper (div, not table)
2455
+ $nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
2456
+ $table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
2457
+ nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
2458
+ // clone table, then wrap to make sticky header
2459
+ $stickyTable = wo.$sticky = $table.clone()
2460
+ .addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' )
2461
+ .wrap('<div class="' + ts.css.stickyWrap + '">'),
2462
+ $stickyWrap = $stickyTable.parent()
2463
+ .addClass(ts.css.stickyHide)
2464
+ .css({
2465
+ position : $attach.length ? 'absolute' : 'fixed',
2466
+ padding : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
2467
+ top : stickyOffset + nestedStickyTop,
2468
+ left : 0,
2469
+ visibility : 'hidden',
2470
+ zIndex : wo.stickyHeaders_zIndex || 2
2471
+ }),
2472
+ $stickyThead = $stickyTable.children('thead:first'),
2473
+ $stickyCells,
2474
+ laststate = '',
2475
+ setWidth = function($orig, $clone) {
2476
+ var index, width, border, $cell, $this,
2477
+ $cells = $orig.filter(':visible'),
2478
+ len = $cells.length;
2479
+ for ( index = 0; index < len; index++ ) {
2480
+ $cell = $clone.filter(':visible').eq(index);
2481
+ $this = $cells.eq(index);
2482
+ // code from https://github.com/jmosbech/StickyTableHeaders
2483
+ if ($this.css('box-sizing') === 'border-box') {
2484
+ width = $this.outerWidth();
2485
+ } else {
2486
+ if ($cell.css('border-collapse') === 'collapse') {
2487
+ if (window.getComputedStyle) {
2488
+ width = parseFloat( window.getComputedStyle($this[0], null).width );
2489
+ } else {
2490
+ // ie8 only
2491
+ border = parseFloat( $this.css('border-width') );
2492
+ width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
2493
+ }
2494
+ } else {
2495
+ width = $this.width();
2496
+ }
2497
+ }
2498
+ $cell.css({
2499
+ 'width': width,
2500
+ 'min-width': width,
2501
+ 'max-width': width
2502
+ });
2503
+ }
2504
+ },
2505
+ getLeftPosition = function(yWindow) {
2506
+ if (yWindow === false && $nestedSticky.length) {
2507
+ return $table.position().left;
2508
+ }
2509
+ return $attach.length ?
2510
+ parseInt($attach.css('padding-left'), 10) || 0 :
2511
+ $table.offset().left - parseInt($table.css('margin-left'), 10) - $(window).scrollLeft();
2512
+ },
2513
+ resizeHeader = function() {
2514
+ $stickyWrap.css({
2515
+ left : getLeftPosition(),
2516
+ width: $table.outerWidth()
2517
+ });
2518
+ setWidth( $table, $stickyTable );
2519
+ setWidth( $header, $stickyCells );
2520
+ },
2521
+ scrollSticky = function( resizing ) {
2522
+ if (!$table.is(':visible')) { return; } // fixes #278
2523
+ // Detect nested tables - fixes #724
2524
+ nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
2525
+ var tmp,
2526
+ offset = $table.offset(),
2527
+ stickyOffset = getStickyOffset(c, wo),
2528
+ yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
2529
+ yScroll = yWindow ?
2530
+ $yScroll.scrollTop() :
2531
+ // use parent sticky position if nested AND inside of a scrollable element - see #1512
2532
+ $nestedSticky.length ? parseInt($nestedSticky[0].style.top, 10) : $yScroll.offset().top,
2533
+ attachTop = $attach.length ? yScroll : $yScroll.scrollTop(),
2534
+ captionHeight = wo.stickyHeaders_includeCaption ? 0 : $table.children( 'caption' ).height() || 0,
2535
+ scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
2536
+ tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
2537
+ isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
2538
+ state = isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide,
2539
+ needsUpdating = !$stickyWrap.hasClass( state ),
2540
+ cssSettings = { visibility : isVisible };
2541
+ if ($attach.length) {
2542
+ // attached sticky headers always need updating
2543
+ needsUpdating = true;
2544
+ cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
2545
+ }
2546
+ // adjust when scrolling horizontally - fixes issue #143
2547
+ tmp = getLeftPosition(yWindow);
2548
+ if (tmp !== parseInt($stickyWrap.css('left'), 10)) {
2549
+ needsUpdating = true;
2550
+ cssSettings.left = tmp;
2551
+ }
2552
+ cssSettings.top = ( cssSettings.top || 0 ) +
2553
+ // If nested AND inside of a scrollable element, only add parent sticky height
2554
+ (!yWindow && $nestedSticky.length ? $nestedSticky.height() : stickyOffset + nestedStickyTop);
2555
+ if (needsUpdating) {
2556
+ $stickyWrap
2557
+ .removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
2558
+ .addClass( state )
2559
+ .css(cssSettings);
2560
+ }
2561
+ if (isVisible !== laststate || resizing) {
2562
+ // make sure the column widths match
2563
+ resizeHeader();
2564
+ laststate = isVisible;
2565
+ }
2566
+ };
2567
+ // only add a position relative if a position isn't already defined
2568
+ if ($attach.length && !$attach.css('position')) {
2569
+ $attach.css('position', 'relative');
2570
+ }
2571
+ // fix clone ID, if it exists - fixes #271
2572
+ if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.stickyHeaders_cloneId; }
2573
+ // clear out cloned table, except for sticky header
2574
+ // include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
2575
+ $stickyTable.find('> thead:gt(0), tr.sticky-false').hide();
2576
+ $stickyTable.find('> tbody, > tfoot').remove();
2577
+ $stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
2578
+ // issue #172 - find td/th in sticky header
2579
+ $stickyCells = $stickyThead.children().children();
2580
+ $stickyTable.css({ height:0, width:0, margin: 0 });
2581
+ // remove resizable block
2582
+ $stickyCells.find('.' + ts.css.resizer).remove();
2583
+ // update sticky header class names to match real header after sorting
2584
+ $table
2585
+ .addClass('hasStickyHeaders')
2586
+ .bind('pagerComplete' + namespace, function() {
2587
+ resizeHeader();
2588
+ });
2589
+
2590
+ ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header));
2591
+
2592
+ if (wo.stickyHeaders_appendTo) {
2593
+ $(wo.stickyHeaders_appendTo).append( $stickyWrap );
2594
+ } else {
2595
+ // add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
2596
+ $table.after( $stickyWrap );
2597
+ }
2598
+
2599
+ // onRenderHeader is defined, we need to do something about it (fixes #641)
2600
+ if (c.onRenderHeader) {
2601
+ $t = $stickyThead.children('tr').children();
2602
+ len = $t.length;
2603
+ for ( index = 0; index < len; index++ ) {
2604
+ // send second parameter
2605
+ c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
2606
+ }
2607
+ }
2608
+ // make it sticky!
2609
+ $xScroll.add($yScroll)
2610
+ .unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
2611
+ .bind('scroll resize '.split(' ').join( namespace ), function( event ) {
2612
+ scrollSticky( event.type === 'resize' );
2613
+ });
2614
+ c.$table
2615
+ .unbind('stickyHeadersUpdate' + namespace)
2616
+ .bind('stickyHeadersUpdate' + namespace, function() {
2617
+ scrollSticky( true );
2618
+ });
2619
+
2620
+ if (wo.stickyHeaders_addResizeEvent) {
2621
+ ts.addHeaderResizeEvent(table);
2622
+ }
2623
+
2624
+ // look for filter widget
2625
+ if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
2626
+ // scroll table into view after filtering, if sticky header is active - #482
2627
+ $table.bind('filterEnd' + namespace, function() {
2628
+ // $(':focus') needs jQuery 1.6+
2629
+ var $td = $(document.activeElement).closest('td'),
2630
+ column = $td.parent().children().index($td);
2631
+ // only scroll if sticky header is active
2632
+ if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
2633
+ // scroll to original table (not sticky clone)
2634
+ window.scrollTo(0, $table.position().top);
2635
+ // give same input/select focus; check if c.$filters exists; fixes #594
2636
+ if (column >= 0 && c.$filters) {
2637
+ c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
2638
+ }
2639
+ }
2640
+ });
2641
+ ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
2642
+ // support hideFilters
2643
+ if (wo.filter_hideFilters) {
2644
+ ts.filter.hideFilters(c, $stickyTable);
2645
+ }
2646
+ }
2647
+
2648
+ // resize table (Firefox)
2649
+ if (wo.stickyHeaders_addResizeEvent) {
2650
+ $table.bind('resize' + c.namespace + 'stickyheaders', function() {
2651
+ resizeHeader();
2652
+ });
2653
+ }
2654
+
2655
+ // make sure sticky is visible if page is partially scrolled
2656
+ scrollSticky( true );
2657
+ $table.triggerHandler('stickyHeadersInit');
2658
+
2659
+ },
2660
+ remove: function(table, c, wo) {
2661
+ var namespace = c.namespace + 'stickyheaders ';
2662
+ c.$table
2663
+ .removeClass('hasStickyHeaders')
2664
+ .unbind( ('pagerComplete resize filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
2665
+ .next('.' + ts.css.stickyWrap).remove();
2666
+ if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
2667
+ $(window)
2668
+ .add(wo.stickyHeaders_xScroll)
2669
+ .add(wo.stickyHeaders_yScroll)
2670
+ .add(wo.stickyHeaders_attachTo)
2671
+ .unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
2672
+ ts.addHeaderResizeEvent(table, true);
2673
+ }
2674
+ });
2675
+
2676
+ })(jQuery, window);
2677
+
2678
+ /*! Widget: resizable - updated 2018-03-26 (v2.30.2) */
2679
+ /*jshint browser:true, jquery:true, unused:false */
2680
+ ;(function ($, window) {
2681
+ 'use strict';
2682
+ var ts = $.tablesorter || {};
2683
+
2684
+ $.extend(ts.css, {
2685
+ resizableContainer : 'tablesorter-resizable-container',
2686
+ resizableHandle : 'tablesorter-resizable-handle',
2687
+ resizableNoSelect : 'tablesorter-disableSelection',
2688
+ resizableStorage : 'tablesorter-resizable'
2689
+ });
2690
+
2691
+ // Add extra scroller css
2692
+ $(function() {
2693
+ var s = '<style>' +
2694
+ 'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
2695
+ '-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
2696
+ '.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
2697
+ // make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
2698
+ '.' + ts.css.resizableHandle + ' { position: absolute; display: inline-block; width: 8px;' +
2699
+ 'top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }' +
2700
+ '</style>';
2701
+ $('head').append(s);
2702
+ });
2703
+
2704
+ ts.resizable = {
2705
+ init : function( c, wo ) {
2706
+ if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
2707
+ c.$table.addClass( 'hasResizable' );
2708
+
2709
+ var noResize, $header, column, storedSizes, tmp,
2710
+ $table = c.$table,
2711
+ $parent = $table.parent(),
2712
+ marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
2713
+
2714
+ // internal variables
2715
+ vars = wo.resizable_vars = {
2716
+ useStorage : ts.storage && wo.resizable !== false,
2717
+ $wrap : $parent,
2718
+ mouseXPosition : 0,
2719
+ $target : null,
2720
+ $next : null,
2721
+ overflow : $parent.css('overflow') === 'auto' ||
2722
+ $parent.css('overflow') === 'scroll' ||
2723
+ $parent.css('overflow-x') === 'auto' ||
2724
+ $parent.css('overflow-x') === 'scroll',
2725
+ storedSizes : []
2726
+ };
2727
+
2728
+ // set default widths
2729
+ ts.resizableReset( c.table, true );
2730
+
2731
+ // now get measurements!
2732
+ vars.tableWidth = $table.width();
2733
+ // attempt to autodetect
2734
+ vars.fullWidth = Math.abs( $parent.width() - vars.tableWidth ) < 20;
2735
+
2736
+ /*
2737
+ // Hacky method to determine if table width is set to 'auto'
2738
+ // http://stackoverflow.com/a/20892048/145346
2739
+ if ( !vars.fullWidth ) {
2740
+ tmp = $table.width();
2741
+ $header = $table.wrap('<span>').parent(); // temp variable
2742
+ storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
2743
+ $table.css( 'margin-left', storedSizes + 50 );
2744
+ vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
2745
+ $table.css( 'margin-left', storedSizes ? storedSizes : '' );
2746
+ $header = null;
2747
+ $table.unwrap('<span>');
2748
+ }
2749
+ */
2750
+
2751
+ if ( vars.useStorage && vars.overflow ) {
2752
+ // save table width
2753
+ ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
2754
+ tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
2755
+ ts.resizable.setWidth( $table, tmp, true );
2756
+ }
2757
+ wo.resizable_vars.storedSizes = storedSizes = ( vars.useStorage ?
2758
+ ts.storage( c.table, ts.css.resizableStorage ) :
2759
+ [] ) || [];
2760
+ ts.resizable.setWidths( c, wo, storedSizes );
2761
+ ts.resizable.updateStoredSizes( c, wo );
2762
+
2763
+ wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
2764
+ .css({ top : marginTop })
2765
+ .insertBefore( $table );
2766
+ // add container
2767
+ for ( column = 0; column < c.columns; column++ ) {
2768
+ $header = c.$headerIndexed[ column ];
2769
+ tmp = ts.getColumnData( c.table, c.headers, column );
2770
+ noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
2771
+ if ( !noResize ) {
2772
+ $( '<div class="' + ts.css.resizableHandle + '">' )
2773
+ .appendTo( wo.$resizable_container )
2774
+ .attr({
2775
+ 'data-column' : column,
2776
+ 'unselectable' : 'on'
2777
+ })
2778
+ .data( 'header', $header )
2779
+ .bind( 'selectstart', false );
2780
+ }
2781
+ }
2782
+ ts.resizable.bindings( c, wo );
2783
+ },
2784
+
2785
+ updateStoredSizes : function( c, wo ) {
2786
+ var column, $header,
2787
+ len = c.columns,
2788
+ vars = wo.resizable_vars;
2789
+ vars.storedSizes = [];
2790
+ for ( column = 0; column < len; column++ ) {
2791
+ $header = c.$headerIndexed[ column ];
2792
+ vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
2793
+ }
2794
+ },
2795
+
2796
+ setWidth : function( $el, width, overflow ) {
2797
+ // overflow tables need min & max width set as well
2798
+ $el.css({
2799
+ 'width' : width,
2800
+ 'min-width' : overflow ? width : '',
2801
+ 'max-width' : overflow ? width : ''
2802
+ });
2803
+ },
2804
+
2805
+ setWidths : function( c, wo, storedSizes ) {
2806
+ var column, $temp,
2807
+ vars = wo.resizable_vars,
2808
+ $extra = $( c.namespace + '_extra_headers' ),
2809
+ $col = c.$table.children( 'colgroup' ).children( 'col' );
2810
+ storedSizes = storedSizes || vars.storedSizes || [];
2811
+ // process only if table ID or url match
2812
+ if ( storedSizes.length ) {
2813
+ for ( column = 0; column < c.columns; column++ ) {
2814
+ // set saved resizable widths
2815
+ ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
2816
+ if ( $extra.length ) {
2817
+ // stickyHeaders needs to modify min & max width as well
2818
+ $temp = $extra.eq( column ).add( $col.eq( column ) );
2819
+ ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
2820
+ }
2821
+ }
2822
+ $temp = $( c.namespace + '_extra_table' );
2823
+ if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
2824
+ ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
2825
+ }
2826
+ }
2827
+ },
2828
+
2829
+ setHandlePosition : function( c, wo ) {
2830
+ var startPosition,
2831
+ tableHeight = c.$table.height(),
2832
+ $handles = wo.$resizable_container.children(),
2833
+ handleCenter = Math.floor( $handles.width() / 2 );
2834
+
2835
+ if ( ts.hasWidget( c.table, 'scroller' ) ) {
2836
+ tableHeight = 0;
2837
+ c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function() {
2838
+ var $this = $(this);
2839
+ // center table has a max-height set
2840
+ tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
2841
+ });
2842
+ }
2843
+
2844
+ if ( !wo.resizable_includeFooter && c.$table.children('tfoot').length ) {
2845
+ tableHeight -= c.$table.children('tfoot').height();
2846
+ }
2847
+ // subtract out table left position from resizable handles. Fixes #864
2848
+ // jQuery v3.3.0+ appears to include the start position with the $header.position().left; see #1544
2849
+ startPosition = parseFloat($.fn.jquery) >= 3.3 ? 0 : c.$table.position().left;
2850
+ $handles.each( function() {
2851
+ var $this = $(this),
2852
+ column = parseInt( $this.attr( 'data-column' ), 10 ),
2853
+ columns = c.columns - 1,
2854
+ $header = $this.data( 'header' );
2855
+ if ( !$header ) { return; } // see #859
2856
+ if (
2857
+ !$header.is(':visible') ||
2858
+ ( !wo.resizable_addLastColumn && ts.resizable.checkVisibleColumns(c, column) )
2859
+ ) {
2860
+ $this.hide();
2861
+ } else if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
2862
+ $this.css({
2863
+ display: 'inline-block',
2864
+ height : tableHeight,
2865
+ left : $header.position().left - startPosition + $header.outerWidth() - handleCenter
2866
+ });
2867
+ }
2868
+ });
2869
+ },
2870
+
2871
+ // Fixes #1485
2872
+ checkVisibleColumns: function( c, column ) {
2873
+ var i,
2874
+ len = 0;
2875
+ for ( i = column + 1; i < c.columns; i++ ) {
2876
+ len += c.$headerIndexed[i].is( ':visible' ) ? 1 : 0;
2877
+ }
2878
+ return len === 0;
2879
+ },
2880
+
2881
+ // prevent text selection while dragging resize bar
2882
+ toggleTextSelection : function( c, wo, toggle ) {
2883
+ var namespace = c.namespace + 'tsresize';
2884
+ wo.resizable_vars.disabled = toggle;
2885
+ $( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
2886
+ if ( toggle ) {
2887
+ $( 'body' )
2888
+ .attr( 'unselectable', 'on' )
2889
+ .bind( 'selectstart' + namespace, false );
2890
+ } else {
2891
+ $( 'body' )
2892
+ .removeAttr( 'unselectable' )
2893
+ .unbind( 'selectstart' + namespace );
2894
+ }
2895
+ },
2896
+
2897
+ bindings : function( c, wo ) {
2898
+ var namespace = c.namespace + 'tsresize';
2899
+ wo.$resizable_container.children().bind( 'mousedown', function( event ) {
2900
+ // save header cell and mouse position
2901
+ var column,
2902
+ vars = wo.resizable_vars,
2903
+ $extras = $( c.namespace + '_extra_headers' ),
2904
+ $header = $( event.target ).data( 'header' );
2905
+
2906
+ column = parseInt( $header.attr( 'data-column' ), 10 );
2907
+ vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
2908
+ vars.target = column;
2909
+
2910
+ // if table is not as wide as it's parent, then resize the table
2911
+ vars.$next = event.shiftKey || wo.resizable_targetLast ?
2912
+ $header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
2913
+ $header.nextAll( ':not(.resizable-false)' ).eq( 0 );
2914
+
2915
+ column = parseInt( vars.$next.attr( 'data-column' ), 10 );
2916
+ vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
2917
+ vars.next = column;
2918
+
2919
+ vars.mouseXPosition = event.pageX;
2920
+ ts.resizable.updateStoredSizes( c, wo );
2921
+ ts.resizable.toggleTextSelection(c, wo, true );
2922
+ });
2923
+
2924
+ $( document )
2925
+ .bind( 'mousemove' + namespace, function( event ) {
2926
+ var vars = wo.resizable_vars;
2927
+ // ignore mousemove if no mousedown
2928
+ if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
2929
+ if ( wo.resizable_throttle ) {
2930
+ clearTimeout( vars.timer );
2931
+ vars.timer = setTimeout( function() {
2932
+ ts.resizable.mouseMove( c, wo, event );
2933
+ }, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
2934
+ } else {
2935
+ ts.resizable.mouseMove( c, wo, event );
2936
+ }
2937
+ })
2938
+ .bind( 'mouseup' + namespace, function() {
2939
+ if (!wo.resizable_vars.disabled) { return; }
2940
+ ts.resizable.toggleTextSelection( c, wo, false );
2941
+ ts.resizable.stopResize( c, wo );
2942
+ ts.resizable.setHandlePosition( c, wo );
2943
+ });
2944
+
2945
+ // resizeEnd event triggered by scroller widget
2946
+ $( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
2947
+ ts.resizable.setHandlePosition( c, wo );
2948
+ });
2949
+
2950
+ // right click to reset columns to default widths
2951
+ c.$table
2952
+ .bind( 'columnUpdate pagerComplete resizableUpdate '.split( ' ' ).join( namespace + ' ' ), function() {
2953
+ ts.resizable.setHandlePosition( c, wo );
2954
+ })
2955
+ .bind( 'resizableReset' + namespace, function() {
2956
+ ts.resizableReset( c.table );
2957
+ })
2958
+ .find( 'thead:first' )
2959
+ .add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
2960
+ .bind( 'contextmenu' + namespace, function() {
2961
+ // $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
2962
+ var allowClick = wo.resizable_vars.storedSizes.length === 0;
2963
+ ts.resizableReset( c.table );
2964
+ ts.resizable.setHandlePosition( c, wo );
2965
+ wo.resizable_vars.storedSizes = [];
2966
+ return allowClick;
2967
+ });
2968
+
2969
+ },
2970
+
2971
+ mouseMove : function( c, wo, event ) {
2972
+ if ( wo.resizable_vars.mouseXPosition === 0 || !wo.resizable_vars.$target ) { return; }
2973
+ // resize columns
2974
+ var column,
2975
+ total = 0,
2976
+ vars = wo.resizable_vars,
2977
+ $next = vars.$next,
2978
+ tar = vars.storedSizes[ vars.target ],
2979
+ leftEdge = event.pageX - vars.mouseXPosition;
2980
+ if ( vars.overflow ) {
2981
+ if ( tar + leftEdge > 0 ) {
2982
+ vars.storedSizes[ vars.target ] += leftEdge;
2983
+ ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
2984
+ // update the entire table width
2985
+ for ( column = 0; column < c.columns; column++ ) {
2986
+ total += vars.storedSizes[ column ];
2987
+ }
2988
+ ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
2989
+ }
2990
+ if ( !$next.length ) {
2991
+ // if expanding right-most column, scroll the wrapper
2992
+ vars.$wrap[0].scrollLeft = c.$table.width();
2993
+ }
2994
+ } else if ( vars.fullWidth ) {
2995
+ vars.storedSizes[ vars.target ] += leftEdge;
2996
+ vars.storedSizes[ vars.next ] -= leftEdge;
2997
+ ts.resizable.setWidths( c, wo );
2998
+ } else {
2999
+ vars.storedSizes[ vars.target ] += leftEdge;
3000
+ ts.resizable.setWidths( c, wo );
3001
+ }
3002
+ vars.mouseXPosition = event.pageX;
3003
+ // dynamically update sticky header widths
3004
+ c.$table.triggerHandler('stickyHeadersUpdate');
3005
+ },
3006
+
3007
+ stopResize : function( c, wo ) {
3008
+ var vars = wo.resizable_vars;
3009
+ ts.resizable.updateStoredSizes( c, wo );
3010
+ if ( vars.useStorage ) {
3011
+ // save all column widths
3012
+ ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
3013
+ ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
3014
+ }
3015
+ vars.mouseXPosition = 0;
3016
+ vars.$target = vars.$next = null;
3017
+ // will update stickyHeaders, just in case, see #912
3018
+ c.$table.triggerHandler('stickyHeadersUpdate');
3019
+ c.$table.triggerHandler('resizableComplete');
3020
+ }
3021
+ };
3022
+
3023
+ // this widget saves the column widths if
3024
+ // $.tablesorter.storage function is included
3025
+ // **************************
3026
+ ts.addWidget({
3027
+ id: 'resizable',
3028
+ priority: 40,
3029
+ options: {
3030
+ resizable : true, // save column widths to storage
3031
+ resizable_addLastColumn : false,
3032
+ resizable_includeFooter: true,
3033
+ resizable_widths : [],
3034
+ resizable_throttle : false, // set to true (5ms) or any number 0-10 range
3035
+ resizable_targetLast : false
3036
+ },
3037
+ init: function(table, thisWidget, c, wo) {
3038
+ ts.resizable.init( c, wo );
3039
+ },
3040
+ format: function( table, c, wo ) {
3041
+ ts.resizable.setHandlePosition( c, wo );
3042
+ },
3043
+ remove: function( table, c, wo, refreshing ) {
3044
+ if (wo.$resizable_container) {
3045
+ var namespace = c.namespace + 'tsresize';
3046
+ c.$table.add( $( c.namespace + '_extra_table' ) )
3047
+ .removeClass('hasResizable')
3048
+ .children( 'thead' )
3049
+ .unbind( 'contextmenu' + namespace );
3050
+
3051
+ wo.$resizable_container.remove();
3052
+ ts.resizable.toggleTextSelection( c, wo, false );
3053
+ ts.resizableReset( table, refreshing );
3054
+ $( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
3055
+ }
3056
+ }
3057
+ });
3058
+
3059
+ ts.resizableReset = function( table, refreshing ) {
3060
+ $( table ).each(function() {
3061
+ var index, $t,
3062
+ c = this.config,
3063
+ wo = c && c.widgetOptions,
3064
+ vars = wo.resizable_vars;
3065
+ if ( table && c && c.$headerIndexed.length ) {
3066
+ // restore the initial table width
3067
+ if ( vars.overflow && vars.tableWidth ) {
3068
+ ts.resizable.setWidth( c.$table, vars.tableWidth, true );
3069
+ if ( vars.useStorage ) {
3070
+ ts.storage( table, 'tablesorter-table-resized-width', vars.tableWidth );
3071
+ }
3072
+ }
3073
+ for ( index = 0; index < c.columns; index++ ) {
3074
+ $t = c.$headerIndexed[ index ];
3075
+ if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
3076
+ ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
3077
+ } else if ( !$t.hasClass( 'resizable-false' ) ) {
3078
+ // don't clear the width of any column that is not resizable
3079
+ ts.resizable.setWidth( $t, '', vars.overflow );
3080
+ }
3081
+ }
3082
+
3083
+ // reset stickyHeader widths
3084
+ c.$table.triggerHandler( 'stickyHeadersUpdate' );
3085
+ if ( ts.storage && !refreshing ) {
3086
+ ts.storage( this, ts.css.resizableStorage, [] );
3087
+ }
3088
+ }
3089
+ });
3090
+ };
3091
+
3092
+ })( jQuery, window );
3093
+
3094
+ /*! Widget: saveSort - updated 2018-03-19 (v2.30.1) *//*
3095
+ * Requires tablesorter v2.16+
3096
+ * by Rob Garrison
3097
+ */
3098
+ ;(function ($) {
3099
+ 'use strict';
3100
+ var ts = $.tablesorter || {};
3101
+
3102
+ function getStoredSortList(c) {
3103
+ var stored = ts.storage( c.table, 'tablesorter-savesort' );
3104
+ return (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : [];
3105
+ }
3106
+
3107
+ function sortListChanged(c, sortList) {
3108
+ return (sortList || getStoredSortList(c)).join(',') !== c.sortList.join(',');
3109
+ }
3110
+
3111
+ // this widget saves the last sort only if the
3112
+ // saveSort widget option is true AND the
3113
+ // $.tablesorter.storage function is included
3114
+ // **************************
3115
+ ts.addWidget({
3116
+ id: 'saveSort',
3117
+ priority: 20,
3118
+ options: {
3119
+ saveSort : true
3120
+ },
3121
+ init: function(table, thisWidget, c, wo) {
3122
+ // run widget format before all other widgets are applied to the table
3123
+ thisWidget.format(table, c, wo, true);
3124
+ },
3125
+ format: function(table, c, wo, init) {
3126
+ var time,
3127
+ $table = c.$table,
3128
+ saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
3129
+ sortList = { 'sortList' : c.sortList },
3130
+ debug = ts.debug(c, 'saveSort');
3131
+ if (debug) {
3132
+ time = new Date();
3133
+ }
3134
+ if ($table.hasClass('hasSaveSort')) {
3135
+ if (saveSort && table.hasInitialized && ts.storage && sortListChanged(c)) {
3136
+ ts.storage( table, 'tablesorter-savesort', sortList );
3137
+ if (debug) {
3138
+ console.log('saveSort >> Saving last sort: ' + c.sortList + ts.benchmark(time));
3139
+ }
3140
+ }
3141
+ } else {
3142
+ // set table sort on initial run of the widget
3143
+ $table.addClass('hasSaveSort');
3144
+ sortList = '';
3145
+ // get data
3146
+ if (ts.storage) {
3147
+ sortList = getStoredSortList(c);
3148
+ if (debug) {
3149
+ console.log('saveSort >> Last sort loaded: "' + sortList + '"' + ts.benchmark(time));
3150
+ }
3151
+ $table.bind('saveSortReset', function(event) {
3152
+ event.stopPropagation();
3153
+ ts.storage( table, 'tablesorter-savesort', '' );
3154
+ });
3155
+ }
3156
+ // init is true when widget init is run, this will run this widget before all other widgets have initialized
3157
+ // this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
3158
+ if (init && sortList && sortList.length > 0) {
3159
+ c.sortList = sortList;
3160
+ } else if (table.hasInitialized && sortList && sortList.length > 0) {
3161
+ // update sort change
3162
+ if (sortListChanged(c, sortList)) {
3163
+ ts.sortOn(c, sortList);
3164
+ }
3165
+ }
3166
+ }
3167
+ },
3168
+ remove: function(table, c) {
3169
+ c.$table.removeClass('hasSaveSort');
3170
+ // clear storage
3171
+ if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
3172
+ }
3173
+ });
3174
+
3175
+ })(jQuery);
3176
+ return jQuery.tablesorter;}));
js/tablesorter/jquery.tablesorter.widgets.min.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery){
2
-
3
- /*! tablesorter (FORK) - updated 2018-08-27 (v2.31.0)*/
4
- !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(b,y,_){"use strict";var v=b.tablesorter||{};b.extend(!0,v.defaults,{fixedUrl:"",widgetOptions:{storage_fixedUrl:"",storage_group:"",storage_page:"",storage_storageType:"",storage_tableId:"",storage_useSessionStorage:""}}),v.storage=function(e,t,r,i){var a,l,s,n=!1,o={},c=(e=b(e)[0]).config,d=c&&c.widgetOptions,f=v.debug(c,"storage"),h=(i&&i.storageType||d&&d.storage_storageType).toString().charAt(0).toLowerCase(),u=h?"":i&&i.useSessionStorage||d&&d.storage_useSessionStorage,p=b(e),g=i&&i.id||p.attr(i&&i.group||d&&d.storage_group||"data-table-group")||d&&d.storage_tableId||e.id||b(".tablesorter").index(p),m=i&&i.url||p.attr(i&&i.page||d&&d.storage_page||"data-table-page")||d&&d.storage_fixedUrl||c&&c.fixedUrl||y.location.pathname;if("c"!==h&&(h="s"===h||u?"sessionStorage":"localStorage")in y)try{y[h].setItem("_tmptest","temp"),n=!0,y[h].removeItem("_tmptest")}catch(e){console.warn(h+" is not supported in this browser")}if(f&&console.log("Storage >> Using",n?h:"cookies"),b.parseJSON&&(n?o=b.parseJSON(y[h][t]||"null")||{}:(l=_.cookie.split(/[;\s|=]/),o=0!==(a=b.inArray(t,l)+1)&&b.parseJSON(l[a]||"null")||{})),void 0===r||!y.JSON||!JSON.hasOwnProperty("stringify"))return o&&o[m]?o[m][g]:"";o[m]||(o[m]={}),o[m][g]=r,n?y[h][t]=JSON.stringify(o):((s=new Date).setTime(s.getTime()+31536e6),_.cookie=t+"="+JSON.stringify(o).replace(/\"/g,'"')+"; expires="+s.toGMTString()+"; path=/")}}(e,window,document),function(C){"use strict";var z=C.tablesorter||{};z.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"glyphicon glyphicon-chevron-up",iconSortDesc:"glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s ui-icon-caret-2-n-s",iconSortAsc:"ui-icon-carat-1-n ui-icon-caret-1-n",iconSortDesc:"ui-icon-carat-1-s ui-icon-caret-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},C.extend(z.css,{wrapper:"tablesorter-wrapper"}),z.addWidget({id:"uitheme",priority:10,format:function(e,t,r){var i,a,l,s,n,o,c,d,f,h,u,p,g,m=z.themes,b=t.$table.add(C(t.namespace+"_extra_table")),y=t.$headers.add(C(t.namespace+"_extra_headers")),_=t.theme||"jui",v=m[_]||{},w=C.trim([v.sortNone,v.sortDesc,v.sortAsc,v.active].join(" ")),x=C.trim([v.iconSortNone,v.iconSortDesc,v.iconSortAsc].join(" ")),S=z.debug(t,"uitheme");for(S&&(n=new Date),b.hasClass("tablesorter-"+_)&&t.theme===t.appliedTheme&&r.uitheme_applied||(r.uitheme_applied=!0,h=m[t.appliedTheme]||{},u=(g=!C.isEmptyObject(h))?[h.sortNone,h.sortDesc,h.sortAsc,h.active].join(" "):"",p=g?[h.iconSortNone,h.iconSortDesc,h.iconSortAsc].join(" "):"",g&&(r.zebra[0]=C.trim(" "+r.zebra[0].replace(" "+h.even,"")),r.zebra[1]=C.trim(" "+r.zebra[1].replace(" "+h.odd,"")),t.$tbodies.children().removeClass([h.even,h.odd].join(" "))),v.even&&(r.zebra[0]+=" "+v.even),v.odd&&(r.zebra[1]+=" "+v.odd),b.children("caption").removeClass(h.caption||"").addClass(v.caption),d=b.removeClass((t.appliedTheme?"tablesorter-"+(t.appliedTheme||""):"")+" "+(h.table||"")).addClass("tablesorter-"+_+" "+(v.table||"")).children("tfoot"),t.appliedTheme=t.theme,d.length&&d.children("tr").removeClass(h.footerRow||"").addClass(v.footerRow).children("th, td").removeClass(h.footerCells||"").addClass(v.footerCells),y.removeClass((g?[h.header,h.hover,u].join(" "):"")||"").addClass(v.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(e){C(this)["mouseenter"===e.type?"addClass":"removeClass"](v.hover||"")}),y.each(function(){var e=C(this);e.find("."+z.css.wrapper).length||e.wrapInner('<div class="'+z.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>')}),t.cssIcon&&y.find("."+z.css.icon).removeClass(g?[h.icons,p].join(" "):"").addClass(v.icons||""),z.hasWidget(t.table,"filter")&&(a=function(){b.children("thead").children("."+z.css.filterRow).removeClass(g&&h.filterRow||"").addClass(v.filterRow||"")},r.filter_initialized?a():b.one("filterInit",function(){a()}))),i=0;i<t.columns;i++)o=t.$headers.add(C(t.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+i+'"]'),c=z.css.icon?o.find("."+z.css.icon):C(),(f=y.not(".sorter-false").filter('[data-column="'+i+'"]:last')).length&&(o.removeClass(w),c.removeClass(x),f[0].sortDisabled?c.removeClass(v.icons||""):(l=v.sortNone,s=v.iconSortNone,f.hasClass(z.css.sortAsc)?(l=[v.sortAsc,v.active].join(" "),s=v.iconSortAsc):f.hasClass(z.css.sortDesc)&&(l=[v.sortDesc,v.active].join(" "),s=v.iconSortDesc),o.addClass(l),c.addClass(s||"")));S&&console.log("uitheme >> Applied "+_+" theme"+z.benchmark(n))},remove:function(e,t,r,i){if(r.uitheme_applied){var a=t.$table,l=t.appliedTheme||"jui",s=z.themes[l]||z.themes.jui,n=a.children("thead").children(),o=s.sortNone+" "+s.sortDesc+" "+s.sortAsc,c=s.iconSortNone+" "+s.iconSortDesc+" "+s.iconSortAsc;a.removeClass("tablesorter-"+l+" "+s.table),r.uitheme_applied=!1,i||(a.find(z.css.header).removeClass(s.header),n.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(s.hover+" "+o+" "+s.active).filter("."+z.css.filterRow).removeClass(s.filterRow),n.find("."+z.css.icon).removeClass(s.icons+" "+c))}}})}(e),function(b){"use strict";var y=b.tablesorter||{};y.addWidget({id:"columns",priority:65,options:{columns:["primary","secondary","tertiary"]},format:function(e,t,r){var i,a,l,s,n,o,c,d,f=t.$table,h=t.$tbodies,u=t.sortList,p=u.length,g=r&&r.columns||["primary","secondary","tertiary"],m=g.length-1;for(c=g.join(" "),a=0;a<h.length;a++)(l=(i=y.processTbody(e,h.eq(a),!0)).children("tr")).each(function(){if(n=b(this),"none"!==this.style.display&&(o=n.children().removeClass(c),u&&u[0]&&(o.eq(u[0][0]).addClass(g[0]),1<p)))for(d=1;d<p;d++)o.eq(u[d][0]).addClass(g[d]||g[m])}),y.processTbody(e,i,!1);if(s=!1!==r.columns_thead?["thead tr"]:[],!1!==r.columns_tfoot&&s.push("tfoot tr"),s.length&&(l=f.find(s.join(",")).children().removeClass(c),p))for(d=0;d<p;d++)l.filter('[data-column="'+u[d][0]+'"]').addClass(g[d]||g[m])},remove:function(e,t,r){var i,a,l=t.$tbodies,s=(r.columns||["primary","secondary","tertiary"]).join(" ");for(t.$headers.removeClass(s),t.$table.children("tfoot").children("tr").children("th, td").removeClass(s),i=0;i<l.length;i++)(a=y.processTbody(e,l.eq(i),!0)).children("tr").each(function(){b(this).children().removeClass(s)}),y.processTbody(e,a,!1)}})}(e),function(A){"use strict";var I,O,E=A.tablesorter||{},b=E.css,o=E.keyCodes;A.extend(b,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),A.extend(o,{backSpace:8,escape:27,space:32,left:37,down:40}),E.addWidget({id:"filter",priority:50,options:{filter_cellFilter:"",filter_childRows:!1,filter_childByColumn:!1,filter_childWithSibs:!0,filter_columnAnyMatch:!0,filter_columnFilters:!0,filter_cssFilter:"",filter_defaultAttrib:"data-value",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_filterLabel:'Filter "{{label}}" column by...',filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_matchType:{input:"exact",select:"exact"},filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_resetOnEsc:!0,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_selectSourceSeparator:"|",filter_serversideFiltering:!1,filter_startsWith:!1,filter_useParsedData:!1},format:function(e,t,r){t.$table.hasClass("hasFilters")||I.init(e,t,r)},remove:function(e,t,r,i){var a,l,s=t.$table,n=t.$tbodies,o="addRows updateCell update updateRows updateComplete appendCache filterReset filterAndSortReset filterFomatterUpdate filterEnd search stickyHeadersInit ".split(" ").join(t.namespace+"filter ");if(s.removeClass("hasFilters").unbind(o.replace(E.regex.spaces," ")).find("."+b.filterRow).remove(),r.filter_initialized=!1,!i){for(a=0;a<n.length;a++)(l=E.processTbody(e,n.eq(a),!0)).children().removeClass(r.filter_filteredRow).show(),E.processTbody(e,l,!1);r.filter_reset&&A(document).undelegate(r.filter_reset,"click"+t.namespace+"filter")}}}),O=(I=E.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,operators:/[<>=]/g,query:"(q|query)",wild01:/\?/g,wild0More:/\*/g,quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},types:{or:function(e,t,r){if(!O.orTest.test(t.iFilter)&&!O.orSplit.test(t.filter)||O.regex.test(t.filter))return null;var i,a,l,s=A.extend({},t),n=t.filter.split(O.orSplit),o=t.iFilter.split(O.orSplit),c=n.length;for(i=0;i<c;i++){s.nestedFilters=!0,s.filter=""+(I.parseFilter(e,n[i],t)||""),s.iFilter=""+(I.parseFilter(e,o[i],t)||""),l="("+(I.parseFilter(e,s.filter,t)||"")+")";try{if(a=new RegExp(t.isMatch?l:"^"+l+"$",e.widgetOptions.filter_ignoreCase?"i":"").test(s.exact)||I.processTypes(e,s,r))return a}catch(e){return null}}return a||!1},and:function(e,t,r){if(O.andTest.test(t.filter)){var i,a,l,s,n=A.extend({},t),o=t.filter.split(O.andSplit),c=t.iFilter.split(O.andSplit),d=o.length;for(i=0;i<d;i++){n.nestedFilters=!0,n.filter=""+(I.parseFilter(e,o[i],t)||""),n.iFilter=""+(I.parseFilter(e,c[i],t)||""),s=("("+(I.parseFilter(e,n.filter,t)||"")+")").replace(O.wild01,"\\S{1}").replace(O.wild0More,"\\S*");try{l=new RegExp(t.isMatch?s:"^"+s+"$",e.widgetOptions.filter_ignoreCase?"i":"").test(n.exact)||I.processTypes(e,n,r),a=0===i?l:a&&l}catch(e){return null}}return a||!1}return null},regex:function(e,t){if(O.regex.test(t.filter)){var r,i=t.filter_regexCache[t.index]||O.regex.exec(t.filter),a=i instanceof RegExp;try{a||(t.filter_regexCache[t.index]=i=new RegExp(i[1],i[2])),r=i.test(t.exact)}catch(e){r=!1}return r}return null},operators:function(e,t){if(O.operTest.test(t.iFilter)&&""!==t.iExact){var r,i,a,l=e.table,s=t.parsed[t.index],n=E.formatFloat(t.iFilter.replace(O.operators,""),l),o=e.parsers[t.index]||{},c=n;return(s||"numeric"===o.type)&&(a=A.trim(""+t.iFilter.replace(O.operators,"")),n="number"!=typeof(i=I.parseFilter(e,a,t,!0))||""===i||isNaN(i)?n:i),!s&&"numeric"!==o.type||isNaN(n)||void 0===t.cache?(a=isNaN(t.iExact)?t.iExact.replace(E.regex.nondigit,""):t.iExact,r=E.formatFloat(a,l)):r=t.cache,O.gtTest.test(t.iFilter)?i=O.gteTest.test(t.iFilter)?n<=r:n<r:O.ltTest.test(t.iFilter)&&(i=O.lteTest.test(t.iFilter)?r<=n:r<n),i||""!==c||(i=!0),i}return null},notMatch:function(e,t){if(O.notTest.test(t.iFilter)){var r,i=t.iFilter.replace("!",""),a=I.parseFilter(e,i,t)||"";return O.exact.test(a)?""===(a=a.replace(O.exact,""))||A.trim(a)!==t.iExact:(r=t.iExact.search(A.trim(a)),""===a||(t.anyMatch?r<0:!(e.widgetOptions.filter_startsWith?0===r:0<=r)))}return null},exact:function(e,t){if(O.exact.test(t.iFilter)){var r=t.iFilter.replace(O.exact,""),i=I.parseFilter(e,r,t)||"";return t.anyMatch?0<=A.inArray(i,t.rowArray):i==t.iExact}return null},range:function(e,t){if(O.toTest.test(t.iFilter)){var r,i,a,l,s=e.table,n=t.index,o=t.parsed[n],c=t.iFilter.split(O.toSplit);return i=c[0].replace(E.regex.nondigit,"")||"",a=E.formatFloat(I.parseFilter(e,i,t),s),i=c[1].replace(E.regex.nondigit,"")||"",l=E.formatFloat(I.parseFilter(e,i,t),s),(o||"numeric"===e.parsers[n].type)&&(a=""===(r=e.parsers[n].format(""+c[0],s,e.$headers.eq(n),n))||isNaN(r)?a:r,l=""===(r=e.parsers[n].format(""+c[1],s,e.$headers.eq(n),n))||isNaN(r)?l:r),!o&&"numeric"!==e.parsers[n].type||isNaN(a)||isNaN(l)?(i=isNaN(t.iExact)?t.iExact.replace(E.regex.nondigit,""):t.iExact,r=E.formatFloat(i,s)):r=t.cache,l<a&&(i=a,a=l,l=i),a<=r&&r<=l||""===a||""===l}return null},wild:function(e,t){if(O.wildOrTest.test(t.iFilter)){var r=""+(I.parseFilter(e,t.iFilter,t)||"");!O.wildTest.test(r)&&t.nestedFilters&&(r=t.isMatch?r:"^("+r+")$");try{return new RegExp(r.replace(O.wild01,"\\S{1}").replace(O.wild0More,"\\S*"),e.widgetOptions.filter_ignoreCase?"i":"").test(t.exact)}catch(e){return null}}return null},fuzzy:function(e,t){if(O.fuzzyTest.test(t.iFilter)){var r,i=0,a=t.iExact.length,l=t.iFilter.slice(1),s=I.parseFilter(e,l,t)||"";for(r=0;r<a;r++)t.iExact[r]===s[i]&&(i+=1);return i===s.length}return null}},init:function(r){E.language=A.extend(!0,{},{to:"to",or:"or",and:"and"},E.language);var e,t,i,a,l,s,n,o,c=r.config,d=c.widgetOptions,f=function(e,t,r){return""===(t=t.trim())?"":(e||"")+t+(r||"")};if(c.$table.addClass("hasFilters"),c.lastSearch=[],d.filter_searchTimer=null,d.filter_initTimer=null,d.filter_formatterCount=0,d.filter_formatterInit=[],d.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',d.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',s="\\{"+O.query+"\\}",A.extend(O,{child:new RegExp(c.cssChildRow),filtered:new RegExp(d.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+(-"+f("|",E.language.or)+f("|",E.language.to)+")\\s+)","i"),toTest:new RegExp("\\s+(-"+f("|",E.language.to)+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-"+f("|",E.language.to)+")\\s+)","gi"),andTest:new RegExp("\\s+("+f("",E.language.and,"|")+"&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+f("",E.language.and,"|")+"&&)\\s+)","gi"),orTest:new RegExp("(\\|"+f("|\\s+",E.language.or,"\\s+")+")","i"),orSplit:new RegExp("(?:\\|"+f("|\\s+(?:",E.language.or,")\\s+")+")","gi"),iQuery:new RegExp(s,"i"),igQuery:new RegExp(s,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),s=c.$headers.filter(".filter-false, .parser-false").length,!1!==d.filter_columnFilters&&s!==c.$headers.length&&I.buildRow(r,c,d),i="addRows updateCell update updateRows updateComplete appendCache filterReset "+"filterAndSortReset filterResetSaved filterEnd search ".split(" ").join(c.namespace+"filter "),c.$table.bind(i,function(e,t){return s=d.filter_hideEmpty&&A.isEmptyObject(c.cache)&&!(c.delayInit&&"appendCache"===e.type),c.$table.find("."+b.filterRow).toggleClass(d.filter_filteredRow,s),/(search|filter)/.test(e.type)||(e.stopPropagation(),I.buildDefault(r,!0)),"filterReset"===e.type||"filterAndSortReset"===e.type?(c.$table.find("."+b.filter).add(d.filter_$externalFilters).val(""),"filterAndSortReset"===e.type?E.sortReset(this.config,function(){I.searching(r,[])}):I.searching(r,[])):"filterResetSaved"===e.type?E.storage(r,"tablesorter-filters",""):"filterEnd"===e.type?I.buildDefault(r,!0):(t="search"===e.type?t:"updateComplete"===e.type?c.$table.data("lastSearch"):"",/(update|add)/.test(e.type)&&"updateComplete"!==e.type&&(c.lastCombinedFilter=null,c.lastSearch=[],setTimeout(function(){c.$table.triggerHandler("filterFomatterUpdate")},100)),I.searching(r,t,!0)),!1}),d.filter_reset&&(d.filter_reset instanceof A?d.filter_reset.click(function(){c.$table.triggerHandler("filterReset")}):A(d.filter_reset).length&&A(document).undelegate(d.filter_reset,"click"+c.namespace+"filter").delegate(d.filter_reset,"click"+c.namespace+"filter",function(){c.$table.triggerHandler("filterReset")})),d.filter_functions)for(l=0;l<c.columns;l++)if(n=E.getColumnData(r,d.filter_functions,l))if(o=!((a=c.$headerIndexed[l].removeClass("filter-select")).hasClass("filter-false")||a.hasClass("parser-false")),!(e="")===n&&o)I.buildSelect(r,l);else if("object"==typeof n&&o){for(t in n)"string"==typeof t&&(e+=""===e?'<option value="">'+(a.data("placeholder")||a.attr("data-placeholder")||d.filter_placeholder.select||"")+"</option>":"",0<=(i=s=t).indexOf(d.filter_selectSourceSeparator)&&(i=(s=t.split(d.filter_selectSourceSeparator))[1],s=s[0]),e+="<option "+(i===s?"":'data-function-name="'+t+'" ')+'value="'+s+'">'+i+"</option>");c.$table.find("thead").find("select."+b.filter+'[data-column="'+l+'"]').append(e),(n="function"==typeof(i=d.filter_selectSource)||E.getColumnData(r,i,l))&&I.buildSelect(c.table,l,"",!0,a.hasClass(d.filter_onlyAvail))}I.buildDefault(r,!0),I.bindSearch(r,c.$table.find("."+b.filter),!0),d.filter_external&&I.bindSearch(r,d.filter_external),d.filter_hideFilters&&I.hideFilters(c),c.showProcessing&&(i="filterStart filterEnd ".split(" ").join(c.namespace+"filter-sp "),c.$table.unbind(i.replace(E.regex.spaces," ")).bind(i,function(e,t){a=t?c.$table.find("."+b.header).filter("[data-column]").filter(function(){return""!==t[A(this).data("column")]}):"",E.isProcessing(r,"filterStart"===e.type,t?a:"")})),c.filteredRows=c.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(c.namespace+"filter "),c.$table.unbind(i.replace(E.regex.spaces," ")).bind(i,function(){I.completeInit(this)}),c.pager&&c.pager.initialized&&!d.filter_initialized?(c.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){I.filterInitComplete(c)},100)):d.filter_initialized||I.completeInit(r)},completeInit:function(e){var t=e.config,r=t.widgetOptions,i=I.setDefaults(e,t,r)||[];i.length&&(t.delayInit&&""===i.join("")||E.setFilters(e,i,!0)),t.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){r.filter_initialized||I.filterInitComplete(t)},100)},formatterUpdated:function(e,t){var r=e&&e.closest("table"),i=r.length&&r[0].config,a=i&&i.widgetOptions;a&&!a.filter_initialized&&(a.filter_formatterInit[t]=1)},filterInitComplete:function(e){var t,r,i=e.widgetOptions,a=0,l=function(){i.filter_initialized=!0,e.lastSearch=e.$table.data("lastSearch"),e.$table.triggerHandler("filterInit",e),I.findRows(e.table,e.lastSearch||[]),E.debug(e,"filter")&&console.log("Filter >> Widget initialized")};if(A.isEmptyObject(i.filter_formatter))l();else{for(r=i.filter_formatterInit.length,t=0;t<r;t++)1===i.filter_formatterInit[t]&&a++;clearTimeout(i.filter_initTimer),i.filter_initialized||a!==i.filter_formatterCount?i.filter_initialized||(i.filter_initTimer=setTimeout(function(){l()},500)):l()}},processFilters:function(e,t){var r,i=[],a=t?encodeURIComponent:decodeURIComponent,l=e.length;for(r=0;r<l;r++)e[r]&&(i[r]=a(e[r]));return i},setDefaults:function(e,t,r){var i,a,l,s,n,o=E.getFilters(e)||[];if(r.filter_saveFilters&&E.storage&&(a=E.storage(e,"tablesorter-filters")||[],(i=A.isArray(a))&&""===a.join("")||!i||(o=I.processFilters(a))),""===o.join(""))for(n=t.$headers.add(r.filter_$externalFilters).filter("["+r.filter_defaultAttrib+"]"),l=0;l<=t.columns;l++)s=l===t.columns?"all":l,o[l]=n.filter('[data-column="'+s+'"]').attr(r.filter_defaultAttrib)||o[l]||"";return t.$table.data("lastSearch",o),o},parseFilter:function(e,t,r,i){return i||r.parsed[r.index]?e.parsers[r.index].format(t,e.table,[],r.index):t},buildRow:function(e,t,r){var i,a,l,s,n,o,c,d,f,h=r.filter_cellFilter,u=t.columns,p=A.isArray(h),g='<tr role="search" class="'+b.filterRow+" "+t.cssIgnoreRow+'">';for(l=0;l<u;l++)t.$headerIndexed[l].length&&(g+=1<(f=t.$headerIndexed[l]&&t.$headerIndexed[l][0].colSpan||0)?'<td data-column="'+l+"-"+(l+f-1)+'" colspan="'+f+'"':'<td data-column="'+l+'"',g+=p?h[l]?' class="'+h[l]+'"':"":""!==h?' class="'+h+'"':"",g+="></td>");for(t.$filters=A(g+="</tr>").appendTo(t.$table.children("thead").eq(0)).children("td"),l=0;l<u;l++)o=!1,(s=t.$headerIndexed[l])&&s.length&&(i=I.getColumnElm(t,t.$filters,l),d=E.getColumnData(e,r.filter_functions,l),n=r.filter_functions&&d&&"function"!=typeof d||s.hasClass("filter-select"),a=E.getColumnData(e,t.headers,l),o="false"===E.getData(s[0],a,"filter")||"false"===E.getData(s[0],a,"parser"),n?g=A("<select>").appendTo(i):((d=E.getColumnData(e,r.filter_formatter,l))?(r.filter_formatterCount++,(g=d(i,l))&&0===g.length&&(g=i.children("input")),g&&(0===g.parent().length||g.parent().length&&g.parent()[0]!==i[0])&&i.append(g)):g=A('<input type="search">').appendTo(i),g&&(f=s.data("placeholder")||s.attr("data-placeholder")||r.filter_placeholder.search||"",g.attr("placeholder",f))),g&&(c=(A.isArray(r.filter_cssFilter)?void 0!==r.filter_cssFilter[l]&&r.filter_cssFilter[l]||"":r.filter_cssFilter)||"",g.addClass(b.filter+" "+c),(f=(c=r.filter_filterLabel).match(/{{([^}]+?)}}/g))||(f=["{{label}}"]),A.each(f,function(e,t){var r=new RegExp(t,"g"),i=s.attr("data-"+t.replace(/{{|}}/g,"")),a=void 0===i?s.text():i;c=c.replace(r,A.trim(a))}),g.attr({"data-column":i.attr("data-column"),"aria-label":c}),o&&(g.attr("placeholder","").addClass(b.filterDisabled)[0].disabled=!0)))},bindSearch:function(a,e,t){if(a=A(a)[0],(e=A(e)).length){var r,l=a.config,s=l.widgetOptions,i=l.namespace+"filter",n=s.filter_$externalFilters;!0!==t&&(r=s.filter_anyColumnSelector+","+s.filter_multipleColumnSelector,s.filter_$anyMatch=e.filter(r),n&&n.length?s.filter_$externalFilters=s.filter_$externalFilters.add(e):s.filter_$externalFilters=e,E.setFilters(a,l.$table.data("lastSearch")||[],!1===t)),r="keypress keyup keydown search change input ".split(" ").join(i+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(r.replace(E.regex.spaces," ")).bind("keydown"+i,function(e){if(e.which===o.escape&&!a.config.widgetOptions.filter_resetOnEsc)return!1}).bind("keyup"+i,function(e){s=a.config.widgetOptions;var t=parseInt(A(this).attr("data-column"),10),r="boolean"==typeof s.filter_liveSearch?s.filter_liveSearch:E.getColumnData(a,s.filter_liveSearch,t);if(void 0===r&&(r=s.filter_liveSearch.fallback||!1),A(this).attr("data-lastSearchTime",(new Date).getTime()),e.which===o.escape)this.value=s.filter_resetOnEsc?"":l.lastSearch[t];else{if(""!==this.value&&("number"==typeof r&&this.value.length<r||e.which!==o.enter&&e.which!==o.backSpace&&(e.which<o.space||e.which>=o.left&&e.which<=o.down)))return;if(!1===r&&""!==this.value&&e.which!==o.enter)return}I.searching(a,!0,!0,t)}).bind("search change keypress input blur ".split(" ").join(i+" "),function(e){var t=parseInt(A(this).attr("data-column"),10),r=e.type,i="boolean"==typeof s.filter_liveSearch?s.filter_liveSearch:E.getColumnData(a,s.filter_liveSearch,t);!a.config.widgetOptions.filter_initialized||e.which!==o.enter&&"search"!==r&&"blur"!==r&&("change"!==r&&"input"!==r||!0!==i&&(!0===i||"INPUT"===e.target.nodeName)||this.value===l.lastSearch[t])||(e.preventDefault(),A(this).attr("data-lastSearchTime",(new Date).getTime()),I.searching(a,"keypress"!==r,!0,t))})}},searching:function(e,t,r,i){var a,l=e.config.widgetOptions;void 0===i?a=!1:void 0===(a="boolean"==typeof l.filter_liveSearch?l.filter_liveSearch:E.getColumnData(e,l.filter_liveSearch,i))&&(a=l.filter_liveSearch.fallback||!1),clearTimeout(l.filter_searchTimer),void 0===t||!0===t?l.filter_searchTimer=setTimeout(function(){I.checkFilters(e,t,r)},a?l.filter_searchDelay:10):I.checkFilters(e,t,r)},equalFilters:function(e,t,r){var i,a=[],l=[],s=e.columns+1;for(t=A.isArray(t)?t:[],r=A.isArray(r)?r:[],i=0;i<s;i++)a[i]=t[i]||"",l[i]=r[i]||"";return a.join(",")===l.join(",")},checkFilters:function(e,t,r){var i=e.config,a=i.widgetOptions,l=A.isArray(t),s=l?t:E.getFilters(e,!0),n=s||[];if(A.isEmptyObject(i.cache))i.delayInit&&(!i.pager||i.pager&&i.pager.initialized)&&E.updateCache(i,function(){I.checkFilters(e,!1,r)});else if(l&&(E.setFilters(e,s,!1,!0!==r),a.filter_initialized||(i.lastSearch=[],i.lastCombinedFilter="")),a.filter_hideFilters&&i.$table.find("."+b.filterRow).triggerHandler(I.hideFiltersCheck(i)?"mouseleave":"mouseenter"),!I.equalFilters(i,i.lastSearch,n)||!1===t){if(!1===t&&(i.lastCombinedFilter="",i.lastSearch=[]),s=s||[],s=Array.prototype.map?s.map(String):s.join("�").split("�"),a.filter_initialized&&i.$table.triggerHandler("filterStart",[s]),!i.showProcessing)return I.findRows(e,s,n),!1;setTimeout(function(){return I.findRows(e,s,n),!1},30)}},hideFiltersCheck:function(e){if("function"==typeof e.widgetOptions.filter_hideFilters){var t=e.widgetOptions.filter_hideFilters(e);if("boolean"==typeof t)return t}return""===E.getFilters(e.$table).join("")},hideFilters:function(i,e){var a;(e||i.$table).find("."+b.filterRow).addClass(b.filterRowHide).bind("mouseenter mouseleave",function(e){var t=e,r=A(this);clearTimeout(a),a=setTimeout(function(){/enter|over/.test(t.type)?r.removeClass(b.filterRowHide):A(document.activeElement).closest("tr")[0]!==r[0]&&r.toggleClass(b.filterRowHide,I.hideFiltersCheck(i))},200)}).find("input, select").bind("focus blur",function(e){var t=e,r=A(this).closest("tr");clearTimeout(a),a=setTimeout(function(){clearTimeout(a),r.toggleClass(b.filterRowHide,I.hideFiltersCheck(i)&&"focus"!==t.type)},200)})},defaultFilter:function(e,t){if(""===e)return e;var r=O.iQuery,i=t.match(O.igQuery).length,a=1<i?A.trim(e).split(/\s/):[A.trim(e)],l=a.length-1,s=0,n=t;for(l<1&&1<i&&(a[1]=a[0]);r.test(n);)n=n.replace(r,a[s++]||""),r.test(n)&&s<l&&""!==(a[s]||"")&&(n=t.replace(r,n));return n},getLatestSearch:function(e){return e?e.sort(function(e,t){return A(t).attr("data-lastSearchTime")-A(e).attr("data-lastSearchTime")}):e||A()},findRange:function(e,t,r){var i,a,l,s,n,o,c,d,f,h=[];if(/^[0-9]+$/.test(t))return[parseInt(t,10)];if(!r&&/-/.test(t))for(f=(a=t.match(/(\d+)\s*-\s*(\d+)/g))?a.length:0,d=0;d<f;d++){for(l=a[d].split(/\s*-\s*/),s=parseInt(l[0],10)||0,(n=parseInt(l[1],10)||e.columns-1)<s&&(i=s,s=n,n=i),n>=e.columns&&(n=e.columns-1);s<=n;s++)h[h.length]=s;t=t.replace(a[d],"")}if(!r&&/,/.test(t))for(f=(o=t.split(/\s*,\s*/)).length,c=0;c<f;c++)""!==o[c]&&(d=parseInt(o[c],10))<e.columns&&(h[h.length]=d);if(!h.length)for(d=0;d<e.columns;d++)h[h.length]=d;return h},getColumnElm:function(t,e,r){return e.filter(function(){var e=I.findRange(t,A(this).attr("data-column"));return-1<A.inArray(r,e)})},multipleColumns:function(e,t){var r=e.widgetOptions,i=r.filter_initialized||!t.filter(r.filter_anyColumnSelector).length,a=A.trim(I.getLatestSearch(t).attr("data-column")||"");return I.findRange(e,a,!i)},processTypes:function(e,t,r){var i,a=null,l=null;for(i in I.types)A.inArray(i,r.excludeMatch)<0&&null===l&&null!==(l=I.types[i](e,t,r))&&(t.matchedOn=i,a=l);return a},matchType:function(e,t){var r,i=e.widgetOptions,a=e.$headerIndexed[t];return a.hasClass("filter-exact")?r=!1:a.hasClass("filter-match")?r=!0:(i.filter_columnFilters?a=e.$filters.find("."+b.filter).add(i.filter_$externalFilters).filter('[data-column="'+t+'"]'):i.filter_$externalFilters&&(a=i.filter_$externalFilters.filter('[data-column="'+t+'"]')),r=!!a.length&&"match"===e.widgetOptions.filter_matchType[(a[0].nodeName||"").toLowerCase()]),r},processRow:function(t,r,e){var i,a,l,s,n,o=t.widgetOptions,c=!0,d=o.filter_$anyMatch&&o.filter_$anyMatch.length,f=o.filter_$anyMatch&&o.filter_$anyMatch.length?I.multipleColumns(t,o.filter_$anyMatch):[];if(r.$cells=r.$row.children(),r.matchedOn=null,r.anyMatchFlag&&1<f.length||r.anyMatchFilter&&!d){if(r.anyMatch=!0,r.isMatch=!0,r.rowArray=r.$cells.map(function(e){if(-1<A.inArray(e,f)||r.anyMatchFilter&&!d)return r.parsed[e]?n=r.cacheArray[e]:(n=r.rawArray[e],n=A.trim(o.filter_ignoreCase?n.toLowerCase():n),t.sortLocaleCompare&&(n=E.replaceAccents(n))),n}).get(),r.filter=r.anyMatchFilter,r.iFilter=r.iAnyMatchFilter,r.exact=r.rowArray.join(" "),r.iExact=o.filter_ignoreCase?r.exact.toLowerCase():r.exact,r.cache=r.cacheArray.slice(0,-1).join(" "),e.excludeMatch=e.noAnyMatch,null!==(a=I.processTypes(t,r,e)))c=a;else if(o.filter_startsWith)for(c=!1,f=Math.min(t.columns,r.rowArray.length);!c&&0<f;)f--,c=c||0===r.rowArray[f].indexOf(r.iFilter);else c=0<=(r.iExact+r.childRowText).indexOf(r.iFilter);if(r.anyMatch=!1,r.filters.join("")===r.filter)return c}for(f=0;f<t.columns;f++)r.filter=r.filters[f],r.index=f,e.excludeMatch=e.excludeFilter[f],r.filter&&(r.cache=r.cacheArray[f],i=r.parsed[f]?r.cache:r.rawArray[f]||"",r.exact=t.sortLocaleCompare?E.replaceAccents(i):i,r.iExact=!O.type.test(typeof r.exact)&&o.filter_ignoreCase?r.exact.toLowerCase():r.exact,r.isMatch=I.matchType(t,f),i=c,s=o.filter_columnFilters&&t.$filters.add(o.filter_$externalFilters).filter('[data-column="'+f+'"]').find("select option:selected").attr("data-function-name")||"",t.sortLocaleCompare&&(r.filter=E.replaceAccents(r.filter)),o.filter_defaultFilter&&O.iQuery.test(e.defaultColFilter[f])&&(r.filter=I.defaultFilter(r.filter,e.defaultColFilter[f])),r.iFilter=o.filter_ignoreCase?(r.filter||"").toLowerCase():r.filter,a=null,(l=e.functions[f])&&("function"==typeof l?a=l(r.exact,r.cache,r.filter,f,r.$row,t,r):"function"==typeof l[s||r.filter]&&(a=l[n=s||r.filter](r.exact,r.cache,r.filter,f,r.$row,t,r))),null===a?(a=I.processTypes(t,r,e),n=!0===l&&("and"===r.matchedOn||"or"===r.matchedOn),null===a||n?!0===l?i=r.isMatch?0<=(""+r.iExact).search(r.iFilter):r.filter===r.exact:(n=(r.iExact+r.childRowText).indexOf(I.parseFilter(t,r.iFilter,r)),i=!o.filter_startsWith&&0<=n||o.filter_startsWith&&0===n):i=a):i=a,c=!!i&&c);return c},findRows:function(e,r,t){if(!I.equalFilters(e.config,e.config.lastSearch,t)&&e.config.widgetOptions.filter_initialized){var i,a,l,s,n,o,c,d,f,h,u,p,g,m,b,y,_,v,w,x,S,C,z,$=A.extend([],r),F=e.config,R=F.widgetOptions,T=E.debug(F,"filter"),k={anyMatch:!1,filters:r,filter_regexCache:[]},H={noAnyMatch:["range","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:E.getColumnData(e,R.filter_defaultFilter,F.columns,!0)||""};for(k.parsed=[],f=0;f<F.columns;f++)k.parsed[f]=R.filter_useParsedData||F.parsers&&F.parsers[f]&&F.parsers[f].parsed||E.getData&&"parsed"===E.getData(F.$headerIndexed[f],E.getColumnData(e,F.headers,f),"filter")||F.$headerIndexed[f].hasClass("filter-parsed"),H.functions[f]=E.getColumnData(e,R.filter_functions,f)||F.$headerIndexed[f].hasClass("filter-select"),H.defaultColFilter[f]=E.getColumnData(e,R.filter_defaultFilter,f)||"",H.excludeFilter[f]=(E.getColumnData(e,R.filter_excludeFilter,f,!0)||"").split(/\s+/);for(T&&(console.log("Filter >> Starting filter widget search",r),m=new Date),F.filteredRows=0,t=$||[],c=F.totalRows=0;c<F.$tbodies.length;c++){if(d=E.processTbody(e,F.$tbodies.eq(c),!0),f=F.columns,a=F.cache[c].normalized,s=A(A.map(a,function(e){return e[f].$row.get()})),""===t.join("")||R.filter_serversideFiltering)s.removeClass(R.filter_filteredRow).not("."+F.cssChildRow).css("display","");else{if(i=(s=s.not("."+F.cssChildRow)).length,(R.filter_$anyMatch&&R.filter_$anyMatch.length||void 0!==r[F.columns])&&(k.anyMatchFlag=!0,k.anyMatchFilter=""+(r[F.columns]||R.filter_$anyMatch&&I.getLatestSearch(R.filter_$anyMatch).val()||""),R.filter_columnAnyMatch)){for(w=k.anyMatchFilter.split(O.andSplit),x=!1,y=0;y<w.length;y++)1<(S=w[y].split(":")).length&&(isNaN(S[0])?A.each(F.headerContent,function(e,t){-1<t.toLowerCase().indexOf(S[0])&&(r[C=e]=S[1])}):C=parseInt(S[0],10)-1,0<=C&&C<F.columns&&(r[C]=S[1],w.splice(y,1),y--,x=!0));x&&(k.anyMatchFilter=w.join(" && "))}if(v=R.filter_searchFiltered,u=F.lastSearch||F.$table.data("lastSearch")||[],v)for(y=0;y<f+1;y++)b=r[y]||"",v||(y=f),v=v&&u.length&&0===b.indexOf(u[y]||"")&&!O.alreadyFiltered.test(b)&&!O.exactTest.test(b)&&!(O.isNeg1.test(b)||O.isNeg2.test(b))&&!(""!==b&&F.$filters&&F.$filters.filter('[data-column="'+y+'"]').find("select").length&&!I.matchType(F,y));for(_=s.not("."+R.filter_filteredRow).length,v&&0===_&&(v=!1),T&&console.log("Filter >> Searching through "+(v&&_<i?_:"all")+" rows"),k.anyMatchFlag&&(F.sortLocaleCompare&&(k.anyMatchFilter=E.replaceAccents(k.anyMatchFilter)),R.filter_defaultFilter&&O.iQuery.test(H.defaultAnyFilter)&&(k.anyMatchFilter=I.defaultFilter(k.anyMatchFilter,H.defaultAnyFilter),v=!1),k.iAnyMatchFilter=R.filter_ignoreCase&&F.ignoreCase?k.anyMatchFilter.toLowerCase():k.anyMatchFilter),o=0;o<i;o++)if(z=s[o].className,!(o&&O.child.test(z)||v&&O.filtered.test(z))){if(k.$row=s.eq(o),k.rowIndex=o,k.cacheArray=a[o],l=k.cacheArray[F.columns],k.rawArray=l.raw,k.childRowText="",!R.filter_childByColumn){for(z="",h=l.child,y=0;y<h.length;y++)z+=" "+h[y].join(" ")||"";k.childRowText=R.filter_childRows?R.filter_ignoreCase?z.toLowerCase():z:""}if(p=!1,g=I.processRow(F,k,H),n=l.$row,b=!!g,h=l.$row.filter(":gt(0)"),R.filter_childRows&&h.length){if(R.filter_childByColumn)for(R.filter_childWithSibs||(h.addClass(R.filter_filteredRow),n=n.eq(0)),y=0;y<h.length;y++)k.$row=h.eq(y),k.cacheArray=l.child[y],k.rawArray=k.cacheArray,b=I.processRow(F,k,H),p=p||b,!R.filter_childWithSibs&&b&&h.eq(y).removeClass(R.filter_filteredRow);p=p||g}else p=b;n.toggleClass(R.filter_filteredRow,!p)[0].display=p?"":"none"}}F.filteredRows+=s.not("."+R.filter_filteredRow).length,F.totalRows+=s.length,E.processTbody(e,d,!1)}F.lastCombinedFilter=$.join(""),F.lastSearch=$,F.$table.data("lastSearch",$),R.filter_saveFilters&&E.storage&&E.storage(e,"tablesorter-filters",I.processFilters($,!0)),T&&console.log("Filter >> Completed search"+E.benchmark(m)),R.filter_initialized&&(F.$table.triggerHandler("filterBeforeEnd",F),F.$table.triggerHandler("filterEnd",F)),setTimeout(function(){E.applyWidget(F.table)},0)}},getOptionSource:function(e,t,r){var i=(e=A(e)[0]).config,a=!1,l=i.widgetOptions.filter_selectSource,s=i.$table.data("lastSearch")||[],n="function"==typeof l||E.getColumnData(e,l,t);if(r&&""!==s[t]&&(r=!1),!0===n)a=l(e,t,r);else{if(n instanceof A||"string"===A.type(n)&&0<=n.indexOf("</option>"))return n;if(A.isArray(n))a=n;else if("object"===A.type(l)&&n&&null===(a=n(e,t,r)))return null}return!1===a&&(a=I.getOptions(e,t,r)),I.processOptions(e,t,a)},processOptions:function(a,l,r){if(!A.isArray(r))return!1;var s,e,t,i,n,o,c=(a=A(a)[0]).config,d=null!=l&&0<=l&&l<c.columns,f=!!d&&c.$headerIndexed[l].hasClass("filter-select-sort-desc"),h=[];if(r=A.grep(r,function(e,t){return!!e.text||A.inArray(e,r)===t}),d&&c.$headerIndexed[l].hasClass("filter-select-nosort"))return r;for(i=r.length,t=0;t<i;t++)o=(e=r[t]).text?e.text:e,n=(d&&c.parsers&&c.parsers.length&&c.parsers[l].format(o,a,[],l)||o).toString(),n=c.widgetOptions.filter_ignoreCase?n.toLowerCase():n,e.text?(e.parsed=n,h[h.length]=e):h[h.length]={text:e,parsed:n};for(s=c.textSorter||"",h.sort(function(e,t){var r=f?t.parsed:e.parsed,i=f?e.parsed:t.parsed;return d&&"function"==typeof s?s(r,i,!0,l,a):d&&"object"==typeof s&&s.hasOwnProperty(l)?s[l](r,i,!0,l,a):!E.sortNatural||E.sortNatural(r,i)}),r=[],i=h.length,t=0;t<i;t++)r[r.length]=h[t];return r},getOptions:function(e,t,r){var i,a,l,s,n,o,c,d,f=(e=A(e)[0]).config,h=f.widgetOptions,u=[];for(a=0;a<f.$tbodies.length;a++)for(n=f.cache[a],l=f.cache[a].normalized.length,i=0;i<l;i++)if(s=n.row?n.row[i]:n.normalized[i][f.columns].$row[0],!r||!s.className.match(h.filter_filteredRow))if(h.filter_useParsedData||f.parsers[t].parsed||f.$headerIndexed[t].hasClass("filter-parsed")){if(u[u.length]=""+n.normalized[i][t],h.filter_childRows&&h.filter_childByColumn)for(d=n.normalized[i][f.columns].$row.length-1,o=0;o<d;o++)u[u.length]=""+n.normalized[i][f.columns].child[o][t]}else if(u[u.length]=n.normalized[i][f.columns].raw[t],h.filter_childRows&&h.filter_childByColumn)for(d=n.normalized[i][f.columns].$row.length,o=1;o<d;o++)c=n.normalized[i][f.columns].$row.eq(o).children().eq(t),u[u.length]=""+E.getElementText(f,c,t);return u},buildSelect:function(e,t,r,i,a){if(e=A(e)[0],t=parseInt(t,10),e.config.cache&&!A.isEmptyObject(e.config.cache)){var l,s,n,o,c,d,f,h=e.config,u=h.widgetOptions,p=h.$headerIndexed[t],g='<option value="">'+(p.data("placeholder")||p.attr("data-placeholder")||u.filter_placeholder.select||"")+"</option>",m=h.$table.find("thead").find("select."+b.filter+'[data-column="'+t+'"]').val();if(void 0!==r&&""!==r||null!==(r=I.getOptionSource(e,t,a))){if(A.isArray(r)){for(l=0;l<r.length;l++)if((f=r[l]).text){for(s in f["data-function-name"]=void 0===f.value?f.text:f.value,g+="<option",f)f.hasOwnProperty(s)&&"text"!==s&&(g+=" "+s+'="'+f[s].replace(O.quote,"&quot;")+'"');f.value||(g+=' value="'+f.text.replace(O.quote,"&quot;")+'"'),g+=">"+f.text.replace(O.quote,"&quot;")+"</option>"}else""+f!="[object Object]"&&(0<=(s=n=f=(""+f).replace(O.quote,"&quot;")).indexOf(u.filter_selectSourceSeparator)&&(s=(o=n.split(u.filter_selectSourceSeparator))[0],n=o[1]),g+=""!==f?"<option "+(s===n?"":'data-function-name="'+f+'" ')+'value="'+s+'">'+n+"</option>":"");r=[]}c=(h.$filters?h.$filters:h.$table.children("thead")).find("."+b.filter),u.filter_$externalFilters&&(c=c&&c.length?c.add(u.filter_$externalFilters):u.filter_$externalFilters),(d=c.filter('select[data-column="'+t+'"]')).length&&(d[i?"html":"append"](g),A.isArray(r)||d.append(r).val(m),d.val(m))}}},buildDefault:function(e,t){var r,i,a,l=e.config,s=l.widgetOptions,n=l.columns;for(r=0;r<n;r++)a=!((i=l.$headerIndexed[r]).hasClass("filter-false")||i.hasClass("parser-false")),(i.hasClass("filter-select")||!0===E.getColumnData(e,s.filter_functions,r))&&a&&I.buildSelect(e,r,"",t,i.hasClass(s.filter_onlyAvail))}}).regex,E.getFilters=function(e,t,r,i){var a,l,s,n,o=[],c=e?A(e)[0].config:"",d=c?c.widgetOptions:"";if(!0!==t&&d&&!d.filter_columnFilters||A.isArray(r)&&I.equalFilters(c,r,c.lastSearch))return A(e).data("lastSearch")||[];if(c&&(c.$filters&&(l=c.$filters.find("."+b.filter)),d.filter_$externalFilters&&(l=l&&l.length?l.add(d.filter_$externalFilters):d.filter_$externalFilters),l&&l.length))for(o=r||[],a=0;a<c.columns+1;a++)n=a===c.columns?d.filter_anyColumnSelector+","+d.filter_multipleColumnSelector:'[data-column="'+a+'"]',(s=l.filter(n)).length&&(s=I.getLatestSearch(s),A.isArray(r)?(i&&1<s.length&&(s=s.slice(1)),a===c.columns&&(s=(n=s.filter(d.filter_anyColumnSelector)).length?n:s),s.val(r[a]).trigger("change"+c.namespace)):(o[a]=s.val()||"",a===c.columns?s.slice(1).filter('[data-column*="'+s.attr("data-column")+'"]').val(o[a]):s.slice(1).val(o[a])),a===c.columns&&s.length&&(d.filter_$anyMatch=s));return o},E.setFilters=function(e,t,r,i){var a=e?A(e)[0].config:"",l=E.getFilters(e,!0,t,i);return void 0===r&&(r=!0),a&&r&&(a.lastCombinedFilter=null,a.lastSearch=[],I.searching(a.table,t,i),a.$table.triggerHandler("filterFomatterUpdate")),0!==l.length}}(e),function(z,$){"use strict";var F=z.tablesorter||{};function R(e,t){var r=isNaN(t.stickyHeaders_offset)?z(t.stickyHeaders_offset):[];return r.length?r.height()||0:parseInt(t.stickyHeaders_offset,10)||0}z.extend(F.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),F.addHeaderResizeEvent=function(e,t,r){if((e=z(e)[0]).config){var i=z.extend({},{timer:250},r),o=e.config,c=o.widgetOptions,a=function(e){var t,r,i,a,l,s,n=o.$headers.length;for(c.resize_flag=!0,r=[],t=0;t<n;t++)a=(i=o.$headers.eq(t)).data("savedSizes")||[0,0],l=i[0].offsetWidth,s=i[0].offsetHeight,l===a[0]&&s===a[1]||(i.data("savedSizes",[l,s]),r.push(i[0]));r.length&&!1!==e&&o.$table.triggerHandler("resize",[r]),c.resize_flag=!1};if(clearInterval(c.resize_timer),t)return c.resize_flag=!1;a(!1),c.resize_timer=setInterval(function(){c.resize_flag||a()},i.timer)}},F.addWidget({id:"stickyHeaders",priority:54,options:{stickyHeaders:"",stickyHeaders_appendTo:null,stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(e,r,p){if(!(r.$table.hasClass("hasStickyHeaders")||0<=z.inArray("filter",r.widgets)&&!r.$table.hasClass("hasFilters"))){var t,i,a,l,g=r.$table,m=z(p.stickyHeaders_attachTo||p.stickyHeaders_appendTo),s=r.namespace+"stickyheaders ",b=z(p.stickyHeaders_yScroll||p.stickyHeaders_attachTo||$),n=z(p.stickyHeaders_xScroll||p.stickyHeaders_attachTo||$),o=g.children("thead:first").children("tr").not(".sticky-false").children(),y=g.children("tfoot"),c=R(0,p),_=g.parent().closest("."+F.css.table).hasClass("hasStickyHeaders")?g.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=_.length?_.height():0,d=p.$sticky=g.clone().addClass("containsStickyHeaders "+F.css.sticky+" "+p.stickyHeaders+" "+r.namespace.slice(1)+"_extra_table").wrap('<div class="'+F.css.stickyWrap+'">'),w=d.parent().addClass(F.css.stickyHide).css({position:m.length?"absolute":"fixed",padding:parseInt(d.parent().parent().css("padding-left"),10),top:c+v,left:0,visibility:"hidden",zIndex:p.stickyHeaders_zIndex||2}),f=d.children("thead:first"),x="",h=function(e,t){var r,i,a,l,s,n=e.filter(":visible"),o=n.length;for(r=0;r<o;r++)l=t.filter(":visible").eq(r),"border-box"===(s=n.eq(r)).css("box-sizing")?i=s.outerWidth():"collapse"===l.css("border-collapse")?$.getComputedStyle?i=parseFloat($.getComputedStyle(s[0],null).width):(a=parseFloat(s.css("border-width")),i=s.outerWidth()-parseFloat(s.css("padding-left"))-parseFloat(s.css("padding-right"))-a):i=s.width(),l.css({width:i,"min-width":i,"max-width":i})},S=function(e){return!1===e&&_.length?g.position().left:m.length?parseInt(m.css("padding-left"),10)||0:g.offset().left-parseInt(g.css("margin-left"),10)-z($).scrollLeft()},C=function(){w.css({left:S(),width:g.outerWidth()}),h(g,d),h(o,l)},u=function(e){if(g.is(":visible")){v=_.length?_.offset().top-b.scrollTop()+_.height():0;var t,r=g.offset(),i=R(0,p),a=z.isWindow(b[0]),l=a?b.scrollTop():_.length?parseInt(_[0].style.top,10):b.offset().top,s=m.length?l:b.scrollTop(),n=p.stickyHeaders_includeCaption?0:g.children("caption").height()||0,o=s+i+v-n,c=g.height()-(w.height()+(y.height()||0))-n,d=o>r.top&&o<r.top+c?"visible":"hidden",f="visible"===d?F.css.stickyVis:F.css.stickyHide,h=!w.hasClass(f),u={visibility:d};m.length&&(h=!0,u.top=a?o-m.offset().top:m.scrollTop()),(t=S(a))!==parseInt(w.css("left"),10)&&(h=!0,u.left=t),u.top=(u.top||0)+(!a&&_.length?_.height():i+v),h&&w.removeClass(F.css.stickyVis+" "+F.css.stickyHide).addClass(f).css(u),(d!==x||e)&&(C(),x=d)}};if(m.length&&!m.css("position")&&m.css("position","relative"),d.attr("id")&&(d[0].id+=p.stickyHeaders_cloneId),d.find("> thead:gt(0), tr.sticky-false").hide(),d.find("> tbody, > tfoot").remove(),d.find("caption").toggle(p.stickyHeaders_includeCaption),l=f.children().children(),d.css({height:0,width:0,margin:0}),l.find("."+F.css.resizer).remove(),g.addClass("hasStickyHeaders").bind("pagerComplete"+s,function(){C()}),F.bindEvents(e,f.children().children("."+F.css.header)),p.stickyHeaders_appendTo?z(p.stickyHeaders_appendTo).append(w):g.after(w),r.onRenderHeader)for(i=(a=f.children("tr").children()).length,t=0;t<i;t++)r.onRenderHeader.apply(a.eq(t),[t,r,d]);n.add(b).unbind("scroll resize ".split(" ").join(s).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(s),function(e){u("resize"===e.type)}),r.$table.unbind("stickyHeadersUpdate"+s).bind("stickyHeadersUpdate"+s,function(){u(!0)}),p.stickyHeaders_addResizeEvent&&F.addHeaderResizeEvent(e),g.hasClass("hasFilters")&&p.filter_columnFilters&&(g.bind("filterEnd"+s,function(){var e=z(document.activeElement).closest("td"),t=e.parent().children().index(e);w.hasClass(F.css.stickyVis)&&p.stickyHeaders_filteredToTop&&($.scrollTo(0,g.position().top),0<=t&&r.$filters&&r.$filters.eq(t).find("a, select, input").filter(":visible").focus())}),F.filter.bindSearch(g,l.find("."+F.css.filter)),p.filter_hideFilters&&F.filter.hideFilters(r,d)),p.stickyHeaders_addResizeEvent&&g.bind("resize"+r.namespace+"stickyheaders",function(){C()}),u(!0),g.triggerHandler("stickyHeadersInit")}},remove:function(e,t,r){var i=t.namespace+"stickyheaders ";t.$table.removeClass("hasStickyHeaders").unbind("pagerComplete resize filterEnd stickyHeadersUpdate ".split(" ").join(i).replace(/\s+/g," ")).next("."+F.css.stickyWrap).remove(),r.$sticky&&r.$sticky.length&&r.$sticky.remove(),z($).add(r.stickyHeaders_xScroll).add(r.stickyHeaders_yScroll).add(r.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(i).replace(/\s+/g," ")),F.addHeaderResizeEvent(e,!0)}})}(e,window),function(d,t){"use strict";var f=d.tablesorter||{};d.extend(f.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),d(function(){var e="<style>body."+f.css.resizableNoSelect+" { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }."+f.css.resizableContainer+" { position: relative; height: 1px; }."+f.css.resizableHandle+" { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>";d("head").append(e)}),f.resizable={init:function(e,t){if(!e.$table.hasClass("hasResizable")){e.$table.addClass("hasResizable");var r,i,a,l,s=e.$table,n=s.parent(),o=parseInt(s.css("margin-top"),10),c=t.resizable_vars={useStorage:f.storage&&!1!==t.resizable,$wrap:n,mouseXPosition:0,$target:null,$next:null,overflow:"auto"===n.css("overflow")||"scroll"===n.css("overflow")||"auto"===n.css("overflow-x")||"scroll"===n.css("overflow-x"),storedSizes:[]};for(f.resizableReset(e.table,!0),c.tableWidth=s.width(),c.fullWidth=Math.abs(n.width()-c.tableWidth)<20,c.useStorage&&c.overflow&&(f.storage(e.table,"tablesorter-table-original-css-width",c.tableWidth),l=f.storage(e.table,"tablesorter-table-resized-width")||"auto",f.resizable.setWidth(s,l,!0)),t.resizable_vars.storedSizes=a=(c.useStorage?f.storage(e.table,f.css.resizableStorage):[])||[],f.resizable.setWidths(e,t,a),f.resizable.updateStoredSizes(e,t),t.$resizable_container=d('<div class="'+f.css.resizableContainer+'">').css({top:o}).insertBefore(s),i=0;i<e.columns;i++)r=e.$headerIndexed[i],l=f.getColumnData(e.table,e.headers,i),"false"===f.getData(r,l,"resizable")||d('<div class="'+f.css.resizableHandle+'">').appendTo(t.$resizable_container).attr({"data-column":i,unselectable:"on"}).data("header",r).bind("selectstart",!1);f.resizable.bindings(e,t)}},updateStoredSizes:function(e,t){var r,i,a=e.columns,l=t.resizable_vars;for(l.storedSizes=[],r=0;r<a;r++)i=e.$headerIndexed[r],l.storedSizes[r]=i.is(":visible")?i.width():0},setWidth:function(e,t,r){e.css({width:t,"min-width":r?t:"","max-width":r?t:""})},setWidths:function(e,t,r){var i,a,l=t.resizable_vars,s=d(e.namespace+"_extra_headers"),n=e.$table.children("colgroup").children("col");if((r=r||l.storedSizes||[]).length){for(i=0;i<e.columns;i++)f.resizable.setWidth(e.$headerIndexed[i],r[i],l.overflow),s.length&&(a=s.eq(i).add(n.eq(i)),f.resizable.setWidth(a,r[i],l.overflow));(a=d(e.namespace+"_extra_table")).length&&!f.hasWidget(e.table,"scroller")&&f.resizable.setWidth(a,e.$table.outerWidth(),l.overflow)}},setHandlePosition:function(a,l){var s,n=a.$table.height(),e=l.$resizable_container.children(),o=Math.floor(e.width()/2);f.hasWidget(a.table,"scroller")&&(n=0,a.$table.closest("."+f.css.scrollerWrap).children().each(function(){var e=d(this);n+=e.filter('[style*="height"]').length?e.height():e.children("table").height()})),!l.resizable_includeFooter&&a.$table.children("tfoot").length&&(n-=a.$table.children("tfoot").height()),s=3.3<=parseFloat(d.fn.jquery)?0:a.$table.position().left,e.each(function(){var e=d(this),t=parseInt(e.attr("data-column"),10),r=a.columns-1,i=e.data("header");i&&(!i.is(":visible")||!l.resizable_addLastColumn&&f.resizable.checkVisibleColumns(a,t)?e.hide():(t<r||t===r&&l.resizable_addLastColumn)&&e.css({display:"inline-block",height:n,left:i.position().left-s+i.outerWidth()-o}))})},checkVisibleColumns:function(e,t){var r,i=0;for(r=t+1;r<e.columns;r++)i+=e.$headerIndexed[r].is(":visible")?1:0;return 0===i},toggleTextSelection:function(e,t,r){var i=e.namespace+"tsresize";t.resizable_vars.disabled=r,d("body").toggleClass(f.css.resizableNoSelect,r),r?d("body").attr("unselectable","on").bind("selectstart"+i,!1):d("body").removeAttr("unselectable").unbind("selectstart"+i)},bindings:function(l,s){var e=l.namespace+"tsresize";s.$resizable_container.children().bind("mousedown",function(e){var t,r=s.resizable_vars,i=d(l.namespace+"_extra_headers"),a=d(e.target).data("header");t=parseInt(a.attr("data-column"),10),r.$target=a=a.add(i.filter('[data-column="'+t+'"]')),r.target=t,r.$next=e.shiftKey||s.resizable_targetLast?a.parent().children().not(".resizable-false").filter(":last"):a.nextAll(":not(.resizable-false)").eq(0),t=parseInt(r.$next.attr("data-column"),10),r.$next=r.$next.add(i.filter('[data-column="'+t+'"]')),r.next=t,r.mouseXPosition=e.pageX,f.resizable.updateStoredSizes(l,s),f.resizable.toggleTextSelection(l,s,!0)}),d(document).bind("mousemove"+e,function(e){var t=s.resizable_vars;t.disabled&&0!==t.mouseXPosition&&t.$target&&(s.resizable_throttle?(clearTimeout(t.timer),t.timer=setTimeout(function(){f.resizable.mouseMove(l,s,e)},isNaN(s.resizable_throttle)?5:s.resizable_throttle)):f.resizable.mouseMove(l,s,e))}).bind("mouseup"+e,function(){s.resizable_vars.disabled&&(f.resizable.toggleTextSelection(l,s,!1),f.resizable.stopResize(l,s),f.resizable.setHandlePosition(l,s))}),d(t).bind("resize"+e+" resizeEnd"+e,function(){f.resizable.setHandlePosition(l,s)}),l.$table.bind("columnUpdate pagerComplete resizableUpdate ".split(" ").join(e+" "),function(){f.resizable.setHandlePosition(l,s)}).bind("resizableReset"+e,function(){f.resizableReset(l.table)}).find("thead:first").add(d(l.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+e,function(){var e=0===s.resizable_vars.storedSizes.length;return f.resizableReset(l.table),f.resizable.setHandlePosition(l,s),s.resizable_vars.storedSizes=[],e})},mouseMove:function(e,t,r){if(0!==t.resizable_vars.mouseXPosition&&t.resizable_vars.$target){var i,a=0,l=t.resizable_vars,s=l.$next,n=l.storedSizes[l.target],o=r.pageX-l.mouseXPosition;if(l.overflow){if(0<n+o){for(l.storedSizes[l.target]+=o,f.resizable.setWidth(l.$target,l.storedSizes[l.target],!0),i=0;i<e.columns;i++)a+=l.storedSizes[i];f.resizable.setWidth(e.$table.add(d(e.namespace+"_extra_table")),a)}s.length||(l.$wrap[0].scrollLeft=e.$table.width())}else l.fullWidth?(l.storedSizes[l.target]+=o,l.storedSizes[l.next]-=o):l.storedSizes[l.target]+=o,f.resizable.setWidths(e,t);l.mouseXPosition=r.pageX,e.$table.triggerHandler("stickyHeadersUpdate")}},stopResize:function(e,t){var r=t.resizable_vars;f.resizable.updateStoredSizes(e,t),r.useStorage&&(f.storage(e.table,f.css.resizableStorage,r.storedSizes),f.storage(e.table,"tablesorter-table-resized-width",e.$table.width())),r.mouseXPosition=0,r.$target=r.$next=null,e.$table.triggerHandler("stickyHeadersUpdate"),e.$table.triggerHandler("resizableComplete")}},f.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_includeFooter:!0,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1},init:function(e,t,r,i){f.resizable.init(r,i)},format:function(e,t,r){f.resizable.setHandlePosition(t,r)},remove:function(e,t,r,i){if(r.$resizable_container){var a=t.namespace+"tsresize";t.$table.add(d(t.namespace+"_extra_table")).removeClass("hasResizable").children("thead").unbind("contextmenu"+a),r.$resizable_container.remove(),f.resizable.toggleTextSelection(t,r,!1),f.resizableReset(e,i),d(document).unbind("mousemove"+a+" mouseup"+a)}}}),f.resizableReset=function(l,s){d(l).each(function(){var e,t,r=this.config,i=r&&r.widgetOptions,a=i.resizable_vars;if(l&&r&&r.$headerIndexed.length){for(a.overflow&&a.tableWidth&&(f.resizable.setWidth(r.$table,a.tableWidth,!0),a.useStorage&&f.storage(l,"tablesorter-table-resized-width",a.tableWidth)),e=0;e<r.columns;e++)t=r.$headerIndexed[e],i.resizable_widths&&i.resizable_widths[e]?f.resizable.setWidth(t,i.resizable_widths[e],a.overflow):t.hasClass("resizable-false")||f.resizable.setWidth(t,"",a.overflow);r.$table.triggerHandler("stickyHeadersUpdate"),f.storage&&!s&&f.storage(this,f.css.resizableStorage,[])}})}}(e,window),function(r){"use strict";var c=r.tablesorter||{};function d(e){var t=c.storage(e.table,"tablesorter-savesort");return t&&t.hasOwnProperty("sortList")&&r.isArray(t.sortList)?t.sortList:[]}function f(e,t){return(t||d(e)).join(",")!==e.sortList.join(",")}c.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(e,t,r,i){t.format(e,r,i,!0)},format:function(t,e,r,i){var a,l=e.$table,s=!1!==r.saveSort,n={sortList:e.sortList},o=c.debug(e,"saveSort");o&&(a=new Date),l.hasClass("hasSaveSort")?s&&t.hasInitialized&&c.storage&&f(e)&&(c.storage(t,"tablesorter-savesort",n),o&&console.log("saveSort >> Saving last sort: "+e.sortList+c.benchmark(a))):(l.addClass("hasSaveSort"),n="",c.storage&&(n=d(e),o&&console.log('saveSort >> Last sort loaded: "'+n+'"'+c.benchmark(a)),l.bind("saveSortReset",function(e){e.stopPropagation(),c.storage(t,"tablesorter-savesort","")})),i&&n&&0<n.length?e.sortList=n:t.hasInitialized&&n&&0<n.length&&f(e,n)&&c.sortOn(e,n))},remove:function(e,t){t.$table.removeClass("hasSaveSort"),c.storage&&c.storage(e,"tablesorter-savesort","")}})}(e),e.tablesorter});return jQuery;}));
1
+ (function(factory){if (typeof define === 'function' && define.amd){define(['jquery'], factory);} else if (typeof module === 'object' && typeof module.exports === 'object'){module.exports = factory(require('jquery'));} else {factory(jQuery);}}(function(jQuery){
2
+
3
+ /*! tablesorter (FORK) - updated 2018-11-20 (v2.31.1)*/
4
+ !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):"object"==typeof module&&"object"==typeof module.exports?module.exports=e(require("jquery")):e(jQuery)}(function(e){return function(b,y,_){"use strict";var v=b.tablesorter||{};b.extend(!0,v.defaults,{fixedUrl:"",widgetOptions:{storage_fixedUrl:"",storage_group:"",storage_page:"",storage_storageType:"",storage_tableId:"",storage_useSessionStorage:""}}),v.storage=function(e,t,r,i){var a,l,s,n=!1,o={},c=(e=b(e)[0]).config,d=c&&c.widgetOptions,f=v.debug(c,"storage"),h=(i&&i.storageType||d&&d.storage_storageType).toString().charAt(0).toLowerCase(),u=h?"":i&&i.useSessionStorage||d&&d.storage_useSessionStorage,p=b(e),g=i&&i.id||p.attr(i&&i.group||d&&d.storage_group||"data-table-group")||d&&d.storage_tableId||e.id||b(".tablesorter").index(p),m=i&&i.url||p.attr(i&&i.page||d&&d.storage_page||"data-table-page")||d&&d.storage_fixedUrl||c&&c.fixedUrl||y.location.pathname;if("c"!==h&&(h="s"===h||u?"sessionStorage":"localStorage")in y)try{y[h].setItem("_tmptest","temp"),n=!0,y[h].removeItem("_tmptest")}catch(e){console.warn(h+" is not supported in this browser")}if(f&&console.log("Storage >> Using",n?h:"cookies"),b.parseJSON&&(o=n?b.parseJSON(y[h][t]||"null")||{}:(l=_.cookie.split(/[;\s|=]/),0!==(a=b.inArray(t,l)+1)&&b.parseJSON(l[a]||"null")||{})),void 0===r||!y.JSON||!JSON.hasOwnProperty("stringify"))return o&&o[m]?o[m][g]:"";o[m]||(o[m]={}),o[m][g]=r,n?y[h][t]=JSON.stringify(o):((s=new Date).setTime(s.getTime()+31536e6),_.cookie=t+"="+JSON.stringify(o).replace(/\"/g,'"')+"; expires="+s.toGMTString()+"; path=/")}}(e,window,document),function(C){"use strict";var z=C.tablesorter||{};z.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"glyphicon glyphicon-chevron-up",iconSortDesc:"glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s ui-icon-caret-2-n-s",iconSortAsc:"ui-icon-carat-1-n ui-icon-caret-1-n",iconSortDesc:"ui-icon-carat-1-s ui-icon-caret-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",odd:"ui-state-default"}},C.extend(z.css,{wrapper:"tablesorter-wrapper"}),z.addWidget({id:"uitheme",priority:10,format:function(e,t,r){var i,a,l,s,n,o,c,d,f,h,u,p,g,m=z.themes,b=t.$table.add(C(t.namespace+"_extra_table")),y=t.$headers.add(C(t.namespace+"_extra_headers")),_=t.theme||"jui",v=m[_]||{},w=C.trim([v.sortNone,v.sortDesc,v.sortAsc,v.active].join(" ")),x=C.trim([v.iconSortNone,v.iconSortDesc,v.iconSortAsc].join(" ")),S=z.debug(t,"uitheme");for(S&&(n=new Date),b.hasClass("tablesorter-"+_)&&t.theme===t.appliedTheme&&r.uitheme_applied||(r.uitheme_applied=!0,h=m[t.appliedTheme]||{},u=(g=!C.isEmptyObject(h))?[h.sortNone,h.sortDesc,h.sortAsc,h.active].join(" "):"",p=g?[h.iconSortNone,h.iconSortDesc,h.iconSortAsc].join(" "):"",g&&(r.zebra[0]=C.trim(" "+r.zebra[0].replace(" "+h.even,"")),r.zebra[1]=C.trim(" "+r.zebra[1].replace(" "+h.odd,"")),t.$tbodies.children().removeClass([h.even,h.odd].join(" "))),v.even&&(r.zebra[0]+=" "+v.even),v.odd&&(r.zebra[1]+=" "+v.odd),b.children("caption").removeClass(h.caption||"").addClass(v.caption),d=b.removeClass((t.appliedTheme?"tablesorter-"+(t.appliedTheme||""):"")+" "+(h.table||"")).addClass("tablesorter-"+_+" "+(v.table||"")).children("tfoot"),t.appliedTheme=t.theme,d.length&&d.children("tr").removeClass(h.footerRow||"").addClass(v.footerRow).children("th, td").removeClass(h.footerCells||"").addClass(v.footerCells),y.removeClass((g?[h.header,h.hover,u].join(" "):"")||"").addClass(v.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(e){C(this)["mouseenter"===e.type?"addClass":"removeClass"](v.hover||"")}),y.each(function(){var e=C(this);e.find("."+z.css.wrapper).length||e.wrapInner('<div class="'+z.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>')}),t.cssIcon&&y.find("."+z.css.icon).removeClass(g?[h.icons,p].join(" "):"").addClass(v.icons||""),z.hasWidget(t.table,"filter")&&(a=function(){b.children("thead").children("."+z.css.filterRow).removeClass(g&&h.filterRow||"").addClass(v.filterRow||"")},r.filter_initialized?a():b.one("filterInit",function(){a()}))),i=0;i<t.columns;i++)o=t.$headers.add(C(t.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+i+'"]'),c=z.css.icon?o.find("."+z.css.icon):C(),(f=y.not(".sorter-false").filter('[data-column="'+i+'"]:last')).length&&(o.removeClass(w),c.removeClass(x),f[0].sortDisabled?c.removeClass(v.icons||""):(l=v.sortNone,s=v.iconSortNone,f.hasClass(z.css.sortAsc)?(l=[v.sortAsc,v.active].join(" "),s=v.iconSortAsc):f.hasClass(z.css.sortDesc)&&(l=[v.sortDesc,v.active].join(" "),s=v.iconSortDesc),o.addClass(l),c.addClass(s||"")));S&&console.log("uitheme >> Applied "+_+" theme"+z.benchmark(n))},remove:function(e,t,r,i){if(r.uitheme_applied){var a=t.$table,l=t.appliedTheme||"jui",s=z.themes[l]||z.themes.jui,n=a.children("thead").children(),o=s.sortNone+" "+s.sortDesc+" "+s.sortAsc,c=s.iconSortNone+" "+s.iconSortDesc+" "+s.iconSortAsc;a.removeClass("tablesorter-"+l+" "+s.table),r.uitheme_applied=!1,i||(a.find(z.css.header).removeClass(s.header),n.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(s.hover+" "+o+" "+s.active).filter("."+z.css.filterRow).removeClass(s.filterRow),n.find("."+z.css.icon).removeClass(s.icons+" "+c))}}})}(e),function(b){"use strict";var y=b.tablesorter||{};y.addWidget({id:"columns",priority:65,options:{columns:["primary","secondary","tertiary"]},format:function(e,t,r){var i,a,l,s,n,o,c,d,f=t.$table,h=t.$tbodies,u=t.sortList,p=u.length,g=r&&r.columns||["primary","secondary","tertiary"],m=g.length-1;for(c=g.join(" "),a=0;a<h.length;a++)(l=(i=y.processTbody(e,h.eq(a),!0)).children("tr")).each(function(){if(n=b(this),"none"!==this.style.display&&(o=n.children().removeClass(c),u&&u[0]&&(o.eq(u[0][0]).addClass(g[0]),1<p)))for(d=1;d<p;d++)o.eq(u[d][0]).addClass(g[d]||g[m])}),y.processTbody(e,i,!1);if(s=!1!==r.columns_thead?["thead tr"]:[],!1!==r.columns_tfoot&&s.push("tfoot tr"),s.length&&(l=f.find(s.join(",")).children().removeClass(c),p))for(d=0;d<p;d++)l.filter('[data-column="'+u[d][0]+'"]').addClass(g[d]||g[m])},remove:function(e,t,r){var i,a,l=t.$tbodies,s=(r.columns||["primary","secondary","tertiary"]).join(" ");for(t.$headers.removeClass(s),t.$table.children("tfoot").children("tr").children("th, td").removeClass(s),i=0;i<l.length;i++)(a=y.processTbody(e,l.eq(i),!0)).children("tr").each(function(){b(this).children().removeClass(s)}),y.processTbody(e,a,!1)}})}(e),function(A){"use strict";var I,O,E=A.tablesorter||{},b=E.css,o=E.keyCodes;A.extend(b,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),A.extend(o,{backSpace:8,escape:27,space:32,left:37,down:40}),E.addWidget({id:"filter",priority:50,options:{filter_cellFilter:"",filter_childRows:!1,filter_childByColumn:!1,filter_childWithSibs:!0,filter_columnAnyMatch:!0,filter_columnFilters:!0,filter_cssFilter:"",filter_defaultAttrib:"data-value",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_filterLabel:'Filter "{{label}}" column by...',filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_matchType:{input:"exact",select:"exact"},filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_resetOnEsc:!0,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_selectSourceSeparator:"|",filter_serversideFiltering:!1,filter_startsWith:!1,filter_useParsedData:!1},format:function(e,t,r){t.$table.hasClass("hasFilters")||I.init(e,t,r)},remove:function(e,t,r,i){var a,l,s=t.$table,n=t.$tbodies,o="addRows updateCell update updateRows updateComplete appendCache filterReset filterAndSortReset filterFomatterUpdate filterEnd search stickyHeadersInit ".split(" ").join(t.namespace+"filter ");if(s.removeClass("hasFilters").unbind(o.replace(E.regex.spaces," ")).find("."+b.filterRow).remove(),r.filter_initialized=!1,!i){for(a=0;a<n.length;a++)(l=E.processTbody(e,n.eq(a),!0)).children().removeClass(r.filter_filteredRow).show(),E.processTbody(e,l,!1);r.filter_reset&&A(document).undelegate(r.filter_reset,"click"+t.namespace+"filter")}}}),O=(I=E.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,operators:/[<>=]/g,query:"(q|query)",wild01:/\?/g,wild0More:/\*/g,quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},types:{or:function(e,t,r){if(!O.orTest.test(t.iFilter)&&!O.orSplit.test(t.filter)||O.regex.test(t.filter))return null;var i,a,l,s=A.extend({},t),n=t.filter.split(O.orSplit),o=t.iFilter.split(O.orSplit),c=n.length;for(i=0;i<c;i++){s.nestedFilters=!0,s.filter=""+(I.parseFilter(e,n[i],t)||""),s.iFilter=""+(I.parseFilter(e,o[i],t)||""),l="("+(I.parseFilter(e,s.filter,t)||"")+")";try{if(a=new RegExp(t.isMatch?l:"^"+l+"$",e.widgetOptions.filter_ignoreCase?"i":"").test(s.exact)||I.processTypes(e,s,r))return a}catch(e){return null}}return a||!1},and:function(e,t,r){if(O.andTest.test(t.filter)){var i,a,l,s,n=A.extend({},t),o=t.filter.split(O.andSplit),c=t.iFilter.split(O.andSplit),d=o.length;for(i=0;i<d;i++){n.nestedFilters=!0,n.filter=""+(I.parseFilter(e,o[i],t)||""),n.iFilter=""+(I.parseFilter(e,c[i],t)||""),s=("("+(I.parseFilter(e,n.filter,t)||"")+")").replace(O.wild01,"\\S{1}").replace(O.wild0More,"\\S*");try{l=new RegExp(t.isMatch?s:"^"+s+"$",e.widgetOptions.filter_ignoreCase?"i":"").test(n.exact)||I.processTypes(e,n,r),a=0===i?l:a&&l}catch(e){return null}}return a||!1}return null},regex:function(e,t){if(O.regex.test(t.filter)){var r,i=t.filter_regexCache[t.index]||O.regex.exec(t.filter),a=i instanceof RegExp;try{a||(t.filter_regexCache[t.index]=i=new RegExp(i[1],i[2])),r=i.test(t.exact)}catch(e){r=!1}return r}return null},operators:function(e,t){if(O.operTest.test(t.iFilter)&&""!==t.iExact){var r,i,a,l=e.table,s=t.parsed[t.index],n=E.formatFloat(t.iFilter.replace(O.operators,""),l),o=e.parsers[t.index]||{},c=n;return(s||"numeric"===o.type)&&(a=A.trim(""+t.iFilter.replace(O.operators,"")),n="number"!=typeof(i=I.parseFilter(e,a,t,!0))||""===i||isNaN(i)?n:i),r=!s&&"numeric"!==o.type||isNaN(n)||void 0===t.cache?(a=isNaN(t.iExact)?t.iExact.replace(E.regex.nondigit,""):t.iExact,E.formatFloat(a,l)):t.cache,O.gtTest.test(t.iFilter)?i=O.gteTest.test(t.iFilter)?n<=r:n<r:O.ltTest.test(t.iFilter)&&(i=O.lteTest.test(t.iFilter)?r<=n:r<n),i||""!==c||(i=!0),i}return null},notMatch:function(e,t){if(O.notTest.test(t.iFilter)){var r,i=t.iFilter.replace("!",""),a=I.parseFilter(e,i,t)||"";return O.exact.test(a)?""===(a=a.replace(O.exact,""))||A.trim(a)!==t.iExact:(r=t.iExact.search(A.trim(a)),""===a||(t.anyMatch?r<0:!(e.widgetOptions.filter_startsWith?0===r:0<=r)))}return null},exact:function(e,t){if(O.exact.test(t.iFilter)){var r=t.iFilter.replace(O.exact,""),i=I.parseFilter(e,r,t)||"";return t.anyMatch?0<=A.inArray(i,t.rowArray):i==t.iExact}return null},range:function(e,t){if(O.toTest.test(t.iFilter)){var r,i,a,l,s=e.table,n=t.index,o=t.parsed[n],c=t.iFilter.split(O.toSplit);return i=c[0].replace(E.regex.nondigit,"")||"",a=E.formatFloat(I.parseFilter(e,i,t),s),i=c[1].replace(E.regex.nondigit,"")||"",l=E.formatFloat(I.parseFilter(e,i,t),s),(o||"numeric"===e.parsers[n].type)&&(a=""===(r=e.parsers[n].format(""+c[0],s,e.$headers.eq(n),n))||isNaN(r)?a:r,l=""===(r=e.parsers[n].format(""+c[1],s,e.$headers.eq(n),n))||isNaN(r)?l:r),r=!o&&"numeric"!==e.parsers[n].type||isNaN(a)||isNaN(l)?(i=isNaN(t.iExact)?t.iExact.replace(E.regex.nondigit,""):t.iExact,E.formatFloat(i,s)):t.cache,l<a&&(i=a,a=l,l=i),a<=r&&r<=l||""===a||""===l}return null},wild:function(e,t){if(O.wildOrTest.test(t.iFilter)){var r=""+(I.parseFilter(e,t.iFilter,t)||"");!O.wildTest.test(r)&&t.nestedFilters&&(r=t.isMatch?r:"^("+r+")$");try{return new RegExp(r.replace(O.wild01,"\\S{1}").replace(O.wild0More,"\\S*"),e.widgetOptions.filter_ignoreCase?"i":"").test(t.exact)}catch(e){return null}}return null},fuzzy:function(e,t){if(O.fuzzyTest.test(t.iFilter)){var r,i=0,a=t.iExact.length,l=t.iFilter.slice(1),s=I.parseFilter(e,l,t)||"";for(r=0;r<a;r++)t.iExact[r]===s[i]&&(i+=1);return i===s.length}return null}},init:function(r){E.language=A.extend(!0,{},{to:"to",or:"or",and:"and"},E.language);var e,t,i,a,l,s,n,o,c=r.config,d=c.widgetOptions,f=function(e,t,r){return""===(t=t.trim())?"":(e||"")+t+(r||"")};if(c.$table.addClass("hasFilters"),c.lastSearch=[],d.filter_searchTimer=null,d.filter_initTimer=null,d.filter_formatterCount=0,d.filter_formatterInit=[],d.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',d.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',s="\\{"+O.query+"\\}",A.extend(O,{child:new RegExp(c.cssChildRow),filtered:new RegExp(d.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+(-"+f("|",E.language.or)+f("|",E.language.to)+")\\s+)","i"),toTest:new RegExp("\\s+(-"+f("|",E.language.to)+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-"+f("|",E.language.to)+")\\s+)","gi"),andTest:new RegExp("\\s+("+f("",E.language.and,"|")+"&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+f("",E.language.and,"|")+"&&)\\s+)","gi"),orTest:new RegExp("(\\|"+f("|\\s+",E.language.or,"\\s+")+")","i"),orSplit:new RegExp("(?:\\|"+f("|\\s+(?:",E.language.or,")\\s+")+")","gi"),iQuery:new RegExp(s,"i"),igQuery:new RegExp(s,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),s=c.$headers.filter(".filter-false, .parser-false").length,!1!==d.filter_columnFilters&&s!==c.$headers.length&&I.buildRow(r,c,d),i="addRows updateCell update updateRows updateComplete appendCache filterReset "+"filterAndSortReset filterResetSaved filterEnd search ".split(" ").join(c.namespace+"filter "),c.$table.bind(i,function(e,t){return s=d.filter_hideEmpty&&A.isEmptyObject(c.cache)&&!(c.delayInit&&"appendCache"===e.type),c.$table.find("."+b.filterRow).toggleClass(d.filter_filteredRow,s),/(search|filter)/.test(e.type)||(e.stopPropagation(),I.buildDefault(r,!0)),"filterReset"===e.type||"filterAndSortReset"===e.type?(c.$table.find("."+b.filter).add(d.filter_$externalFilters).val(""),"filterAndSortReset"===e.type?E.sortReset(this.config,function(){I.searching(r,[])}):I.searching(r,[])):"filterResetSaved"===e.type?E.storage(r,"tablesorter-filters",""):"filterEnd"===e.type?I.buildDefault(r,!0):(t="search"===e.type?t:"updateComplete"===e.type?c.$table.data("lastSearch"):"",/(update|add)/.test(e.type)&&"updateComplete"!==e.type&&(c.lastCombinedFilter=null,c.lastSearch=[],setTimeout(function(){c.$table.triggerHandler("filterFomatterUpdate")},100)),I.searching(r,t,!0)),!1}),d.filter_reset&&(d.filter_reset instanceof A?d.filter_reset.click(function(){c.$table.triggerHandler("filterReset")}):A(d.filter_reset).length&&A(document).undelegate(d.filter_reset,"click"+c.namespace+"filter").delegate(d.filter_reset,"click"+c.namespace+"filter",function(){c.$table.triggerHandler("filterReset")})),d.filter_functions)for(l=0;l<c.columns;l++)if(n=E.getColumnData(r,d.filter_functions,l))if(o=!((a=c.$headerIndexed[l].removeClass("filter-select")).hasClass("filter-false")||a.hasClass("parser-false")),!(e="")===n&&o)I.buildSelect(r,l);else if("object"==typeof n&&o){for(t in n)"string"==typeof t&&(e+=""===e?'<option value="">'+(a.data("placeholder")||a.attr("data-placeholder")||d.filter_placeholder.select||"")+"</option>":"",0<=(i=s=t).indexOf(d.filter_selectSourceSeparator)&&(i=(s=t.split(d.filter_selectSourceSeparator))[1],s=s[0]),e+="<option "+(i===s?"":'data-function-name="'+t+'" ')+'value="'+s+'">'+i+"</option>");c.$table.find("thead").find("select."+b.filter+'[data-column="'+l+'"]').append(e),(n="function"==typeof(i=d.filter_selectSource)||E.getColumnData(r,i,l))&&I.buildSelect(c.table,l,"",!0,a.hasClass(d.filter_onlyAvail))}I.buildDefault(r,!0),I.bindSearch(r,c.$table.find("."+b.filter),!0),d.filter_external&&I.bindSearch(r,d.filter_external),d.filter_hideFilters&&I.hideFilters(c),c.showProcessing&&(i="filterStart filterEnd ".split(" ").join(c.namespace+"filter-sp "),c.$table.unbind(i.replace(E.regex.spaces," ")).bind(i,function(e,t){a=t?c.$table.find("."+b.header).filter("[data-column]").filter(function(){return""!==t[A(this).data("column")]}):"",E.isProcessing(r,"filterStart"===e.type,t?a:"")})),c.filteredRows=c.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(c.namespace+"filter "),c.$table.unbind(i.replace(E.regex.spaces," ")).bind(i,function(){I.completeInit(this)}),c.pager&&c.pager.initialized&&!d.filter_initialized?(c.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){I.filterInitComplete(c)},100)):d.filter_initialized||I.completeInit(r)},completeInit:function(e){var t=e.config,r=t.widgetOptions,i=I.setDefaults(e,t,r)||[];i.length&&(t.delayInit&&""===i.join("")||E.setFilters(e,i,!0)),t.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){r.filter_initialized||I.filterInitComplete(t)},100)},formatterUpdated:function(e,t){var r=e&&e.closest("table"),i=r.length&&r[0].config,a=i&&i.widgetOptions;a&&!a.filter_initialized&&(a.filter_formatterInit[t]=1)},filterInitComplete:function(e){var t,r,i=e.widgetOptions,a=0,l=function(){i.filter_initialized=!0,e.lastSearch=e.$table.data("lastSearch"),e.$table.triggerHandler("filterInit",e),I.findRows(e.table,e.lastSearch||[]),E.debug(e,"filter")&&console.log("Filter >> Widget initialized")};if(A.isEmptyObject(i.filter_formatter))l();else{for(r=i.filter_formatterInit.length,t=0;t<r;t++)1===i.filter_formatterInit[t]&&a++;clearTimeout(i.filter_initTimer),i.filter_initialized||a!==i.filter_formatterCount?i.filter_initialized||(i.filter_initTimer=setTimeout(function(){l()},500)):l()}},processFilters:function(e,t){var r,i=[],a=t?encodeURIComponent:decodeURIComponent,l=e.length;for(r=0;r<l;r++)e[r]&&(i[r]=a(e[r]));return i},setDefaults:function(e,t,r){var i,a,l,s,n,o=E.getFilters(e)||[];if(r.filter_saveFilters&&E.storage&&(a=E.storage(e,"tablesorter-filters")||[],(i=A.isArray(a))&&""===a.join("")||!i||(o=I.processFilters(a))),""===o.join(""))for(n=t.$headers.add(r.filter_$externalFilters).filter("["+r.filter_defaultAttrib+"]"),l=0;l<=t.columns;l++)s=l===t.columns?"all":l,o[l]=n.filter('[data-column="'+s+'"]').attr(r.filter_defaultAttrib)||o[l]||"";return t.$table.data("lastSearch",o),o},parseFilter:function(e,t,r,i){return i||r.parsed[r.index]?e.parsers[r.index].format(t,e.table,[],r.index):t},buildRow:function(e,t,r){var i,a,l,s,n,o,c,d,f,h=r.filter_cellFilter,u=t.columns,p=A.isArray(h),g='<tr role="search" class="'+b.filterRow+" "+t.cssIgnoreRow+'">';for(l=0;l<u;l++)t.$headerIndexed[l].length&&(g+=1<(f=t.$headerIndexed[l]&&t.$headerIndexed[l][0].colSpan||0)?'<td data-column="'+l+"-"+(l+f-1)+'" colspan="'+f+'"':'<td data-column="'+l+'"',g+=p?h[l]?' class="'+h[l]+'"':"":""!==h?' class="'+h+'"':"",g+="></td>");for(t.$filters=A(g+="</tr>").appendTo(t.$table.children("thead").eq(0)).children("td"),l=0;l<u;l++)o=!1,(s=t.$headerIndexed[l])&&s.length&&(i=I.getColumnElm(t,t.$filters,l),d=E.getColumnData(e,r.filter_functions,l),n=r.filter_functions&&d&&"function"!=typeof d||s.hasClass("filter-select"),a=E.getColumnData(e,t.headers,l),o="false"===E.getData(s[0],a,"filter")||"false"===E.getData(s[0],a,"parser"),n?g=A("<select>").appendTo(i):((d=E.getColumnData(e,r.filter_formatter,l))?(r.filter_formatterCount++,(g=d(i,l))&&0===g.length&&(g=i.children("input")),g&&(0===g.parent().length||g.parent().length&&g.parent()[0]!==i[0])&&i.append(g)):g=A('<input type="search">').appendTo(i),g&&(f=s.data("placeholder")||s.attr("data-placeholder")||r.filter_placeholder.search||"",g.attr("placeholder",f))),g&&(c=(A.isArray(r.filter_cssFilter)?void 0!==r.filter_cssFilter[l]&&r.filter_cssFilter[l]||"":r.filter_cssFilter)||"",g.addClass(b.filter+" "+c),(f=(c=r.filter_filterLabel).match(/{{([^}]+?)}}/g))||(f=["{{label}}"]),A.each(f,function(e,t){var r=new RegExp(t,"g"),i=s.attr("data-"+t.replace(/{{|}}/g,"")),a=void 0===i?s.text():i;c=c.replace(r,A.trim(a))}),g.attr({"data-column":i.attr("data-column"),"aria-label":c}),o&&(g.attr("placeholder","").addClass(b.filterDisabled)[0].disabled=!0)))},bindSearch:function(a,e,t){if(a=A(a)[0],(e=A(e)).length){var r,l=a.config,s=l.widgetOptions,i=l.namespace+"filter",n=s.filter_$externalFilters;!0!==t&&(r=s.filter_anyColumnSelector+","+s.filter_multipleColumnSelector,s.filter_$anyMatch=e.filter(r),n&&n.length?s.filter_$externalFilters=s.filter_$externalFilters.add(e):s.filter_$externalFilters=e,E.setFilters(a,l.$table.data("lastSearch")||[],!1===t)),r="keypress keyup keydown search change input ".split(" ").join(i+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(r.replace(E.regex.spaces," ")).bind("keydown"+i,function(e){if(e.which===o.escape&&!a.config.widgetOptions.filter_resetOnEsc)return!1}).bind("keyup"+i,function(e){s=a.config.widgetOptions;var t=parseInt(A(this).attr("data-column"),10),r="boolean"==typeof s.filter_liveSearch?s.filter_liveSearch:E.getColumnData(a,s.filter_liveSearch,t);if(void 0===r&&(r=s.filter_liveSearch.fallback||!1),A(this).attr("data-lastSearchTime",(new Date).getTime()),e.which===o.escape)this.value=s.filter_resetOnEsc?"":l.lastSearch[t];else{if(""!==this.value&&("number"==typeof r&&this.value.length<r||e.which!==o.enter&&e.which!==o.backSpace&&(e.which<o.space||e.which>=o.left&&e.which<=o.down)))return;if(!1===r&&""!==this.value&&e.which!==o.enter)return}I.searching(a,!0,!0,t)}).bind("search change keypress input blur ".split(" ").join(i+" "),function(e){var t=parseInt(A(this).attr("data-column"),10),r=e.type,i="boolean"==typeof s.filter_liveSearch?s.filter_liveSearch:E.getColumnData(a,s.filter_liveSearch,t);!a.config.widgetOptions.filter_initialized||e.which!==o.enter&&"search"!==r&&"blur"!==r&&("change"!==r&&"input"!==r||!0!==i&&(!0===i||"INPUT"===e.target.nodeName)||this.value===l.lastSearch[t])||(e.preventDefault(),A(this).attr("data-lastSearchTime",(new Date).getTime()),I.searching(a,"keypress"!==r,!0,t))})}},searching:function(e,t,r,i){var a,l=e.config.widgetOptions;void 0===i?a=!1:void 0===(a="boolean"==typeof l.filter_liveSearch?l.filter_liveSearch:E.getColumnData(e,l.filter_liveSearch,i))&&(a=l.filter_liveSearch.fallback||!1),clearTimeout(l.filter_searchTimer),void 0===t||!0===t?l.filter_searchTimer=setTimeout(function(){I.checkFilters(e,t,r)},a?l.filter_searchDelay:10):I.checkFilters(e,t,r)},equalFilters:function(e,t,r){var i,a=[],l=[],s=e.columns+1;for(t=A.isArray(t)?t:[],r=A.isArray(r)?r:[],i=0;i<s;i++)a[i]=t[i]||"",l[i]=r[i]||"";return a.join(",")===l.join(",")},checkFilters:function(e,t,r){var i=e.config,a=i.widgetOptions,l=A.isArray(t),s=l?t:E.getFilters(e,!0),n=s||[];if(A.isEmptyObject(i.cache))i.delayInit&&(!i.pager||i.pager&&i.pager.initialized)&&E.updateCache(i,function(){I.checkFilters(e,!1,r)});else if(l&&(E.setFilters(e,s,!1,!0!==r),a.filter_initialized||(i.lastSearch=[],i.lastCombinedFilter="")),a.filter_hideFilters&&i.$table.find("."+b.filterRow).triggerHandler(I.hideFiltersCheck(i)?"mouseleave":"mouseenter"),!I.equalFilters(i,i.lastSearch,n)||!1===t){if(!1===t&&(i.lastCombinedFilter="",i.lastSearch=[]),s=s||[],s=Array.prototype.map?s.map(String):s.join("�").split("�"),a.filter_initialized&&i.$table.triggerHandler("filterStart",[s]),!i.showProcessing)return I.findRows(e,s,n),!1;setTimeout(function(){return I.findRows(e,s,n),!1},30)}},hideFiltersCheck:function(e){if("function"==typeof e.widgetOptions.filter_hideFilters){var t=e.widgetOptions.filter_hideFilters(e);if("boolean"==typeof t)return t}return""===E.getFilters(e.$table).join("")},hideFilters:function(i,e){var a;(e||i.$table).find("."+b.filterRow).addClass(b.filterRowHide).bind("mouseenter mouseleave",function(e){var t=e,r=A(this);clearTimeout(a),a=setTimeout(function(){/enter|over/.test(t.type)?r.removeClass(b.filterRowHide):A(document.activeElement).closest("tr")[0]!==r[0]&&r.toggleClass(b.filterRowHide,I.hideFiltersCheck(i))},200)}).find("input, select").bind("focus blur",function(e){var t=e,r=A(this).closest("tr");clearTimeout(a),a=setTimeout(function(){clearTimeout(a),r.toggleClass(b.filterRowHide,I.hideFiltersCheck(i)&&"focus"!==t.type)},200)})},defaultFilter:function(e,t){if(""===e)return e;var r=O.iQuery,i=t.match(O.igQuery).length,a=1<i?A.trim(e).split(/\s/):[A.trim(e)],l=a.length-1,s=0,n=t;for(l<1&&1<i&&(a[1]=a[0]);r.test(n);)n=n.replace(r,a[s++]||""),r.test(n)&&s<l&&""!==(a[s]||"")&&(n=t.replace(r,n));return n},getLatestSearch:function(e){return e?e.sort(function(e,t){return A(t).attr("data-lastSearchTime")-A(e).attr("data-lastSearchTime")}):e||A()},findRange:function(e,t,r){var i,a,l,s,n,o,c,d,f,h=[];if(/^[0-9]+$/.test(t))return[parseInt(t,10)];if(!r&&/-/.test(t))for(f=(a=t.match(/(\d+)\s*-\s*(\d+)/g))?a.length:0,d=0;d<f;d++){for(l=a[d].split(/\s*-\s*/),s=parseInt(l[0],10)||0,(n=parseInt(l[1],10)||e.columns-1)<s&&(i=s,s=n,n=i),n>=e.columns&&(n=e.columns-1);s<=n;s++)h[h.length]=s;t=t.replace(a[d],"")}if(!r&&/,/.test(t))for(f=(o=t.split(/\s*,\s*/)).length,c=0;c<f;c++)""!==o[c]&&(d=parseInt(o[c],10))<e.columns&&(h[h.length]=d);if(!h.length)for(d=0;d<e.columns;d++)h[h.length]=d;return h},getColumnElm:function(t,e,r){return e.filter(function(){var e=I.findRange(t,A(this).attr("data-column"));return-1<A.inArray(r,e)})},multipleColumns:function(e,t){var r=e.widgetOptions,i=r.filter_initialized||!t.filter(r.filter_anyColumnSelector).length,a=A.trim(I.getLatestSearch(t).attr("data-column")||"");return I.findRange(e,a,!i)},processTypes:function(e,t,r){var i,a=null,l=null;for(i in I.types)A.inArray(i,r.excludeMatch)<0&&null===l&&null!==(l=I.types[i](e,t,r))&&(t.matchedOn=i,a=l);return a},matchType:function(e,t){var r=e.widgetOptions,i=e.$headerIndexed[t];return!i.hasClass("filter-exact")&&(!!i.hasClass("filter-match")||(r.filter_columnFilters?i=e.$filters.find("."+b.filter).add(r.filter_$externalFilters).filter('[data-column="'+t+'"]'):r.filter_$externalFilters&&(i=r.filter_$externalFilters.filter('[data-column="'+t+'"]')),!!i.length&&"match"===e.widgetOptions.filter_matchType[(i[0].nodeName||"").toLowerCase()]))},processRow:function(t,r,e){var i,a,l,s,n,o=t.widgetOptions,c=!0,d=o.filter_$anyMatch&&o.filter_$anyMatch.length,f=o.filter_$anyMatch&&o.filter_$anyMatch.length?I.multipleColumns(t,o.filter_$anyMatch):[];if(r.$cells=r.$row.children(),r.matchedOn=null,r.anyMatchFlag&&1<f.length||r.anyMatchFilter&&!d){if(r.anyMatch=!0,r.isMatch=!0,r.rowArray=r.$cells.map(function(e){if(-1<A.inArray(e,f)||r.anyMatchFilter&&!d)return r.parsed[e]?n=r.cacheArray[e]:(n=r.rawArray[e],n=A.trim(o.filter_ignoreCase?n.toLowerCase():n),t.sortLocaleCompare&&(n=E.replaceAccents(n))),n}).get(),r.filter=r.anyMatchFilter,r.iFilter=r.iAnyMatchFilter,r.exact=r.rowArray.join(" "),r.iExact=o.filter_ignoreCase?r.exact.toLowerCase():r.exact,r.cache=r.cacheArray.slice(0,-1).join(" "),e.excludeMatch=e.noAnyMatch,null!==(a=I.processTypes(t,r,e)))c=a;else if(o.filter_startsWith)for(c=!1,f=Math.min(t.columns,r.rowArray.length);!c&&0<f;)f--,c=c||0===r.rowArray[f].indexOf(r.iFilter);else c=0<=(r.iExact+r.childRowText).indexOf(r.iFilter);if(r.anyMatch=!1,r.filters.join("")===r.filter)return c}for(f=0;f<t.columns;f++)r.filter=r.filters[f],r.index=f,e.excludeMatch=e.excludeFilter[f],r.filter&&(r.cache=r.cacheArray[f],i=r.parsed[f]?r.cache:r.rawArray[f]||"",r.exact=t.sortLocaleCompare?E.replaceAccents(i):i,r.iExact=!O.type.test(typeof r.exact)&&o.filter_ignoreCase?r.exact.toLowerCase():r.exact,r.isMatch=I.matchType(t,f),i=c,s=o.filter_columnFilters&&t.$filters.add(o.filter_$externalFilters).filter('[data-column="'+f+'"]').find("select option:selected").attr("data-function-name")||"",t.sortLocaleCompare&&(r.filter=E.replaceAccents(r.filter)),o.filter_defaultFilter&&O.iQuery.test(e.defaultColFilter[f])&&(r.filter=I.defaultFilter(r.filter,e.defaultColFilter[f])),r.iFilter=o.filter_ignoreCase?(r.filter||"").toLowerCase():r.filter,a=null,(l=e.functions[f])&&("function"==typeof l?a=l(r.exact,r.cache,r.filter,f,r.$row,t,r):"function"==typeof l[s||r.filter]&&(a=l[n=s||r.filter](r.exact,r.cache,r.filter,f,r.$row,t,r))),c=!!(i=null===a?(a=I.processTypes(t,r,e),n=!0===l&&("and"===r.matchedOn||"or"===r.matchedOn),null===a||n?!0===l?r.isMatch?0<=(""+r.iExact).search(r.iFilter):r.filter===r.exact:(n=(r.iExact+r.childRowText).indexOf(I.parseFilter(t,r.iFilter,r)),!o.filter_startsWith&&0<=n||o.filter_startsWith&&0===n):a):a)&&c);return c},findRows:function(e,r,t){if(!I.equalFilters(e.config,e.config.lastSearch,t)&&e.config.widgetOptions.filter_initialized){var i,a,l,s,n,o,c,d,f,h,u,p,g,m,b,y,_,v,w,x,S,C,z,$=A.extend([],r),F=e.config,R=F.widgetOptions,T=E.debug(F,"filter"),k={anyMatch:!1,filters:r,filter_regexCache:[]},H={noAnyMatch:["range","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:E.getColumnData(e,R.filter_defaultFilter,F.columns,!0)||""};for(k.parsed=[],f=0;f<F.columns;f++)k.parsed[f]=R.filter_useParsedData||F.parsers&&F.parsers[f]&&F.parsers[f].parsed||E.getData&&"parsed"===E.getData(F.$headerIndexed[f],E.getColumnData(e,F.headers,f),"filter")||F.$headerIndexed[f].hasClass("filter-parsed"),H.functions[f]=E.getColumnData(e,R.filter_functions,f)||F.$headerIndexed[f].hasClass("filter-select"),H.defaultColFilter[f]=E.getColumnData(e,R.filter_defaultFilter,f)||"",H.excludeFilter[f]=(E.getColumnData(e,R.filter_excludeFilter,f,!0)||"").split(/\s+/);for(T&&(console.log("Filter >> Starting filter widget search",r),m=new Date),F.filteredRows=0,t=$||[],c=F.totalRows=0;c<F.$tbodies.length;c++){if(d=E.processTbody(e,F.$tbodies.eq(c),!0),f=F.columns,a=F.cache[c].normalized,s=A(A.map(a,function(e){return e[f].$row.get()})),""===t.join("")||R.filter_serversideFiltering)s.removeClass(R.filter_filteredRow).not("."+F.cssChildRow).css("display","");else{if(i=(s=s.not("."+F.cssChildRow)).length,(R.filter_$anyMatch&&R.filter_$anyMatch.length||void 0!==r[F.columns])&&(k.anyMatchFlag=!0,k.anyMatchFilter=""+(r[F.columns]||R.filter_$anyMatch&&I.getLatestSearch(R.filter_$anyMatch).val()||""),R.filter_columnAnyMatch)){for(w=k.anyMatchFilter.split(O.andSplit),x=!1,y=0;y<w.length;y++)1<(S=w[y].split(":")).length&&(isNaN(S[0])?A.each(F.headerContent,function(e,t){-1<t.toLowerCase().indexOf(S[0])&&(r[C=e]=S[1])}):C=parseInt(S[0],10)-1,0<=C&&C<F.columns&&(r[C]=S[1],w.splice(y,1),y--,x=!0));x&&(k.anyMatchFilter=w.join(" && "))}if(v=R.filter_searchFiltered,u=F.lastSearch||F.$table.data("lastSearch")||[],v)for(y=0;y<f+1;y++)b=r[y]||"",v||(y=f),v=v&&u.length&&0===b.indexOf(u[y]||"")&&!O.alreadyFiltered.test(b)&&!O.exactTest.test(b)&&!(O.isNeg1.test(b)||O.isNeg2.test(b))&&!(""!==b&&F.$filters&&F.$filters.filter('[data-column="'+y+'"]').find("select").length&&!I.matchType(F,y));for(_=s.not("."+R.filter_filteredRow).length,v&&0===_&&(v=!1),T&&console.log("Filter >> Searching through "+(v&&_<i?_:"all")+" rows"),k.anyMatchFlag&&(F.sortLocaleCompare&&(k.anyMatchFilter=E.replaceAccents(k.anyMatchFilter)),R.filter_defaultFilter&&O.iQuery.test(H.defaultAnyFilter)&&(k.anyMatchFilter=I.defaultFilter(k.anyMatchFilter,H.defaultAnyFilter),v=!1),k.iAnyMatchFilter=R.filter_ignoreCase&&F.ignoreCase?k.anyMatchFilter.toLowerCase():k.anyMatchFilter),o=0;o<i;o++)if(z=s[o].className,!(o&&O.child.test(z)||v&&O.filtered.test(z))){if(k.$row=s.eq(o),k.rowIndex=o,k.cacheArray=a[o],l=k.cacheArray[F.columns],k.rawArray=l.raw,k.childRowText="",!R.filter_childByColumn){for(z="",h=l.child,y=0;y<h.length;y++)z+=" "+h[y].join(" ")||"";k.childRowText=R.filter_childRows?R.filter_ignoreCase?z.toLowerCase():z:""}if(p=!1,g=I.processRow(F,k,H),n=l.$row,b=!!g,h=l.$row.filter(":gt(0)"),R.filter_childRows&&h.length){if(R.filter_childByColumn)for(R.filter_childWithSibs||(h.addClass(R.filter_filteredRow),n=n.eq(0)),y=0;y<h.length;y++)k.$row=h.eq(y),k.cacheArray=l.child[y],k.rawArray=k.cacheArray,b=I.processRow(F,k,H),p=p||b,!R.filter_childWithSibs&&b&&h.eq(y).removeClass(R.filter_filteredRow);p=p||g}else p=b;n.toggleClass(R.filter_filteredRow,!p)[0].display=p?"":"none"}}F.filteredRows+=s.not("."+R.filter_filteredRow).length,F.totalRows+=s.length,E.processTbody(e,d,!1)}F.lastCombinedFilter=$.join(""),F.lastSearch=$,F.$table.data("lastSearch",$),R.filter_saveFilters&&E.storage&&E.storage(e,"tablesorter-filters",I.processFilters($,!0)),T&&console.log("Filter >> Completed search"+E.benchmark(m)),R.filter_initialized&&(F.$table.triggerHandler("filterBeforeEnd",F),F.$table.triggerHandler("filterEnd",F)),setTimeout(function(){E.applyWidget(F.table)},0)}},getOptionSource:function(e,t,r){var i=(e=A(e)[0]).config,a=!1,l=i.widgetOptions.filter_selectSource,s=i.$table.data("lastSearch")||[],n="function"==typeof l||E.getColumnData(e,l,t);if(r&&""!==s[t]&&(r=!1),!0===n)a=l(e,t,r);else{if(n instanceof A||"string"===A.type(n)&&0<=n.indexOf("</option>"))return n;if(A.isArray(n))a=n;else if("object"===A.type(l)&&n&&null===(a=n(e,t,r)))return null}return!1===a&&(a=I.getOptions(e,t,r)),I.processOptions(e,t,a)},processOptions:function(a,l,r){if(!A.isArray(r))return!1;var s,e,t,i,n,o,c=(a=A(a)[0]).config,d=null!=l&&0<=l&&l<c.columns,f=!!d&&c.$headerIndexed[l].hasClass("filter-select-sort-desc"),h=[];if(r=A.grep(r,function(e,t){return!!e.text||A.inArray(e,r)===t}),d&&c.$headerIndexed[l].hasClass("filter-select-nosort"))return r;for(i=r.length,t=0;t<i;t++)o=(e=r[t]).text?e.text:e,n=(d&&c.parsers&&c.parsers.length&&c.parsers[l].format(o,a,[],l)||o).toString(),n=c.widgetOptions.filter_ignoreCase?n.toLowerCase():n,e.text?(e.parsed=n,h[h.length]=e):h[h.length]={text:e,parsed:n};for(s=c.textSorter||"",h.sort(function(e,t){var r=f?t.parsed:e.parsed,i=f?e.parsed:t.parsed;return d&&"function"==typeof s?s(r,i,!0,l,a):d&&"object"==typeof s&&s.hasOwnProperty(l)?s[l](r,i,!0,l,a):!E.sortNatural||E.sortNatural(r,i)}),r=[],i=h.length,t=0;t<i;t++)r[r.length]=h[t];return r},getOptions:function(e,t,r){var i,a,l,s,n,o,c,d,f=(e=A(e)[0]).config,h=f.widgetOptions,u=[];for(a=0;a<f.$tbodies.length;a++)for(n=f.cache[a],l=f.cache[a].normalized.length,i=0;i<l;i++)if(s=n.row?n.row[i]:n.normalized[i][f.columns].$row[0],!r||!s.className.match(h.filter_filteredRow))if(h.filter_useParsedData||f.parsers[t].parsed||f.$headerIndexed[t].hasClass("filter-parsed")){if(u[u.length]=""+n.normalized[i][t],h.filter_childRows&&h.filter_childByColumn)for(d=n.normalized[i][f.columns].$row.length-1,o=0;o<d;o++)u[u.length]=""+n.normalized[i][f.columns].child[o][t]}else if(u[u.length]=n.normalized[i][f.columns].raw[t],h.filter_childRows&&h.filter_childByColumn)for(d=n.normalized[i][f.columns].$row.length,o=1;o<d;o++)c=n.normalized[i][f.columns].$row.eq(o).children().eq(t),u[u.length]=""+E.getElementText(f,c,t);return u},buildSelect:function(e,t,r,i,a){if(e=A(e)[0],t=parseInt(t,10),e.config.cache&&!A.isEmptyObject(e.config.cache)){var l,s,n,o,c,d,f,h=e.config,u=h.widgetOptions,p=h.$headerIndexed[t],g='<option value="">'+(p.data("placeholder")||p.attr("data-placeholder")||u.filter_placeholder.select||"")+"</option>",m=h.$table.find("thead").find("select."+b.filter+'[data-column="'+t+'"]').val();if(void 0!==r&&""!==r||null!==(r=I.getOptionSource(e,t,a))){if(A.isArray(r)){for(l=0;l<r.length;l++)if((f=r[l]).text){for(s in f["data-function-name"]=void 0===f.value?f.text:f.value,g+="<option",f)f.hasOwnProperty(s)&&"text"!==s&&(g+=" "+s+'="'+f[s].replace(O.quote,"&quot;")+'"');f.value||(g+=' value="'+f.text.replace(O.quote,"&quot;")+'"'),g+=">"+f.text.replace(O.quote,"&quot;")+"</option>"}else""+f!="[object Object]"&&(0<=(s=n=f=(""+f).replace(O.quote,"&quot;")).indexOf(u.filter_selectSourceSeparator)&&(s=(o=n.split(u.filter_selectSourceSeparator))[0],n=o[1]),g+=""!==f?"<option "+(s===n?"":'data-function-name="'+f+'" ')+'value="'+s+'">'+n+"</option>":"");r=[]}c=(h.$filters?h.$filters:h.$table.children("thead")).find("."+b.filter),u.filter_$externalFilters&&(c=c&&c.length?c.add(u.filter_$externalFilters):u.filter_$externalFilters),(d=c.filter('select[data-column="'+t+'"]')).length&&(d[i?"html":"append"](g),A.isArray(r)||d.append(r).val(m),d.val(m))}}},buildDefault:function(e,t){var r,i,a,l=e.config,s=l.widgetOptions,n=l.columns;for(r=0;r<n;r++)a=!((i=l.$headerIndexed[r]).hasClass("filter-false")||i.hasClass("parser-false")),(i.hasClass("filter-select")||!0===E.getColumnData(e,s.filter_functions,r))&&a&&I.buildSelect(e,r,"",t,i.hasClass(s.filter_onlyAvail))}}).regex,E.getFilters=function(e,t,r,i){var a,l,s,n,o=[],c=e?A(e)[0].config:"",d=c?c.widgetOptions:"";if(!0!==t&&d&&!d.filter_columnFilters||A.isArray(r)&&I.equalFilters(c,r,c.lastSearch))return A(e).data("lastSearch")||[];if(c&&(c.$filters&&(l=c.$filters.find("."+b.filter)),d.filter_$externalFilters&&(l=l&&l.length?l.add(d.filter_$externalFilters):d.filter_$externalFilters),l&&l.length))for(o=r||[],a=0;a<c.columns+1;a++)n=a===c.columns?d.filter_anyColumnSelector+","+d.filter_multipleColumnSelector:'[data-column="'+a+'"]',(s=l.filter(n)).length&&(s=I.getLatestSearch(s),A.isArray(r)?(i&&1<s.length&&(s=s.slice(1)),a===c.columns&&(s=(n=s.filter(d.filter_anyColumnSelector)).length?n:s),s.val(r[a]).trigger("change"+c.namespace)):(o[a]=s.val()||"",a===c.columns?s.slice(1).filter('[data-column*="'+s.attr("data-column")+'"]').val(o[a]):s.slice(1).val(o[a])),a===c.columns&&s.length&&(d.filter_$anyMatch=s));return o},E.setFilters=function(e,t,r,i){var a=e?A(e)[0].config:"",l=E.getFilters(e,!0,t,i);return void 0===r&&(r=!0),a&&r&&(a.lastCombinedFilter=null,a.lastSearch=[],I.searching(a.table,t,i),a.$table.triggerHandler("filterFomatterUpdate")),0!==l.length}}(e),function(z,$){"use strict";var F=z.tablesorter||{};function R(e,t){var r=isNaN(t.stickyHeaders_offset)?z(t.stickyHeaders_offset):[];return r.length?r.height()||0:parseInt(t.stickyHeaders_offset,10)||0}z.extend(F.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),F.addHeaderResizeEvent=function(e,t,r){if((e=z(e)[0]).config){var i=z.extend({},{timer:250},r),o=e.config,c=o.widgetOptions,a=function(e){var t,r,i,a,l,s,n=o.$headers.length;for(c.resize_flag=!0,r=[],t=0;t<n;t++)a=(i=o.$headers.eq(t)).data("savedSizes")||[0,0],l=i[0].offsetWidth,s=i[0].offsetHeight,l===a[0]&&s===a[1]||(i.data("savedSizes",[l,s]),r.push(i[0]));r.length&&!1!==e&&o.$table.triggerHandler("resize",[r]),c.resize_flag=!1};if(clearInterval(c.resize_timer),t)return c.resize_flag=!1;a(!1),c.resize_timer=setInterval(function(){c.resize_flag||a()},i.timer)}},F.addWidget({id:"stickyHeaders",priority:54,options:{stickyHeaders:"",stickyHeaders_appendTo:null,stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(e,r,p){if(!(r.$table.hasClass("hasStickyHeaders")||0<=z.inArray("filter",r.widgets)&&!r.$table.hasClass("hasFilters"))){var t,i,a,l,g=r.$table,m=z(p.stickyHeaders_attachTo||p.stickyHeaders_appendTo),s=r.namespace+"stickyheaders ",b=z(p.stickyHeaders_yScroll||p.stickyHeaders_attachTo||$),n=z(p.stickyHeaders_xScroll||p.stickyHeaders_attachTo||$),o=g.children("thead:first").children("tr").not(".sticky-false").children(),y=g.children("tfoot"),c=R(0,p),_=g.parent().closest("."+F.css.table).hasClass("hasStickyHeaders")?g.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=_.length?_.height():0,d=p.$sticky=g.clone().addClass("containsStickyHeaders "+F.css.sticky+" "+p.stickyHeaders+" "+r.namespace.slice(1)+"_extra_table").wrap('<div class="'+F.css.stickyWrap+'">'),w=d.parent().addClass(F.css.stickyHide).css({position:m.length?"absolute":"fixed",padding:parseInt(d.parent().parent().css("padding-left"),10),top:c+v,left:0,visibility:"hidden",zIndex:p.stickyHeaders_zIndex||2}),f=d.children("thead:first"),x="",h=function(e,t){var r,i,a,l,s,n=e.filter(":visible"),o=n.length;for(r=0;r<o;r++)l=t.filter(":visible").eq(r),i="border-box"===(s=n.eq(r)).css("box-sizing")?s.outerWidth():"collapse"===l.css("border-collapse")?$.getComputedStyle?parseFloat($.getComputedStyle(s[0],null).width):(a=parseFloat(s.css("border-width")),s.outerWidth()-parseFloat(s.css("padding-left"))-parseFloat(s.css("padding-right"))-a):s.width(),l.css({width:i,"min-width":i,"max-width":i})},S=function(e){return!1===e&&_.length?g.position().left:m.length?parseInt(m.css("padding-left"),10)||0:g.offset().left-parseInt(g.css("margin-left"),10)-z($).scrollLeft()},C=function(){w.css({left:S(),width:g.outerWidth()}),h(g,d),h(o,l)},u=function(e){if(g.is(":visible")){v=_.length?_.offset().top-b.scrollTop()+_.height():0;var t,r=g.offset(),i=R(0,p),a=z.isWindow(b[0]),l=a?b.scrollTop():_.length?parseInt(_[0].style.top,10):b.offset().top,s=m.length?l:b.scrollTop(),n=p.stickyHeaders_includeCaption?0:g.children("caption").height()||0,o=s+i+v-n,c=g.height()-(w.height()+(y.height()||0))-n,d=o>r.top&&o<r.top+c?"visible":"hidden",f="visible"===d?F.css.stickyVis:F.css.stickyHide,h=!w.hasClass(f),u={visibility:d};m.length&&(h=!0,u.top=a?o-m.offset().top:m.scrollTop()),(t=S(a))!==parseInt(w.css("left"),10)&&(h=!0,u.left=t),u.top=(u.top||0)+(!a&&_.length?_.height():i+v),h&&w.removeClass(F.css.stickyVis+" "+F.css.stickyHide).addClass(f).css(u),(d!==x||e)&&(C(),x=d)}};if(m.length&&!m.css("position")&&m.css("position","relative"),d.attr("id")&&(d[0].id+=p.stickyHeaders_cloneId),d.find("> thead:gt(0), tr.sticky-false").hide(),d.find("> tbody, > tfoot").remove(),d.find("caption").toggle(p.stickyHeaders_includeCaption),l=f.children().children(),d.css({height:0,width:0,margin:0}),l.find("."+F.css.resizer).remove(),g.addClass("hasStickyHeaders").bind("pagerComplete"+s,function(){C()}),F.bindEvents(e,f.children().children("."+F.css.header)),p.stickyHeaders_appendTo?z(p.stickyHeaders_appendTo).append(w):g.after(w),r.onRenderHeader)for(i=(a=f.children("tr").children()).length,t=0;t<i;t++)r.onRenderHeader.apply(a.eq(t),[t,r,d]);n.add(b).unbind("scroll resize ".split(" ").join(s).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(s),function(e){u("resize"===e.type)}),r.$table.unbind("stickyHeadersUpdate"+s).bind("stickyHeadersUpdate"+s,function(){u(!0)}),p.stickyHeaders_addResizeEvent&&F.addHeaderResizeEvent(e),g.hasClass("hasFilters")&&p.filter_columnFilters&&(g.bind("filterEnd"+s,function(){var e=z(document.activeElement).closest("td"),t=e.parent().children().index(e);w.hasClass(F.css.stickyVis)&&p.stickyHeaders_filteredToTop&&($.scrollTo(0,g.position().top),0<=t&&r.$filters&&r.$filters.eq(t).find("a, select, input").filter(":visible").focus())}),F.filter.bindSearch(g,l.find("."+F.css.filter)),p.filter_hideFilters&&F.filter.hideFilters(r,d)),p.stickyHeaders_addResizeEvent&&g.bind("resize"+r.namespace+"stickyheaders",function(){C()}),u(!0),g.triggerHandler("stickyHeadersInit")}},remove:function(e,t,r){var i=t.namespace+"stickyheaders ";t.$table.removeClass("hasStickyHeaders").unbind("pagerComplete resize filterEnd stickyHeadersUpdate ".split(" ").join(i).replace(/\s+/g," ")).next("."+F.css.stickyWrap).remove(),r.$sticky&&r.$sticky.length&&r.$sticky.remove(),z($).add(r.stickyHeaders_xScroll).add(r.stickyHeaders_yScroll).add(r.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(i).replace(/\s+/g," ")),F.addHeaderResizeEvent(e,!0)}})}(e,window),function(d,t){"use strict";var f=d.tablesorter||{};d.extend(f.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),d(function(){var e="<style>body."+f.css.resizableNoSelect+" { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }."+f.css.resizableContainer+" { position: relative; height: 1px; }."+f.css.resizableHandle+" { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>";d("head").append(e)}),f.resizable={init:function(e,t){if(!e.$table.hasClass("hasResizable")){e.$table.addClass("hasResizable");var r,i,a,l,s=e.$table,n=s.parent(),o=parseInt(s.css("margin-top"),10),c=t.resizable_vars={useStorage:f.storage&&!1!==t.resizable,$wrap:n,mouseXPosition:0,$target:null,$next:null,overflow:"auto"===n.css("overflow")||"scroll"===n.css("overflow")||"auto"===n.css("overflow-x")||"scroll"===n.css("overflow-x"),storedSizes:[]};for(f.resizableReset(e.table,!0),c.tableWidth=s.width(),c.fullWidth=Math.abs(n.width()-c.tableWidth)<20,c.useStorage&&c.overflow&&(f.storage(e.table,"tablesorter-table-original-css-width",c.tableWidth),l=f.storage(e.table,"tablesorter-table-resized-width")||"auto",f.resizable.setWidth(s,l,!0)),t.resizable_vars.storedSizes=a=(c.useStorage?f.storage(e.table,f.css.resizableStorage):[])||[],f.resizable.setWidths(e,t,a),f.resizable.updateStoredSizes(e,t),t.$resizable_container=d('<div class="'+f.css.resizableContainer+'">').css({top:o}).insertBefore(s),i=0;i<e.columns;i++)r=e.$headerIndexed[i],l=f.getColumnData(e.table,e.headers,i),"false"===f.getData(r,l,"resizable")||d('<div class="'+f.css.resizableHandle+'">').appendTo(t.$resizable_container).attr({"data-column":i,unselectable:"on"}).data("header",r).bind("selectstart",!1);f.resizable.bindings(e,t)}},updateStoredSizes:function(e,t){var r,i,a=e.columns,l=t.resizable_vars;for(l.storedSizes=[],r=0;r<a;r++)i=e.$headerIndexed[r],l.storedSizes[r]=i.is(":visible")?i.width():0},setWidth:function(e,t,r){e.css({width:t,"min-width":r?t:"","max-width":r?t:""})},setWidths:function(e,t,r){var i,a,l=t.resizable_vars,s=d(e.namespace+"_extra_headers"),n=e.$table.children("colgroup").children("col");if((r=r||l.storedSizes||[]).length){for(i=0;i<e.columns;i++)f.resizable.setWidth(e.$headerIndexed[i],r[i],l.overflow),s.length&&(a=s.eq(i).add(n.eq(i)),f.resizable.setWidth(a,r[i],l.overflow));(a=d(e.namespace+"_extra_table")).length&&!f.hasWidget(e.table,"scroller")&&f.resizable.setWidth(a,e.$table.outerWidth(),l.overflow)}},setHandlePosition:function(a,l){var s,n=a.$table.height(),e=l.$resizable_container.children(),o=Math.floor(e.width()/2);f.hasWidget(a.table,"scroller")&&(n=0,a.$table.closest("."+f.css.scrollerWrap).children().each(function(){var e=d(this);n+=e.filter('[style*="height"]').length?e.height():e.children("table").height()})),!l.resizable_includeFooter&&a.$table.children("tfoot").length&&(n-=a.$table.children("tfoot").height()),s=3.3<=parseFloat(d.fn.jquery)?0:a.$table.position().left,e.each(function(){var e=d(this),t=parseInt(e.attr("data-column"),10),r=a.columns-1,i=e.data("header");i&&(!i.is(":visible")||!l.resizable_addLastColumn&&f.resizable.checkVisibleColumns(a,t)?e.hide():(t<r||t===r&&l.resizable_addLastColumn)&&e.css({display:"inline-block",height:n,left:i.position().left-s+i.outerWidth()-o}))})},checkVisibleColumns:function(e,t){var r,i=0;for(r=t+1;r<e.columns;r++)i+=e.$headerIndexed[r].is(":visible")?1:0;return 0===i},toggleTextSelection:function(e,t,r){var i=e.namespace+"tsresize";t.resizable_vars.disabled=r,d("body").toggleClass(f.css.resizableNoSelect,r),r?d("body").attr("unselectable","on").bind("selectstart"+i,!1):d("body").removeAttr("unselectable").unbind("selectstart"+i)},bindings:function(l,s){var e=l.namespace+"tsresize";s.$resizable_container.children().bind("mousedown",function(e){var t,r=s.resizable_vars,i=d(l.namespace+"_extra_headers"),a=d(e.target).data("header");t=parseInt(a.attr("data-column"),10),r.$target=a=a.add(i.filter('[data-column="'+t+'"]')),r.target=t,r.$next=e.shiftKey||s.resizable_targetLast?a.parent().children().not(".resizable-false").filter(":last"):a.nextAll(":not(.resizable-false)").eq(0),t=parseInt(r.$next.attr("data-column"),10),r.$next=r.$next.add(i.filter('[data-column="'+t+'"]')),r.next=t,r.mouseXPosition=e.pageX,f.resizable.updateStoredSizes(l,s),f.resizable.toggleTextSelection(l,s,!0)}),d(document).bind("mousemove"+e,function(e){var t=s.resizable_vars;t.disabled&&0!==t.mouseXPosition&&t.$target&&(s.resizable_throttle?(clearTimeout(t.timer),t.timer=setTimeout(function(){f.resizable.mouseMove(l,s,e)},isNaN(s.resizable_throttle)?5:s.resizable_throttle)):f.resizable.mouseMove(l,s,e))}).bind("mouseup"+e,function(){s.resizable_vars.disabled&&(f.resizable.toggleTextSelection(l,s,!1),f.resizable.stopResize(l,s),f.resizable.setHandlePosition(l,s))}),d(t).bind("resize"+e+" resizeEnd"+e,function(){f.resizable.setHandlePosition(l,s)}),l.$table.bind("columnUpdate pagerComplete resizableUpdate ".split(" ").join(e+" "),function(){f.resizable.setHandlePosition(l,s)}).bind("resizableReset"+e,function(){f.resizableReset(l.table)}).find("thead:first").add(d(l.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+e,function(){var e=0===s.resizable_vars.storedSizes.length;return f.resizableReset(l.table),f.resizable.setHandlePosition(l,s),s.resizable_vars.storedSizes=[],e})},mouseMove:function(e,t,r){if(0!==t.resizable_vars.mouseXPosition&&t.resizable_vars.$target){var i,a=0,l=t.resizable_vars,s=l.$next,n=l.storedSizes[l.target],o=r.pageX-l.mouseXPosition;if(l.overflow){if(0<n+o){for(l.storedSizes[l.target]+=o,f.resizable.setWidth(l.$target,l.storedSizes[l.target],!0),i=0;i<e.columns;i++)a+=l.storedSizes[i];f.resizable.setWidth(e.$table.add(d(e.namespace+"_extra_table")),a)}s.length||(l.$wrap[0].scrollLeft=e.$table.width())}else l.fullWidth?(l.storedSizes[l.target]+=o,l.storedSizes[l.next]-=o):l.storedSizes[l.target]+=o,f.resizable.setWidths(e,t);l.mouseXPosition=r.pageX,e.$table.triggerHandler("stickyHeadersUpdate")}},stopResize:function(e,t){var r=t.resizable_vars;f.resizable.updateStoredSizes(e,t),r.useStorage&&(f.storage(e.table,f.css.resizableStorage,r.storedSizes),f.storage(e.table,"tablesorter-table-resized-width",e.$table.width())),r.mouseXPosition=0,r.$target=r.$next=null,e.$table.triggerHandler("stickyHeadersUpdate"),e.$table.triggerHandler("resizableComplete")}},f.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_includeFooter:!0,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1},init:function(e,t,r,i){f.resizable.init(r,i)},format:function(e,t,r){f.resizable.setHandlePosition(t,r)},remove:function(e,t,r,i){if(r.$resizable_container){var a=t.namespace+"tsresize";t.$table.add(d(t.namespace+"_extra_table")).removeClass("hasResizable").children("thead").unbind("contextmenu"+a),r.$resizable_container.remove(),f.resizable.toggleTextSelection(t,r,!1),f.resizableReset(e,i),d(document).unbind("mousemove"+a+" mouseup"+a)}}}),f.resizableReset=function(l,s){d(l).each(function(){var e,t,r=this.config,i=r&&r.widgetOptions,a=i.resizable_vars;if(l&&r&&r.$headerIndexed.length){for(a.overflow&&a.tableWidth&&(f.resizable.setWidth(r.$table,a.tableWidth,!0),a.useStorage&&f.storage(l,"tablesorter-table-resized-width",a.tableWidth)),e=0;e<r.columns;e++)t=r.$headerIndexed[e],i.resizable_widths&&i.resizable_widths[e]?f.resizable.setWidth(t,i.resizable_widths[e],a.overflow):t.hasClass("resizable-false")||f.resizable.setWidth(t,"",a.overflow);r.$table.triggerHandler("stickyHeadersUpdate"),f.storage&&!s&&f.storage(this,f.css.resizableStorage,[])}})}}(e,window),function(r){"use strict";var c=r.tablesorter||{};function d(e){var t=c.storage(e.table,"tablesorter-savesort");return t&&t.hasOwnProperty("sortList")&&r.isArray(t.sortList)?t.sortList:[]}function f(e,t){return(t||d(e)).join(",")!==e.sortList.join(",")}c.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(e,t,r,i){t.format(e,r,i,!0)},format:function(t,e,r,i){var a,l=e.$table,s=!1!==r.saveSort,n={sortList:e.sortList},o=c.debug(e,"saveSort");o&&(a=new Date),l.hasClass("hasSaveSort")?s&&t.hasInitialized&&c.storage&&f(e)&&(c.storage(t,"tablesorter-savesort",n),o&&console.log("saveSort >> Saving last sort: "+e.sortList+c.benchmark(a))):(l.addClass("hasSaveSort"),n="",c.storage&&(n=d(e),o&&console.log('saveSort >> Last sort loaded: "'+n+'"'+c.benchmark(a)),l.bind("saveSortReset",function(e){e.stopPropagation(),c.storage(t,"tablesorter-savesort","")})),i&&n&&0<n.length?e.sortList=n:t.hasInitialized&&n&&0<n.length&&f(e,n)&&c.sortOn(e,n))},remove:function(e,t){t.$table.removeClass("hasSaveSort"),c.storage&&c.storage(e,"tablesorter-savesort","")}})}(e),e.tablesorter});return jQuery;}));
js/wpadmin.js CHANGED
@@ -88,9 +88,30 @@ var WP_Optimize = function (send_command) {
88
  tables_not_found = $('#wpoptimize_table_list_tables_not_found');
89
 
90
  // table sorter library.
 
91
  // This calls the tablesorter library in order to sort the table information correctly.
92
  // There is a fix below on line 172 to apply applyWidgets on load to avoid diplay hidden for tabs.
93
  $(function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  table_list.tablesorter({
95
  theme: 'default',
96
  widgets: ['zebra', 'rows', 'filter'],
@@ -98,8 +119,8 @@ var WP_Optimize = function (send_command) {
98
  // This option is to specify with colums will be disabled for sorting
99
  headers: {
100
  2: {sorter: 'digit'},
101
- 3: {sorter: 'digit'},
102
- 4: {sorter: 'digit'},
103
  // For Column Action
104
  7: {sorter: false }
105
  },
@@ -145,7 +166,7 @@ var WP_Optimize = function (send_command) {
145
  function temporarily_display_notice(html_contents, where, delay) {
146
  where = ('undefined' === typeof where) ? '#wp-optimize-wrap' : where;
147
  delay = ('undefined' === typeof delay) ? 15 : delay;
148
- $(html_contents).hide().prependTo(where).slideDown('slow').delay(delay * 1000).slideUp('slow', function () {
149
  $(this).remove();
150
  });
151
  }
@@ -173,8 +194,8 @@ var WP_Optimize = function (send_command) {
173
 
174
  if (resp && resp.hasOwnProperty('output')) {
175
  for (var i = 0, len = resp.output.length; i < len; i++) {
176
- var new_html = '<div class="updated">' + resp.output[i] + '</div>';
177
- temporarily_display_notice(new_html, '#actions-results-area');
178
  }
179
  }
180
  });
@@ -196,35 +217,65 @@ var WP_Optimize = function (send_command) {
196
  enable_or_disable_feature('comments', false);
197
  });
198
 
199
- $('#wp-optimize-nav-tab-wrapper .nav-tab, #wp-optimize-images-nav-tab-wrapper .nav-tab').click(function (e) {
200
-
201
- var clicked_tab_id = $(this).attr('id'),
202
- container_id = $(this).closest('.nav-tab-wrapper').attr('id'),
203
- container_prefix_id = container_id.substring(0, container_id.length - 7);
 
 
 
 
 
 
 
204
 
205
- if (!clicked_tab_id) { return; }
206
- if (container_prefix_id != clicked_tab_id.substring(0, container_prefix_id.length)) { return; }
207
 
208
- var clicked_tab_id = clicked_tab_id.substring(container_prefix_id.length);
 
209
 
210
  e.preventDefault();
211
 
212
- $('#' + container_id + ' .nav-tab:not(#wp-optimize-nav-tab-' + clicked_tab_id + ')').removeClass('nav-tab-active');
213
- $(this).addClass('nav-tab-active');
214
 
215
- $('#wp-optimize-wrap .' + container_prefix_id + 'contents:not(#' + container_prefix_id + 'contents-' + clicked_tab_id + ')').hide();
216
- $('#' + container_prefix_id + 'contents-' + clicked_tab_id).show();
217
 
218
- // tablesorter fix.
219
- // At any time, there is a display none as 2 of the 3 tabs will be hidden.
220
- // tablesorter picks this up and then doesnt diplay "zebra" formatting until the user sorts
221
- // This fix updates the tab to allow for "zebra" to be applied regardless if any tab is hiiden or not
222
- // See Line 78 for .tablesorter
223
- if ('tables' == clicked_tab_id) {
224
- $("#wpoptimize_table_list").trigger('applyWidgets');
225
  }
 
 
 
 
 
 
226
  });
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
 
229
  /**
230
  * Gathers the settings from the settings tab and return in selected format.
@@ -238,13 +289,13 @@ var WP_Optimize = function (send_command) {
238
  output_format = ('undefined' === typeof output_format) ? 'string' : output_format;
239
 
240
  if ('object' == output_format) {
241
- form_data = $("#wp-optimize-nav-tab-contents-settings form input[name!='action'], #wp-optimize-nav-tab-contents-settings form textarea, #wp-optimize-nav-tab-contents-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serializeJSON({useIntKeysAsArrayIndex: true});
242
  } else {
243
  // Excluding the unnecessary 'action' input avoids triggering a very mis-conceived mod_security rule seen on one user's site.
244
- form_data = $("#wp-optimize-nav-tab-contents-settings form input[name!='action'], #wp-optimize-nav-tab-contents-settings form textarea, #wp-optimize-nav-tab-contents-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serialize();
245
 
246
  // Include unchecked checkboxes. user filter to only include unchecked boxes.
247
- $.each($('#wp-optimize-nav-tab-contents-settings form input[type=checkbox], .wp-optimize-nav-tab-contents input[name^="enable-auto-backup-"]')
248
  .filter(function (idx) {
249
  return $(this).prop('checked') == false
250
  }),
@@ -495,7 +546,7 @@ var WP_Optimize = function (send_command) {
495
  /**
496
  * Run single optimization click.
497
  */
498
- $('#wp-optimize-nav-tab-contents-optimize').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
499
  var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
500
  if (!optimization_id) {
501
  console.log("Optimization ID corresponding to pressed button not found");
@@ -515,7 +566,7 @@ var WP_Optimize = function (send_command) {
515
  /**
516
  * Run all optimizations click.
517
  */
518
- $('#wp-optimize-nav-tab-contents-optimize').on('click', '#wp-optimize', function (e) {
519
  var run_btn = $(this);
520
 
521
  e.preventDefault();
@@ -586,6 +637,135 @@ var WP_Optimize = function (send_command) {
586
  send_command('save_auto_backup_option', options);
587
  }
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  // Show/hide sites list for multi-site settings.
590
  var wpo_settings_sites_list = $('#wpo_settings_sites_list'),
591
  wpo_settings_sites_list_ul = wpo_settings_sites_list.find('ul').first(),
@@ -755,7 +935,9 @@ var WP_Optimize = function (send_command) {
755
  send_command('save_manual_run_optimization_options', optimization_options);
756
  }
757
 
758
- $('#wp_optimize_table_list_refresh').click(function () {
 
 
759
 
760
  $('#wpoptimize_table_list tbody').css('opacity', '0.5');
761
  send_command('get_table_list', false, function (response) {
@@ -778,11 +960,12 @@ var WP_Optimize = function (send_command) {
778
 
779
  $('#settings_form').on('click', '#wp-optimize-settings-save', function (e) {
780
 
 
 
781
  // validate logger settings.
782
  if (!validate_logger_settings()) return false;
783
 
784
- e.preventDefault();
785
-
786
  $('#save_spinner').show();
787
 
788
  var form_data = gather_settings();
@@ -842,8 +1025,25 @@ var WP_Optimize = function (send_command) {
842
 
843
  // Handle single optimization click.
844
  $('#wpoptimize_table_list').on('click', '.run-single-table-optimization', function() {
845
- var btn = $(this),
846
- spinner = btn.next(),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
847
  action_done_icon = spinner.next(),
848
  table_name = btn.data('table'),
849
  table_type = btn.data('type'),
@@ -852,7 +1052,7 @@ var WP_Optimize = function (send_command) {
852
  optimization_table: table_name,
853
  optimization_table_type: table_type
854
  };
855
-
856
  // if checked force button then send force value.
857
  if (single_table_optimization_force.is(':checked')) {
858
  data['optimization_force'] = true;
@@ -863,9 +1063,11 @@ var WP_Optimize = function (send_command) {
863
  send_command('do_optimization', { optimization_id: 'optimizetables', data: data }, function () {
864
  btn.prop('disabled', false);
865
  spinner.addClass('visibility-hidden');
866
- action_done_icon.show().removeClass('visibility-hidden').delay(3000).fadeOut('slow');
 
 
867
  });
868
- });
869
 
870
  // Handle force optimization checkbox on table list tab.
871
  single_table_optimization_force.change(function() {
@@ -1166,6 +1368,63 @@ var WP_Optimize = function (send_command) {
1166
  });
1167
  });
1168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1169
  change_actions_column_visibility();
1170
 
1171
  /**
@@ -1332,7 +1591,8 @@ jQuery(document).ready(function ($) {
1332
  /**
1333
  * Handle add logging destination click.
1334
  */
1335
- add_logging_btn.on('click', function() {
 
1336
  $('#wp-optimize-logger-settings .save_settings_reminder').after(get_add_logging_form_html());
1337
 
1338
  filter_select_destinations($('.wpo_logger_type').first());
@@ -1341,7 +1601,7 @@ jQuery(document).ready(function ($) {
1341
  /**
1342
  * Handle logging destination select change.
1343
  */
1344
- $('#wp-optimize-nav-tab-contents-settings').on('change', '.wpo_logger_type', function() {
1345
  var select = $(this),
1346
  logger_id = select.val(),
1347
  options_container = select.parent().find('.wpo_additional_logger_options');
@@ -1399,7 +1659,7 @@ jQuery(document).ready(function ($) {
1399
  /**
1400
  * Handle delete logger destination click.
1401
  */
1402
- $('#wp-optimize-nav-tab-contents-settings').on('click', '.wpo_delete_logger', function() {
1403
 
1404
  if (!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination)) {
1405
  return false;
@@ -1536,5 +1796,19 @@ jQuery(document).ready(function ($) {
1536
 
1537
  return options_list.join('');
1538
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1539
  });
1540
 
88
  tables_not_found = $('#wpoptimize_table_list_tables_not_found');
89
 
90
  // table sorter library.
91
+
92
  // This calls the tablesorter library in order to sort the table information correctly.
93
  // There is a fix below on line 172 to apply applyWidgets on load to avoid diplay hidden for tabs.
94
  $(function() {
95
+ // add parser through the tablesorter addParser method
96
+ $.tablesorter.addParser({
97
+ // set a unique id
98
+ id: 'sizes',
99
+ is: function(s) {
100
+ // return false so this parser is not auto detected
101
+ return false;
102
+ },
103
+ format: function(s) {
104
+ // format your data for normalization
105
+ var kb = 1024,
106
+ mb = kb * 1024,
107
+ gb = mb * 1024;
108
+
109
+ return eval(s.toLowerCase().replace(/kb/,['* ', kb].join('')).replace(/mb/,['* ', mb].join('')).replace(/gb/,['* ', gb].join('')).replace(/[^0-9\.\*\s]/g, ''));
110
+ },
111
+ // set type, either numeric or text
112
+ type: 'numeric'
113
+ });
114
+
115
  table_list.tablesorter({
116
  theme: 'default',
117
  widgets: ['zebra', 'rows', 'filter'],
119
  // This option is to specify with colums will be disabled for sorting
120
  headers: {
121
  2: {sorter: 'digit'},
122
+ 3: {sorter: 'sizes'},
123
+ 4: {sorter: 'sizes'},
124
  // For Column Action
125
  7: {sorter: false }
126
  },
166
  function temporarily_display_notice(html_contents, where, delay) {
167
  where = ('undefined' === typeof where) ? '#wp-optimize-wrap' : where;
168
  delay = ('undefined' === typeof delay) ? 15 : delay;
169
+ $(html_contents).hide().prependTo(where).slideDown('fast').delay(delay * 1000).slideUp('fast', function () {
170
  $(this).remove();
171
  });
172
  }
194
 
195
  if (resp && resp.hasOwnProperty('output')) {
196
  for (var i = 0, len = resp.output.length; i < len; i++) {
197
+ var new_html = '<div class="updated"><p>' + resp.output[i] + '</p></div>';
198
+ temporarily_display_notice(new_html, '#' + type + '_notice');
199
  }
200
  }
201
  });
217
  enable_or_disable_feature('comments', false);
218
  });
219
 
220
+ // Main menu
221
+ $('.wpo-pages-menu').on('click', 'a', function(e) {
222
+ e.preventDefault();
223
+ if (!$(this).is('.active')) {
224
+ $('.wpo-pages-menu a.active').removeClass('active');
225
+ $('.wpo-page.active').removeClass('active');
226
+ $(this).addClass('active');
227
+ $('.wpo-page[data-whichpage="' + $(this).data('menuslug') + '"]').addClass('active');
228
+ window.scroll(0, 0);
229
+ }
230
+ // Close the menu on mobile
231
+ $('#wp-optimize-nav-page-menu').trigger('click');
232
 
233
+ });
 
234
 
235
+ // Tabs menu
236
+ $('.nav-tab-wrapper .nav-tab').click(function (e) {
237
 
238
  e.preventDefault();
239
 
240
+ var clicked_tab_id = $(this).attr('id'),
241
+ container = $(this).closest('.nav-tab-wrapper');
242
 
243
+ if (!clicked_tab_id) { return; }
 
244
 
245
+ toggle_mobile_menu(false);
246
+ // Mobile menu TABS toggle
247
+ if ($(this).is('[role="toggle-menu"]')) {
248
+ toggle_mobile_menu(true);
249
+ return;
 
 
250
  }
251
+
252
+ container.find('.nav-tab:not(#wp-optimize-nav-tab-' + clicked_tab_id + ')').removeClass('nav-tab-active');
253
+
254
+ $(this).addClass('nav-tab-active');
255
+ $(this).closest('.wpo-page').find('.wp-optimize-nav-tab-contents').hide();
256
+ $('#' + clicked_tab_id + '-contents').show();
257
  });
258
 
259
+ // Mobile menu toggle
260
+ $('#wp-optimize-nav-page-menu').on('click', function(e) {
261
+ e.preventDefault();
262
+ $(this).toggleClass('opened');
263
+ });
264
+
265
+ /**
266
+ * Toggle Mobile menu
267
+ *
268
+ * @param {bool} open
269
+ *
270
+ * @return {void}
271
+ */
272
+ function toggle_mobile_menu(open) {
273
+ if (open) {
274
+ $('#wp-optimize-wrap').addClass('wpo-mobile-menu-opened');
275
+ } else {
276
+ $('#wp-optimize-wrap').removeClass('wpo-mobile-menu-opened');
277
+ }
278
+ }
279
 
280
  /**
281
  * Gathers the settings from the settings tab and return in selected format.
289
  output_format = ('undefined' === typeof output_format) ? 'string' : output_format;
290
 
291
  if ('object' == output_format) {
292
+ form_data = $("#wp-optimize-general-settings form input[name!='action'], #wp-optimize-general-settings form textarea, #wp-optimize-general-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serializeJSON({useIntKeysAsArrayIndex: true});
293
  } else {
294
  // Excluding the unnecessary 'action' input avoids triggering a very mis-conceived mod_security rule seen on one user's site.
295
+ form_data = $("#wp-optimize-general-settings form input[name!='action'], #wp-optimize-general-settings form textarea, #wp-optimize-general-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serialize();
296
 
297
  // Include unchecked checkboxes. user filter to only include unchecked boxes.
298
+ $.each($('#wp-optimize-general-settings form input[type=checkbox], .wp-optimize-nav-tab-contents input[name^="enable-auto-backup-"]')
299
  .filter(function (idx) {
300
  return $(this).prop('checked') == false
301
  }),
546
  /**
547
  * Run single optimization click.
548
  */
549
+ $('#wp-optimize-nav-tab-wpo_database-optimize-contents').on('click', 'button.wp-optimize-settings-optimization-run-button', function () {
550
  var optimization_id = $(this).closest('.wp-optimize-settings').data('optimization_id');
551
  if (!optimization_id) {
552
  console.log("Optimization ID corresponding to pressed button not found");
566
  /**
567
  * Run all optimizations click.
568
  */
569
+ $('#wp-optimize-nav-tab-wpo_database-optimize-contents').on('click', '#wp-optimize', function (e) {
570
  var run_btn = $(this);
571
 
572
  e.preventDefault();
637
  send_command('save_auto_backup_option', options);
638
  }
639
 
640
+ var browser_cache_enable_btn = $('#wp_optimize_browser_cache_enable');
641
+
642
+ /**
643
+ * Trigger click Browser cache button if user push Enter and form start submitting.
644
+ */
645
+ browser_cache_enable_btn.closest('form').submit(
646
+ function(e) {
647
+ e.preventDefault();
648
+ browser_cache_enable_btn.trigger('click');
649
+ return false;
650
+ }
651
+ );
652
+
653
+ /**
654
+ * Handle Enable Gzip compression button click.
655
+ */
656
+ $('#wp_optimize_gzip_compression_enable').on('click', function() {
657
+ var button = $(this),
658
+ loader = button.next();
659
+
660
+ loader.show();
661
+
662
+ send_command('enable_gzip_compression', {enable: button.data('enable')}, function(response) {
663
+ var gzip_status_message = $('#wpo_gzip_compression_status');
664
+ if (response) {
665
+ if (response.enabled) {
666
+ button.text(wpoptimize.disable);
667
+ button.data('enable', '0');
668
+ gzip_status_message.removeClass('wpo-disabled').addClass('wpo-enabled');
669
+ } else {
670
+ button.text(wpoptimize.enable);
671
+ button.data('enable', '1');
672
+ gzip_status_message.addClass('wpo-disabled').removeClass('wpo-enabled');
673
+ }
674
+
675
+ if (response.message) {
676
+ $('#wpo_gzip_compression_error_message').text(response.message).show();
677
+ } else {
678
+ $('#wpo_gzip_compression_error_message').hide();
679
+ }
680
+
681
+ if (response.output) {
682
+ $('#wpo_gzip_compression_output').html(response.output).show();
683
+ } else {
684
+ $('#wpo_gzip_compression_output').hide();
685
+ }
686
+
687
+ } else {
688
+ alert(wpoptimize.error_unexpected_response);
689
+ }
690
+
691
+ loader.hide();
692
+ }).fail(function() {
693
+ alert(wpoptimize.error_unexpected_response);
694
+ loader.hide();
695
+ });
696
+ });
697
+
698
+ /**
699
+ * Handle Enable browser cache button click.
700
+ */
701
+ browser_cache_enable_btn.on('click', function() {
702
+ var browser_cache_expire_days_el = $('#wpo_browser_cache_expire_days'),
703
+ browser_cache_expire_hours_el = $('#wpo_browser_cache_expire_hours'),
704
+ browser_cache_expire_days = parseInt(browser_cache_expire_days_el.val(), 10),
705
+ browser_cache_expire_hours = parseInt(browser_cache_expire_hours_el.val(), 10),
706
+ button = $(this),
707
+ loader = button.next();
708
+
709
+ // check for invalid integer.
710
+ if (isNaN(browser_cache_expire_days)) browser_cache_expire_days = 0;
711
+ if (isNaN(browser_cache_expire_hours)) browser_cache_expire_hours = 0;
712
+
713
+ if (browser_cache_expire_days < 0 || browser_cache_expire_hours < 0) {
714
+ $('#wpo_browser_cache_error_message').text(wpoptimize.please_use_positive_integers).show();
715
+ return false;
716
+ } else if (browser_cache_expire_hours > 23) {
717
+ $('#wpo_browser_cache_error_message').text(wpoptimize.please_use_valid_values).show();
718
+ return false;
719
+ } else {
720
+ $('#wpo_browser_cache_error_message').hide();
721
+ }
722
+
723
+ // set parsed values into input fields.
724
+ browser_cache_expire_days_el.val(browser_cache_expire_days);
725
+ browser_cache_expire_hours_el.val(browser_cache_expire_hours);
726
+
727
+ loader.show();
728
+
729
+ send_command('enable_browser_cache', {browser_cache_expire_days: browser_cache_expire_days, browser_cache_expire_hours: browser_cache_expire_hours}, function(response) {
730
+ var cache_status_message = $('#wpo_browser_cache_status');
731
+ if (response) {
732
+ if (response.enabled) {
733
+ button.text(wpoptimize.update);
734
+ cache_status_message.removeClass('wpo-disabled').addClass('wpo-enabled');
735
+ } else {
736
+ button.text(wpoptimize.enable);
737
+ cache_status_message.addClass('wpo-disabled').removeClass('wpo-enabled');
738
+ }
739
+
740
+ if (response.message) {
741
+ $('#wpo_browser_cache_message').text(response.message).show();
742
+ } else {
743
+ $('#wpo_browser_cache_message').hide();
744
+ }
745
+
746
+ if (response.error_message) {
747
+ $('#wpo_browser_cache_error_message').text(response.error_message).show();
748
+ } else {
749
+ $('#wpo_browser_cache_error_message').hide();
750
+ }
751
+
752
+ if (response.output) {
753
+ $('#wpo_browser_cache_output').html(response.output).show();
754
+ } else {
755
+ $('#wpo_browser_cache_output').hide();
756
+ }
757
+
758
+ } else {
759
+ alert(wpoptimize.error_unexpected_response);
760
+ }
761
+
762
+ loader.hide();
763
+ }).fail(function() {
764
+ alert(wpoptimize.error_unexpected_response);
765
+ loader.hide();
766
+ });
767
+ });
768
+
769
  // Show/hide sites list for multi-site settings.
770
  var wpo_settings_sites_list = $('#wpo_settings_sites_list'),
771
  wpo_settings_sites_list_ul = wpo_settings_sites_list.find('ul').first(),
935
  send_command('save_manual_run_optimization_options', optimization_options);
936
  }
937
 
938
+ $('#wp_optimize_table_list_refresh').click(function (e) {
939
+
940
+ e.preventDefault();
941
 
942
  $('#wpoptimize_table_list tbody').css('opacity', '0.5');
943
  send_command('get_table_list', false, function (response) {
960
 
961
  $('#settings_form').on('click', '#wp-optimize-settings-save', function (e) {
962
 
963
+ e.preventDefault();
964
+
965
  // validate logger settings.
966
  if (!validate_logger_settings()) return false;
967
 
968
+ console.log('What?');
 
969
  $('#save_spinner').show();
970
 
971
  var form_data = gather_settings();
1025
 
1026
  // Handle single optimization click.
1027
  $('#wpoptimize_table_list').on('click', '.run-single-table-optimization', function() {
1028
+ var take_backup_checkbox = $('#enable-auto-backup-1');
1029
+
1030
+ // check if backup checkbox is checked for db tables
1031
+ if (take_backup_checkbox.is(':checked')) {
1032
+ take_a_backup_with_updraftplus(run_single_table_optimization($(this)));
1033
+ } else {
1034
+ run_single_table_optimization($(this));
1035
+ }
1036
+ });
1037
+
1038
+ /**
1039
+ * Run single table optimization. Handle click on Optimize button.
1040
+ *
1041
+ * @param {Object} btn jQuery object clicked Optimize button
1042
+ *
1043
+ * @return {void}
1044
+ */
1045
+ function run_single_table_optimization(btn) {
1046
+ var spinner = btn.next(),
1047
  action_done_icon = spinner.next(),
1048
  table_name = btn.data('table'),
1049
  table_type = btn.data('type'),
1052
  optimization_table: table_name,
1053
  optimization_table_type: table_type
1054
  };
1055
+ btn.hide();
1056
  // if checked force button then send force value.
1057
  if (single_table_optimization_force.is(':checked')) {
1058
  data['optimization_force'] = true;
1063
  send_command('do_optimization', { optimization_id: 'optimizetables', data: data }, function () {
1064
  btn.prop('disabled', false);
1065
  spinner.addClass('visibility-hidden');
1066
+ action_done_icon.show().removeClass('visibility-hidden').delay(2500).fadeOut('fast', function() {
1067
+ btn.show();
1068
+ });
1069
  });
1070
+ }
1071
 
1072
  // Handle force optimization checkbox on table list tab.
1073
  single_table_optimization_force.change(function() {
1368
  });
1369
  });
1370
 
1371
+ // Handle delete table click
1372
+ $('#wpoptimize_table_list').on('click', '.run-single-table-delete', function() {
1373
+ if (!confirm(wpoptimize.are_you_sure_you_want_to_remove_this_table)) return false;
1374
+
1375
+ var take_backup_checkbox = $('#enable-auto-backup-1');
1376
+
1377
+ // check if backup checkbox is checked for db tables
1378
+ if (take_backup_checkbox.is(':checked')) {
1379
+ take_a_backup_with_updraftplus(remove_single_db_table($(this)));
1380
+ } else {
1381
+ take_backup_checkbox();
1382
+ }
1383
+ });
1384
+
1385
+ /**
1386
+ * Send ajax commant to remove single database table.
1387
+ *
1388
+ * @param {Object} btn jQuery object of clicked "Remove" button.
1389
+ *
1390
+ * @return void
1391
+ */
1392
+ function remove_single_db_table(btn) {
1393
+
1394
+ var spinner = btn.next(),
1395
+ action_done_icon = spinner.next(),
1396
+ table_name = btn.data('table'),
1397
+ data = {
1398
+ optimization_id: 'orphanedtables',
1399
+ optimization_table: table_name
1400
+ };
1401
+
1402
+ spinner.removeClass('visibility-hidden');
1403
+
1404
+ send_command('do_optimization', { optimization_id: 'orphanedtables', data: data }, function (response) {
1405
+ if (response.result.meta.success) {
1406
+ var row = btn.closest('tr');
1407
+
1408
+ btn.prop('disabled', false);
1409
+ spinner.addClass('visibility-hidden');
1410
+ action_done_icon.show().removeClass('visibility-hidden');
1411
+
1412
+ // remove row for deleted table.
1413
+ setTimeout(function() {
1414
+ row.fadeOut('slow', function() {
1415
+ row.remove();
1416
+
1417
+ change_actions_column_visibility();
1418
+ });
1419
+ }, 500);
1420
+ } else {
1421
+ btn.prop('disabled', false);
1422
+ spinner.addClass('visibility-hidden');
1423
+ alert(wpoptimize.table_was_not_deleted.replace('%s', table_name));
1424
+ }
1425
+ });
1426
+ }
1427
+
1428
  change_actions_column_visibility();
1429
 
1430
  /**
1591
  /**
1592
  * Handle add logging destination click.
1593
  */
1594
+ add_logging_btn.on('click', function(e) {
1595
+ e.preventDefault();
1596
  $('#wp-optimize-logger-settings .save_settings_reminder').after(get_add_logging_form_html());
1597
 
1598
  filter_select_destinations($('.wpo_logger_type').first());
1601
  /**
1602
  * Handle logging destination select change.
1603
  */
1604
+ $('#wp-optimize-general-settings').on('change', '.wpo_logger_type', function() {
1605
  var select = $(this),
1606
  logger_id = select.val(),
1607
  options_container = select.parent().find('.wpo_additional_logger_options');
1659
  /**
1660
  * Handle delete logger destination click.
1661
  */
1662
+ $('#wp-optimize-general-settings').on('click', '.wpo_delete_logger', function() {
1663
 
1664
  if (!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination)) {
1665
  return false;
1796
 
1797
  return options_list.join('');
1798
  }
1799
+
1800
+ /**
1801
+ * Layout - Adds `is-scrolled` class to the body element when scrolled.
1802
+ */
1803
+ var is_scrolled = false;
1804
+ $(window).on('scroll', function(e) {
1805
+ window.requestAnimationFrame(function() {
1806
+ var threshold = $('.wpo-main-header').length ? $('.wpo-main-header')[0].offsetTop : 0;
1807
+ if ((window.pageYOffset > threshold - 20) != is_scrolled) {
1808
+ is_scrolled = !is_scrolled;
1809
+ $('body').toggleClass('is-scrolled', is_scrolled);
1810
+ }
1811
+ });
1812
+ });
1813
  });
1814
 
js/wpadmin.min.js CHANGED
@@ -1 +1 @@
1
- wp_optimize_send_command_admin_ajax=function(t,i,e,o){o="undefined"==typeof o||o;var n={action:"wp_optimize_ajax",subaction:t,nonce:wp_optimize_ajax_nonce,data:i};return jQuery.post(ajaxurl,n,function(t){if(o){try{var i=JSON.parse(t)}catch(n){return console.log(n),console.log(t),void alert(wpoptimize.error_unexpected_response)}"undefined"!=typeof e&&e(i)}else"undefined"!=typeof e&&e(t)})},jQuery(document).ready(function(t){WP_Optimize=WP_Optimize(wp_optimize_send_command_admin_ajax)});var WP_Optimize=function(t){function i(){if(j("#enable-schedule").length){var t=j("#enable-schedule").is(":checked");t?j("#wp-optimize-auto-options").css("opacity","1"):j("#wp-optimize-auto-options").css("opacity","0.5")}}function e(t,i,e){i="undefined"==typeof i?"#wp-optimize-wrap":i,e="undefined"==typeof e?15:e,j(t).hide().prependTo(i).slideDown("slow").delay(1e3*e).slideUp("slow",function(){j(this).remove()})}function o(i,o){var n={type:i,enable:o?1:0};j("#"+i+"_spinner").show(),t("enable_or_disable_feature",n,function(t){if(j("#"+i+"_spinner").hide(),t&&t.hasOwnProperty("output"))for(var o=0,n=t.output.length;o<n;o++){var a='<div class="updated">'+t.output[o]+"</div>";e(a,"#actions-results-area")}})}function n(t){var i="",t="undefined"==typeof t?"string":t;return"object"==t?i=j("#wp-optimize-nav-tab-contents-settings form input[name!='action'], #wp-optimize-nav-tab-contents-settings form textarea, #wp-optimize-nav-tab-contents-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serializeJSON({useIntKeysAsArrayIndex:!0}):(i=j("#wp-optimize-nav-tab-contents-settings form input[name!='action'], #wp-optimize-nav-tab-contents-settings form textarea, #wp-optimize-nav-tab-contents-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serialize(),j.each(j('#wp-optimize-nav-tab-contents-settings form input[type=checkbox], .wp-optimize-nav-tab-contents input[name^="enable-auto-backup-"]').filter(function(t){return 0==j(this).prop("checked")}),function(t,e){var o="0";i+="&"+j(e).attr("name")+"="+o})),i}function a(){t("optimizations_done",{},function(){})}function s(){if(!P.get_lock())return void(O>0&&console.log("WP-Optimize: process_queue(): queue is currently locked - exiting"));O>0&&console.log("WP-Optimize: process_queue(): got queue lock");var i=P.peek();return"object"==typeof i?(data=i,i=i.optimization_id):data={},"undefined"==typeof i?(O>0&&console.log("WP-Optimize: process_queue(): queue is apparently empty - exiting"),P.unlock(),void a()):(O>0&&console.log("WP-Optimize: process_queue(): processing item: "+i),P.dequeue(),j(document).trigger(["do_optimization_",i,"_start"].join("")),void t("do_optimization",{optimization_id:i,data:data},function(t){if(j("#optimization_spinner_"+i).hide(),j("#optimization_checkbox_"+i).show(),j(".optimization_button_"+i).prop("disabled",!1),j(document).trigger(["do_optimization_",i,"_done"].join(""),t),t){for(var e="",o=0,n=t.errors.length;o<n;o++)e+='<span class="error">'+t.errors[o]+"</span><br>";for(var o=0,n=t.messages.length;o<n;o++)e+=t.errors[o]+"<br>";for(var o=0,n=t.result.output.length;o<n;o++)e+=t.result.output[o]+"<br>";if(j("#optimization_info_"+i).html(e),t.hasOwnProperty("status_box_contents")&&j("#wp_optimize_status_box").css("opacity","1").find(".inside").html(t.status_box_contents),t.hasOwnProperty("table_list")&&j("#wpoptimize_table_list tbody").html(j(t.table_list).find("tbody").html()),t.hasOwnProperty("total_size")&&j("#optimize_current_db_size").html(t.total_size),"optimizetables"==i&&data.optimization_table&&(P.is_empty()?(j("#optimization_spinner_"+i).hide(),j("#optimization_checkbox_"+i).show(),j(".optimization_button_"+i).prop("disabled",!1),j("#optimization_info_"+i).html(wpoptimize.optimization_complete)):(j("#optimization_checkbox_"+i).hide(),j("#optimization_spinner_"+i).show(),j(".optimization_button_"+i).prop("disabled",!0))),t.result.meta&&t.result.meta.hasOwnProperty("awaiting_mod")){var a=t.result.meta.awaiting_mod;a>0?j("#adminmenu .awaiting-mod .pending-count").remove(a):j("#adminmenu .awaiting-mod").remove()}}setTimeout(function(){P.unlock(),s()},10)}))}function p(t){var i=j("#wp-optimize-nav-tab-contents-optimize .wp-optimize-settings-"+t);i||console.log("do_optimization: row corresponding to this optimization ("+t+") not found");var e={},o=0;if(j('input[type="checkbox"]',j("#optimization_info_"+t)).each(function(){var t=j(this);t.is(":checked")&&(e[t.attr("name")]=t.val(),o++)}),1!=j(".optimization_button_"+t).prop("disabled")){if(j("#optimization_checkbox_"+t).hide(),j("#optimization_spinner_"+t).show(),j(".optimization_button_"+t).prop("disabled",!0),j("#optimization_info_"+t).html("..."),"optimizetables"==t){var n=j("#wpoptimize_table_list #the-list tr");j(n).each(function(i){var e=j(this).find("td");if(table_type=e.eq(5).text(),table=e.eq(1).text(),optimizable=e.eq(5).data("optimizable"),""!=table&&("1"==optimizable||K)){var o={optimization_id:t,optimization_table:e.eq(1).text(),optimization_table_type:table_type,optimization_force:K};P.enqueue(o)}})}else if(o>0){data={optimization_id:t};for(var a in e)e.hasOwnProperty(a)&&(data[a]=e[a]);P.enqueue(data)}else P.enqueue(t);s()}}function r(i){j("#wpo_settings_sites_list").length?t("save_site_settings",{"wpo-sites":l()},function(){i&&i()}):i&&i()}function l(){var t=[];return j('#wpo_settings_sites_list input[type="checkbox"]').each(function(){var i=j(this);i.is(":checked")&&t.push(i.attr("value"))}),t}function _(){var t=!1;j("#enable-auto-backup").is(":checked")&&(t=!0),d(),1==t?c(g):g()}function c(t){"function"==typeof updraft_backupnow_inpage_go?updraft_backupnow_inpage_go(function(){j("#updraft-backupnow-inpage-modal").dialog("close"),t&&t()},"","autobackup",0,1,0,wpoptimize.automatic_backup_before_optimizations):t&&t()}function d(){var i=n("object");i.auto_backup=j("#enable-auto-backup").is(":checked"),t("save_auto_backup_option",i)}function u(t,i,e,o){t.on("click",function(){return i.hasClass("wpo_always_visible")||i.toggleClass("wpo_hidden"),!1}),m(e,o)}function m(t,i){t.on("change",function(){t.is(":checked")?i.prop("checked",!0):i.prop("checked",!1),f(t,i)}),i.on("change",function(){f(t,i)}),f(t,i)}function f(t,i){var e=0,o=0;if(i.each(function(){j(this).is(":checked")&&o++,e++}),t.next().is("label")&&t.next().data("label")){var n=t.next(),a=n.data("label");e==o?n.text(a):n.text(a.replace("all",[o," of ",e].join("")))}e==o?t.prop("checked",!0):t.prop("checked",!1)}function g(){$optimizations=j("#optimizations_list .optimization_checkbox:checked"),$optimizations.sort(function(t,i){return t=j(t).closest(".wp-optimize-settings").data("optimization_run_sort_order"),i=j(i).closest(".wp-optimize-settings").data("optimization_run_sort_order"),t>i?1:t<i?-1:0});var i={};$optimizations.each(function(t){var e=j(this).closest(".wp-optimize-settings").data("optimization_id");return e?(i[e]={active:1},void p(e)):void console.log("Optimization ID corresponding to pressed button not found")}),t("save_manual_run_optimization_options",i)}function w(t){j(".run-single-table-optimization").each(function(){var i=j(this);i.data("disabled")&&(t?i.prop("disabled",!1):i.prop("disabled",!0))})}function b(t){var i,e,o;if(t)for(i in t)t.hasOwnProperty(i)&&(e=["#wp-optimize-settings-",t[i].dom_id].join(""),o=t[i].info?t[i].info.join("<br>"):"",j(e+" .wp-optimize-settings-optimization-info").html(o))}function h(){var i=["",l().join("_")].join("");H.hasOwnProperty(i)?b(H[i]):t("get_optimizations_info",{"wpo-sites":l()},function(t){t&&(H[i]=t,b(t))})}function z(i){var e=j("#wpo_import_spinner"),o=j("#wpo_import_success_message"),n=j("#wpo_import_error_message");e.show(),t("import_settings",{settings:i},function(t){e.hide(),t&&t.errors&&t.errors.length?(n.text(t.errors.join("<br>")),n.slideDown()):t&&t.messages&&t.messages.length&&(o.text(t.messages.join("<br>")),o.slideDown(),setTimeout(function(){window.location.reload()},500)),j("#wpo_import_settings_btn").prop("disabled",!1)})}function v(t,i){var e=document.body.appendChild(document.createElement("a")),o=new Date,n=o.getFullYear(),a=o.getMonth()<10?["0",o.getMonth()].join(""):o.getMonth(),s=o.getDay()<10?["0",o.getDay()].join(""):o.getDay();i=i?i:["wpo-settings-",n,"-",a,"-",s,".json"].join(""),e.setAttribute("download",i),e.setAttribute("style","display:none;"),e.setAttribute("href","data:text/json;charset=UTF-8,"+encodeURIComponent(JSON.stringify(t))),e.click()}function y(){var t=j("#wpoptimize_table_list"),i=!0;j("tr",t).each(function(){var t=j(this);if(j("button",t).length>0)return i=!1,!1}),j("tr",t).each(function(){var t=j(this);i?j("td:last, th:last",t).hide():j("td:last, th:last",t).show()})}function k(){var t=!0;return j(".wpo_logger_addition_option, .wpo_logger_type").each(function(){x(j(this),!0)?j(this).removeClass("wpo_error_field"):(t=!1,j(this).addClass("wpo_error_field"))}),t?j("#wp-optimize-logger-settings .save_settings_reminder").slideUp():j("#wp-optimize-settings-save-results").show().addClass("wpo_alert_notice").text(wpoptimize.fill_all_settings_fields).delay(5e3).fadeOut(3e3,function(){j(this).removeClass("wpo_alert_notice")}),t}function x(t,i){var e=t.val(),o=t.data("validate");if(!o&&i)return""!=j.trim(e);if(o&&!i&&""==j.trim(e))return!0;var n=!0;switch(o){case"email":for(var a=/\S+@\S+\.\S+/,s=e.split(","),p="",r=0;r<s.length;r++)p=j.trim(s[r]),""!=p&&a.test(p)||(n=!1);break;case"url":var a=/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[\/?#]\S*)?$/i;n=a.test(e)}return n}var j=jQuery,O=0,P=new Updraft_Queue;m(j("#select_all_optimizations"),j("#optimizations_list .optimization_checkbox")),i(),j("#enable-schedule").change(function(){i()});var q=j("#wpoptimize_table_list_filter"),C=j("#wpoptimize_table_list"),D=j("#wpoptimize_table_list tbody:last"),S=j("#wpoptimize_table_list_tables_not_found");j(function(){C.tablesorter({theme:"default",widgets:["zebra","rows","filter"],cssInfoBlock:"tablesorter-no-sort",headers:{2:{sorter:"digit"},3:{sorter:"digit"},4:{sorter:"digit"},7:{sorter:!1}},widgetOptions:{filter_external:q,filter_defaultFilter:{2:"~{query}"}}}),C.on("filterEnd",function(){var t=j.trim(q.val());""==t?D.show():D.hide(),0==j("#the-list tr:visible",C).length?S.show():S.hide()})}),j("#wp-optimize-disable-enable-trackbacks-enable").click(function(){o("trackbacks",!0)}),j("#wp-optimize-disable-enable-trackbacks-disable").click(function(){o("trackbacks",!1)}),j("#wp-optimize-disable-enable-comments-enable").click(function(){o("comments",!0)}),j("#wp-optimize-disable-enable-comments-disable").click(function(){o("comments",!1)}),j("#wp-optimize-nav-tab-wrapper .nav-tab, #wp-optimize-images-nav-tab-wrapper .nav-tab").click(function(t){var i=j(this).attr("id"),e=j(this).closest(".nav-tab-wrapper").attr("id"),o=e.substring(0,e.length-7);if(i&&o==i.substring(0,o.length)){var i=i.substring(o.length);t.preventDefault(),j("#"+e+" .nav-tab:not(#wp-optimize-nav-tab-"+i+")").removeClass("nav-tab-active"),j(this).addClass("nav-tab-active"),j("#wp-optimize-wrap ."+o+"contents:not(#"+o+"contents-"+i+")").hide(),j("#"+o+"contents-"+i).show(),"tables"==i&&j("#wpoptimize_table_list").trigger("applyWidgets")}}),j("#wp-optimize-nav-tab-contents-optimize").on("click","button.wp-optimize-settings-optimization-run-button",function(){var t=j(this).closest(".wp-optimize-settings").data("optimization_id");return t?void(1!=j(".optimization_button_"+t).prop("disabled")&&(j(".optimization_button_"+t).prop("disabled",!0),r(function(){j(".optimization_button_"+t).prop("disabled",!1),p(t)}))):void console.log("Optimization ID corresponding to pressed button not found")}),j("#wp-optimize-nav-tab-contents-optimize").on("click","#wp-optimize",function(t){var i=j(this);t.preventDefault(),i.prop("disabled",!0),r(function(){i.prop("disabled",!1),_()})});var T=j("#wpo_settings_sites_list"),W=T.find("ul").first(),A=j('input[type="checkbox"]',W),F=T.find("#wpo_all_sites"),I=j("#wpo_sitelist_show_moreoptions"),U=j("#wpo_sitelist_moreoptions"),Q=j("#wpo_settings_sites_list_cron"),$=Q.find("ul").first(),J=j('input[type="checkbox"]',$),M=Q.find("#wpo_all_sites_cron"),N=j("#wpo_sitelist_show_moreoptions_cron"),E=j("#wpo_sitelist_moreoptions_cron");u(I,U,F,A);var R=0;j([F,A]).each(function(){j(this).on("change",function(){R++,setTimeout(function(){R--,0==R&&h()},1e3)})}),u(N,E,M,J),j("#wp_optimize_table_list_refresh").click(function(){j("#wpoptimize_table_list tbody").css("opacity","0.5"),t("get_table_list",!1,function(t){if(t.hasOwnProperty("table_list")){var i=!0,e=function(t){j("#wpoptimize_table_list tbody").css("opacity","1")};j("#wpoptimize_table_list").trigger("updateAll",[i,e])}t.hasOwnProperty("total_size")&&j("#optimize_current_db_size").html(t.total_size),w(G.is(":checked"))})}),j("#settings_form").on("click","#wp-optimize-settings-save",function(i){if(!k())return!1;i.preventDefault(),j("#save_spinner").show();var o=n();t("save_settings",o,function(t){if(j("#save_spinner").hide(),j("#save_done").show().delay(5e3).fadeOut(),t&&t.hasOwnProperty("save_results")&&t.save_results&&t.save_results.hasOwnProperty("errors")){for(var i=0,o=t.save_results.errors.length;i<o;i++){var n='<div class="error">'+t.errors[i]+"</div>";e(n,"#wp-optimize-settings-save-results")}console.log(t.save_results.messages)}t&&t.hasOwnProperty("status_box_contents")&&j("#wp_optimize_status_box .inside").html(t.status_box_contents),t&&t.hasOwnProperty("optimizations_table")&&j("#optimizations_list").replaceWith(t.optimizations_table),t.save_results.refresh&&location.reload()})}),j("#wp_optimize_status_box").on("click","#wp_optimize_status_box_refresh",function(i){i.preventDefault(),j("#wp_optimize_status_box").css("opacity","0.5"),t("get_status_box_contents",null,function(t){j("#wp_optimize_status_box").css("opacity","1").find(".inside").html(t)})});var B=j("#innodb_force_optimize"),K=B.is(":checked"),Y=B.closest("tr"),G=j("#innodb_force_optimize_single");B.on("change",function(){j('button, input[type="checkbox"]',Y).each(function(){K=B.is(":checked");var t=j(this);t.data("disabled")&&(K?t.prop("disabled",!1):t.prop("disabled",!0))})}),j("#wpoptimize_table_list").on("click",".run-single-table-optimization",function(){var i=j(this),e=i.next(),o=e.next(),n=i.data("table"),a=i.data("type"),s={optimization_id:"optimizetables",optimization_table:n,optimization_table_type:a};G.is(":checked")&&(s.optimization_force=!0),e.removeClass("visibility-hidden"),t("do_optimization",{optimization_id:"optimizetables",data:s},function(){i.prop("disabled",!1),e.addClass("visibility-hidden"),o.show().removeClass("visibility-hidden").delay(3e3).fadeOut("slow")})}),G.change(function(){w(G.is(":checked"))}),w(G.is(":checked"));var H={};setTimeout(function(){t("check_overdue_crons",null,function(t){t&&t.hasOwnProperty("m")&&j("#wpo_settings_warnings").append(t.m)})},11e3),j("#wpo_import_settings_btn").on("click",function(t){var i=j("#wpo_import_settings_file"),e=i.val(),o=i[0].files[0],n=new FileReader;return j("#wpo_import_settings_btn").prop("disabled",!0),/\.json$/.test(e)?(n.onload=function(){z(this.result)},n.readAsText(o),!1):(t.preventDefault(),j("#wpo_import_settings_btn").prop("disabled",!1),j("#wpo_import_error_message").text(wpoptimize.please_select_settings_file).slideDown(),!1)}),j("#wpo_import_settings_file").on("change",function(){j("#wpo_import_error_message").slideUp()}),j("#wpo_export_settings_btn").on("click",function(t){return v(n("object")),!1});var L=function(i,e,o){return t("get_optimization_info",{optimization_id:e,data:o},function(t){var o=t&&t.result&&t.result.meta?t.result.meta:{},n=t&&t.result&&t.result.output?t.result.output.join("<br>"):"...";j(document).trigger(["optimization_get_info_",e].join(""),n),i.html(n),o.finished?j(document).trigger(["optimization_get_info_",e,"_done"].join(""),t):setTimeout(function(){L(i,e,o)},1)})};return j(document).ready(function(){j(".wp-optimize-optimization-info-ajax").each(function(){var t=j(this),i=t.parent(),e=t.data("id");j(document).trigger(["optimization_get_info_",e,"_start"].join("")),L(i,e,{support_ajax_get_info:!0})})}),j("#wpoptimize_table_list").on("click",".run-single-table-repair",function(){var i=j(this),e=i.next(),o=e.next(),n=i.data("table"),a={optimization_id:"repairtables",optimization_table:n};e.removeClass("visibility-hidden"),t("do_optimization",{optimization_id:"repairtables",data:a},function(t){if(t.result.meta.success){var a=i.closest("tr"),s=t.result.meta.tableinfo;i.prop("disabled",!1),e.addClass("visibility-hidden"),o.show().removeClass("visibility-hidden"),j("td:eq(2)",a).text(s.rows),j("td:eq(3)",a).text(s.data_size),j("td:eq(4)",a).text(s.index_size),j("td:eq(5)",a).text(s.type),s.is_optimizable?j("td:eq(6)",a).html(['<span color="',s.overhead>0?"#0000FF":"#004600",'">',s.overhead,"</span>"].join("")):j("td:eq(6)",a).html('<span color="#0000FF">-</span>'),setTimeout(function(){var t=i.closest("td"),e=i.closest(".wpo_button_wrap");e.fadeOut("fast",function(){e.closest(".wpo_button_wrap").remove(),s.is_optimizable&&j(".wpo_button_wrap",t).removeClass("wpo_hidden")}),y()},1e3)}else i.prop("disabled",!1),e.addClass("visibility-hidden"),alert(wpoptimize.table_was_not_repaired.replace("%s",n))})}),y(),setTimeout(function(){t("check_overdue_crons",null,function(t){t&&t.hasOwnProperty("m")&&j("#wpo_settings_warnings").append(t.m)})},11e3),{send_command:t,optimization_get_info:L,take_a_backup_with_updraftplus:c,save_auto_backup_options:d}};jQuery(document).ready(function(t){function i(i){var e=["#",i.data("additional")].join("");i.is(":checked")?t(e).show():t(e).hide()}function e(){var i=t("#wp-optimize-logger-settings .save_settings_reminder");i.is(":visible")||i.slideDown("normal")}function o(){t(".wpo_logger_type").each(function(){n(t(this))})}function n(i){var e,o,n=a();for(e in n)o=n[e],wpoptimize.loggers_classes_info[o].allow_multiple?t('option[value="'+o+'"]',i).show():t('option[value="'+o+'"]',i).hide()}function a(){var i=[];return t(".wpo_logging_row, .wpo_logger_type").each(function(){var e=t(this).is("select")?t(this).val():t(this).data("id");e&&i.push(e)}),i}function s(){var t,i=['<option value="">Select destination</option>'];for(t in wpoptimize.loggers_classes_info)wpoptimize.loggers_classes_info.hasOwnProperty(t)&&wpoptimize.loggers_classes_info[t].available&&i.push(['<option value="',t,'">',wpoptimize.loggers_classes_info[t].description,"</option>"].join(""));return['<div class="wpo_add_logger_form">','<select class="wpo_logger_type" name="wpo-logger-type[]">',i.join(""),"<select>",'<a href="#" class="wpo_delete_logger dashicons dashicons-no-alt"></a>','<div class="wpo_additional_logger_options"></div>',"</div>"].join("")}function p(i){if(!wpoptimize.loggers_classes_info[i].options)return"";var e,o=wpoptimize.loggers_classes_info[i].options,n=[],a="",s="";for(e in o)o.hasOwnProperty(e)&&(t.isArray(o[e])?(a=t.trim(o[e][0]),s=t.trim(o[e][1])):(a=t.trim(o[e]),s=""),n.push(['<input class="wpo_logger_addition_option" type="text" name="wpo-logger-options[',e,'][]" value="" ','placeholder="',a,'" ',""!==s?'data-validate="'+s+'"':"","/>"].join("")));return n.push('<input type="hidden" name="wpo-logger-options[active][]" value="1" />'),n.join("")}t(".wp-optimize-logging-settings").each(function(){var e=t(this);i(e),e.on("change",function(){i(e)})});var r=t("#wpo_add_logger_link");r.on("click",function(){t("#wp-optimize-logger-settings .save_settings_reminder").after(s()),n(t(".wpo_logger_type").first())}),t("#wp-optimize-nav-tab-contents-settings").on("change",".wpo_logger_type",function(){var i=t(this),o=i.val(),n=i.parent().find(".wpo_additional_logger_options");n.html(p(o)),i.val()&&e()}),t(".wpo_logging_actions_row .dashicons-edit").on("click",function(){var i=t(this),e=i.closest(".wpo_logging_row");return t(".wpo_additional_logger_options",e).removeClass("wpo_hidden"),t(".wpo_logging_options_row",e).text(""),t(".wpo_logging_status_row",e).text(""),i.hide(),!1}),t("#wp-optimize-logger-settings").on("change",".wpo_logger_addition_option",function(){e()}),t(".wpo_logger_active_checkbox").on("change",function(){var i=t(this),e=i.closest("label").find('input[type="hidden"]');e.val(i.is(":checked")?"1":"0")}),t("#wp-optimize-nav-tab-contents-settings").on("click",".wpo_delete_logger",function(){if(!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination))return!1;var i=t(this);return i.closest(".wpo_logging_row, .wpo_add_logger_form").remove(),o(),0==t("#wp-optimize-logging-options .wpo_logging_row").length&&t("#wp-optimize-logging-options").hide(),e(),!1})});
1
+ wp_optimize_send_command_admin_ajax=function(e,t,i,o){o="undefined"==typeof o||o;var n={action:"wp_optimize_ajax",subaction:e,nonce:wp_optimize_ajax_nonce,data:t};return jQuery.post(ajaxurl,n,function(e){if(o){try{var t=JSON.parse(e)}catch(n){return console.log(n),console.log(e),void alert(wpoptimize.error_unexpected_response)}"undefined"!=typeof i&&i(t)}else"undefined"!=typeof i&&i(e)})},jQuery(document).ready(function(e){WP_Optimize=WP_Optimize(wp_optimize_send_command_admin_ajax)});var WP_Optimize=function(send_command){function enable_or_disable_schedule_options(){if($("#enable-schedule").length){var e=$("#enable-schedule").is(":checked");e?$("#wp-optimize-auto-options").css("opacity","1"):$("#wp-optimize-auto-options").css("opacity","0.5")}}function temporarily_display_notice(e,t,i){t="undefined"==typeof t?"#wp-optimize-wrap":t,i="undefined"==typeof i?15:i,$(e).hide().prependTo(t).slideDown("fast").delay(1e3*i).slideUp("fast",function(){$(this).remove()})}function enable_or_disable_feature(e,t){var i={type:e,enable:t?1:0};$("#"+e+"_spinner").show(),send_command("enable_or_disable_feature",i,function(t){if($("#"+e+"_spinner").hide(),t&&t.hasOwnProperty("output"))for(var i=0,o=t.output.length;i<o;i++){var n='<div class="updated"><p>'+t.output[i]+"</p></div>";temporarily_display_notice(n,"#"+e+"_notice")}})}function toggle_mobile_menu(e){e?$("#wp-optimize-wrap").addClass("wpo-mobile-menu-opened"):$("#wp-optimize-wrap").removeClass("wpo-mobile-menu-opened")}function gather_settings(e){var t="",e="undefined"==typeof e?"string":e;return"object"==e?t=$("#wp-optimize-general-settings form input[name!='action'], #wp-optimize-general-settings form textarea, #wp-optimize-general-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serializeJSON({useIntKeysAsArrayIndex:!0}):(t=$("#wp-optimize-general-settings form input[name!='action'], #wp-optimize-general-settings form textarea, #wp-optimize-general-settings form select, #wp-optimize-nav-tab-contents-optimize input[type='checkbox'], .wp-optimize-nav-tab-contents input[name^='enable-auto-backup-']").serialize(),$.each($('#wp-optimize-general-settings form input[type=checkbox], .wp-optimize-nav-tab-contents input[name^="enable-auto-backup-"]').filter(function(e){return 0==$(this).prop("checked")}),function(e,i){var o="0";t+="&"+$(i).attr("name")+"="+o})),t}function process_done(){send_command("optimizations_done",{},function(){})}function process_queue(){if(!queue.get_lock())return void(debug_level>0&&console.log("WP-Optimize: process_queue(): queue is currently locked - exiting"));debug_level>0&&console.log("WP-Optimize: process_queue(): got queue lock");var e=queue.peek();return"object"==typeof e?(data=e,e=e.optimization_id):data={},"undefined"==typeof e?(debug_level>0&&console.log("WP-Optimize: process_queue(): queue is apparently empty - exiting"),queue.unlock(),void process_done()):(debug_level>0&&console.log("WP-Optimize: process_queue(): processing item: "+e),queue.dequeue(),$(document).trigger(["do_optimization_",e,"_start"].join("")),void send_command("do_optimization",{optimization_id:e,data:data},function(t){if($("#optimization_spinner_"+e).hide(),$("#optimization_checkbox_"+e).show(),$(".optimization_button_"+e).prop("disabled",!1),$(document).trigger(["do_optimization_",e,"_done"].join(""),t),t){for(var i="",o=0,n=t.errors.length;o<n;o++)i+='<span class="error">'+t.errors[o]+"</span><br>";for(var o=0,n=t.messages.length;o<n;o++)i+=t.errors[o]+"<br>";for(var o=0,n=t.result.output.length;o<n;o++)i+=t.result.output[o]+"<br>";if($("#optimization_info_"+e).html(i),t.hasOwnProperty("status_box_contents")&&$("#wp_optimize_status_box").css("opacity","1").find(".inside").html(t.status_box_contents),t.hasOwnProperty("table_list")&&$("#wpoptimize_table_list tbody").html($(t.table_list).find("tbody").html()),t.hasOwnProperty("total_size")&&$("#optimize_current_db_size").html(t.total_size),"optimizetables"==e&&data.optimization_table&&(queue.is_empty()?($("#optimization_spinner_"+e).hide(),$("#optimization_checkbox_"+e).show(),$(".optimization_button_"+e).prop("disabled",!1),$("#optimization_info_"+e).html(wpoptimize.optimization_complete)):($("#optimization_checkbox_"+e).hide(),$("#optimization_spinner_"+e).show(),$(".optimization_button_"+e).prop("disabled",!0))),t.result.meta&&t.result.meta.hasOwnProperty("awaiting_mod")){var s=t.result.meta.awaiting_mod;s>0?$("#adminmenu .awaiting-mod .pending-count").remove(s):$("#adminmenu .awaiting-mod").remove()}}setTimeout(function(){queue.unlock(),process_queue()},10)}))}function do_optimization(e){var t=$("#wp-optimize-nav-tab-contents-optimize .wp-optimize-settings-"+e);t||console.log("do_optimization: row corresponding to this optimization ("+e+") not found");var i={},o=0;if($('input[type="checkbox"]',$("#optimization_info_"+e)).each(function(){var e=$(this);e.is(":checked")&&(i[e.attr("name")]=e.val(),o++)}),1!=$(".optimization_button_"+e).prop("disabled")){if($("#optimization_checkbox_"+e).hide(),$("#optimization_spinner_"+e).show(),$(".optimization_button_"+e).prop("disabled",!0),$("#optimization_info_"+e).html("..."),"optimizetables"==e){var n=$("#wpoptimize_table_list #the-list tr");$(n).each(function(t){var i=$(this).find("td");if(table_type=i.eq(5).text(),table=i.eq(1).text(),optimizable=i.eq(5).data("optimizable"),""!=table&&("1"==optimizable||optimization_force)){var o={optimization_id:e,optimization_table:i.eq(1).text(),optimization_table_type:table_type,optimization_force:optimization_force};queue.enqueue(o)}})}else if(o>0){data={optimization_id:e};for(var s in i)i.hasOwnProperty(s)&&(data[s]=i[s]);queue.enqueue(data)}else queue.enqueue(e);process_queue()}}function save_sites_list_and_do_action(e){$("#wpo_settings_sites_list").length?send_command("save_site_settings",{"wpo-sites":get_selected_sites_list()},function(){e&&e()}):e&&e()}function get_selected_sites_list(){var e=[];return $('#wpo_settings_sites_list input[type="checkbox"]').each(function(){var t=$(this);t.is(":checked")&&e.push(t.attr("value"))}),e}function run_optimizations(){var e=!1;$("#enable-auto-backup").is(":checked")&&(e=!0),save_auto_backup_options(),1==e?take_a_backup_with_updraftplus(run_optimization):run_optimization()}function take_a_backup_with_updraftplus(e){"function"==typeof updraft_backupnow_inpage_go?updraft_backupnow_inpage_go(function(){$("#updraft-backupnow-inpage-modal").dialog("close"),e&&e()},"","autobackup",0,1,0,wpoptimize.automatic_backup_before_optimizations):e&&e()}function save_auto_backup_options(){var e=gather_settings("object");e.auto_backup=$("#enable-auto-backup").is(":checked"),send_command("save_auto_backup_option",e)}function define_moreoptions_settings(e,t,i,o){e.on("click",function(){return t.hasClass("wpo_always_visible")||t.toggleClass("wpo_hidden"),!1}),define_select_all_checkbox(i,o)}function define_select_all_checkbox(e,t){e.on("change",function(){e.is(":checked")?t.prop("checked",!0):t.prop("checked",!1),update_wpo_all_items_checkbox_state(e,t)}),t.on("change",function(){update_wpo_all_items_checkbox_state(e,t)}),update_wpo_all_items_checkbox_state(e,t)}function update_wpo_all_items_checkbox_state(e,t){var i=0,o=0;if(t.each(function(){$(this).is(":checked")&&o++,i++}),e.next().is("label")&&e.next().data("label")){var n=e.next(),s=n.data("label");i==o?n.text(s):n.text(s.replace("all",[o," of ",i].join("")))}i==o?e.prop("checked",!0):e.prop("checked",!1)}function run_optimization(){$optimizations=$("#optimizations_list .optimization_checkbox:checked"),$optimizations.sort(function(e,t){return e=$(e).closest(".wp-optimize-settings").data("optimization_run_sort_order"),t=$(t).closest(".wp-optimize-settings").data("optimization_run_sort_order"),e>t?1:e<t?-1:0});var e={};$optimizations.each(function(t){var i=$(this).closest(".wp-optimize-settings").data("optimization_id");return i?(e[i]={active:1},void do_optimization(i)):void console.log("Optimization ID corresponding to pressed button not found")}),send_command("save_manual_run_optimization_options",e)}function run_single_table_optimization(e){var t=e.next(),i=t.next(),o=e.data("table"),n=e.data("type"),s={optimization_id:"optimizetables",optimization_table:o,optimization_table_type:n};e.hide(),single_table_optimization_force.is(":checked")&&(s.optimization_force=!0),t.removeClass("visibility-hidden"),send_command("do_optimization",{optimization_id:"optimizetables",data:s},function(){e.prop("disabled",!1),t.addClass("visibility-hidden"),i.show().removeClass("visibility-hidden").delay(2500).fadeOut("fast",function(){e.show()})})}function update_single_table_optimization_buttons(e){$(".run-single-table-optimization").each(function(){var t=$(this);t.data("disabled")&&(e?t.prop("disabled",!1):t.prop("disabled",!0))})}function is_sites_selected(){return 0==wpo_settings_sites_list.length||0!=$('input[type="checkbox"]:checked',wpo_settings_sites_list).length}function update_optimizations_info_view(e){var t,i,o;if(e)for(t in e)e.hasOwnProperty(t)&&(i=["#wp-optimize-settings-",e[t].dom_id].join(""),o=e[t].info?e[t].info.join("<br>"):"",$(i+" .wp-optimize-settings-optimization-info").html(o))}function update_optimizations_info(){var e=["",get_selected_sites_list().join("_")].join("");get_optimizations_info_cache.hasOwnProperty(e)?update_optimizations_info_view(get_optimizations_info_cache[e]):send_command("get_optimizations_info",{"wpo-sites":get_selected_sites_list()},function(t){t&&(get_optimizations_info_cache[e]=t,update_optimizations_info_view(t))})}function import_settings(e){var t=$("#wpo_import_spinner"),i=$("#wpo_import_success_message"),o=$("#wpo_import_error_message");t.show(),send_command("import_settings",{settings:e},function(e){t.hide(),e&&e.errors&&e.errors.length?(o.text(e.errors.join("<br>")),o.slideDown()):e&&e.messages&&e.messages.length&&(i.text(e.messages.join("<br>")),i.slideDown(),setTimeout(function(){window.location.reload()},500)),$("#wpo_import_settings_btn").prop("disabled",!1)})}function wpo_download_json_file(e,t){var i=document.body.appendChild(document.createElement("a")),o=new Date,n=o.getFullYear(),s=o.getMonth()<10?["0",o.getMonth()].join(""):o.getMonth(),a=o.getDay()<10?["0",o.getDay()].join(""):o.getDay();t=t?t:["wpo-settings-",n,"-",s,"-",a,".json"].join(""),i.setAttribute("download",t),i.setAttribute("style","display:none;"),i.setAttribute("href","data:text/json;charset=UTF-8,"+encodeURIComponent(JSON.stringify(e))),i.click()}function remove_single_db_table(e){var t=e.next(),i=t.next(),o=e.data("table"),n={optimization_id:"orphanedtables",optimization_table:o};t.removeClass("visibility-hidden"),send_command("do_optimization",{optimization_id:"orphanedtables",data:n},function(n){if(n.result.meta.success){var s=e.closest("tr");e.prop("disabled",!1),t.addClass("visibility-hidden"),i.show().removeClass("visibility-hidden"),setTimeout(function(){s.fadeOut("slow",function(){s.remove(),change_actions_column_visibility()})},500)}else e.prop("disabled",!1),t.addClass("visibility-hidden"),alert(wpoptimize.table_was_not_deleted.replace("%s",o))})}function change_actions_column_visibility(){var e=$("#wpoptimize_table_list"),t=!0;$("tr",e).each(function(){var e=$(this);if($("button",e).length>0)return t=!1,!1}),$("tr",e).each(function(){var e=$(this);t?$("td:last, th:last",e).hide():$("td:last, th:last",e).show()})}function validate_logger_settings(){var e=!0;return $(".wpo_logger_addition_option, .wpo_logger_type").each(function(){validate_field($(this),!0)?$(this).removeClass("wpo_error_field"):(e=!1,$(this).addClass("wpo_error_field"))}),e?$("#wp-optimize-logger-settings .save_settings_reminder").slideUp():$("#wp-optimize-settings-save-results").show().addClass("wpo_alert_notice").text(wpoptimize.fill_all_settings_fields).delay(5e3).fadeOut(3e3,function(){$(this).removeClass("wpo_alert_notice")}),e}function validate_field(e,t){var i=e.val(),o=e.data("validate");if(!o&&t)return""!=$.trim(i);if(o&&!t&&""==$.trim(i))return!0;var n=!0;switch(o){case"email":for(var s=/\S+@\S+\.\S+/,a=i.split(","),_="",p=0;p<a.length;p++)_=$.trim(a[p]),""!=_&&s.test(_)||(n=!1);break;case"url":var s=/^(?:(?:https?|ftp):\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))\.?)(?::\d{2,5})?(?:[\/?#]\S*)?$/i;n=s.test(i)}return n}var $=jQuery,debug_level=0,queue=new Updraft_Queue;define_select_all_checkbox($("#select_all_optimizations"),$("#optimizations_list .optimization_checkbox")),enable_or_disable_schedule_options(),$("#enable-schedule").change(function(){enable_or_disable_schedule_options()});var table_list_filter=$("#wpoptimize_table_list_filter"),table_list=$("#wpoptimize_table_list"),table_footer_line=$("#wpoptimize_table_list tbody:last"),tables_not_found=$("#wpoptimize_table_list_tables_not_found");$(function(){$.tablesorter.addParser({id:"sizes",is:function(e){return!1},format:function(s){var kb=1024,mb=1024*kb,gb=1024*mb;return eval(s.toLowerCase().replace(/kb/,["* ",kb].join("")).replace(/mb/,["* ",mb].join("")).replace(/gb/,["* ",gb].join("")).replace(/[^0-9\.\*\s]/g,""))},type:"numeric"}),table_list.tablesorter({theme:"default",widgets:["zebra","rows","filter"],cssInfoBlock:"tablesorter-no-sort",headers:{2:{sorter:"digit"},3:{sorter:"sizes"},4:{sorter:"sizes"},7:{sorter:!1}},widgetOptions:{filter_external:table_list_filter,filter_defaultFilter:{2:"~{query}"}}}),table_list.on("filterEnd",function(){var e=$.trim(table_list_filter.val());""==e?table_footer_line.show():table_footer_line.hide(),0==$("#the-list tr:visible",table_list).length?tables_not_found.show():tables_not_found.hide()})}),$("#wp-optimize-disable-enable-trackbacks-enable").click(function(){enable_or_disable_feature("trackbacks",!0)}),$("#wp-optimize-disable-enable-trackbacks-disable").click(function(){enable_or_disable_feature("trackbacks",!1)}),$("#wp-optimize-disable-enable-comments-enable").click(function(){enable_or_disable_feature("comments",!0)}),$("#wp-optimize-disable-enable-comments-disable").click(function(){enable_or_disable_feature("comments",!1)}),$(".wpo-pages-menu").on("click","a",function(e){e.preventDefault(),$(this).is(".active")||($(".wpo-pages-menu a.active").removeClass("active"),$(".wpo-page.active").removeClass("active"),$(this).addClass("active"),$('.wpo-page[data-whichpage="'+$(this).data("menuslug")+'"]').addClass("active"),window.scroll(0,0)),$("#wp-optimize-nav-page-menu").trigger("click")}),$(".nav-tab-wrapper .nav-tab").click(function(e){e.preventDefault();var t=$(this).attr("id"),i=$(this).closest(".nav-tab-wrapper");if(t){if(toggle_mobile_menu(!1),$(this).is('[role="toggle-menu"]'))return void toggle_mobile_menu(!0);i.find(".nav-tab:not(#wp-optimize-nav-tab-"+t+")").removeClass("nav-tab-active"),$(this).addClass("nav-tab-active"),$(this).closest(".wpo-page").find(".wp-optimize-nav-tab-contents").hide(),$("#"+t+"-contents").show()}}),$("#wp-optimize-nav-page-menu").on("click",function(e){e.preventDefault(),$(this).toggleClass("opened")}),$("#wp-optimize-nav-tab-wpo_database-optimize-contents").on("click","button.wp-optimize-settings-optimization-run-button",function(){var e=$(this).closest(".wp-optimize-settings").data("optimization_id");return e?void(1!=$(".optimization_button_"+e).prop("disabled")&&($(".optimization_button_"+e).prop("disabled",!0),save_sites_list_and_do_action(function(){$(".optimization_button_"+e).prop("disabled",!1),do_optimization(e)}))):void console.log("Optimization ID corresponding to pressed button not found")}),$("#wp-optimize-nav-tab-wpo_database-optimize-contents").on("click","#wp-optimize",function(e){var t=$(this);e.preventDefault(),t.prop("disabled",!0),save_sites_list_and_do_action(function(){t.prop("disabled",!1),run_optimizations()})});var browser_cache_enable_btn=$("#wp_optimize_browser_cache_enable");browser_cache_enable_btn.closest("form").submit(function(e){return e.preventDefault(),browser_cache_enable_btn.trigger("click"),!1}),$("#wp_optimize_gzip_compression_enable").on("click",function(){var e=$(this),t=e.next();t.show(),send_command("enable_gzip_compression",{enable:e.data("enable")},function(i){var o=$("#wpo_gzip_compression_status");i?(i.enabled?(e.text(wpoptimize.disable),e.data("enable","0"),o.removeClass("wpo-disabled").addClass("wpo-enabled")):(e.text(wpoptimize.enable),e.data("enable","1"),o.addClass("wpo-disabled").removeClass("wpo-enabled")),i.message?$("#wpo_gzip_compression_error_message").text(i.message).show():$("#wpo_gzip_compression_error_message").hide(),i.output?$("#wpo_gzip_compression_output").html(i.output).show():$("#wpo_gzip_compression_output").hide()):alert(wpoptimize.error_unexpected_response),t.hide()}).fail(function(){alert(wpoptimize.error_unexpected_response),t.hide()})}),browser_cache_enable_btn.on("click",function(){var e=$("#wpo_browser_cache_expire_days"),t=$("#wpo_browser_cache_expire_hours"),i=parseInt(e.val(),10),o=parseInt(t.val(),10),n=$(this),s=n.next();return isNaN(i)&&(i=0),isNaN(o)&&(o=0),i<0||o<0?($("#wpo_browser_cache_error_message").text(wpoptimize.please_use_positive_integers).show(),!1):o>23?($("#wpo_browser_cache_error_message").text(wpoptimize.please_use_valid_values).show(),!1):($("#wpo_browser_cache_error_message").hide(),e.val(i),t.val(o),s.show(),void send_command("enable_browser_cache",{browser_cache_expire_days:i,browser_cache_expire_hours:o},function(e){var t=$("#wpo_browser_cache_status");e?(e.enabled?(n.text(wpoptimize.update),t.removeClass("wpo-disabled").addClass("wpo-enabled")):(n.text(wpoptimize.enable),t.addClass("wpo-disabled").removeClass("wpo-enabled")),e.message?$("#wpo_browser_cache_message").text(e.message).show():$("#wpo_browser_cache_message").hide(),e.error_message?$("#wpo_browser_cache_error_message").text(e.error_message).show():$("#wpo_browser_cache_error_message").hide(),e.output?$("#wpo_browser_cache_output").html(e.output).show():$("#wpo_browser_cache_output").hide()):alert(wpoptimize.error_unexpected_response),s.hide()}).fail(function(){alert(wpoptimize.error_unexpected_response),s.hide()}))});var wpo_settings_sites_list=$("#wpo_settings_sites_list"),wpo_settings_sites_list_ul=wpo_settings_sites_list.find("ul").first(),wpo_settings_sites_list_items=$('input[type="checkbox"]',wpo_settings_sites_list_ul),wpo_settings_all_sites_checkbox=wpo_settings_sites_list.find("#wpo_all_sites"),wpo_sitelist_show_moreoptions_link=$("#wpo_sitelist_show_moreoptions"),wpo_sitelist_moreoptions_div=$("#wpo_sitelist_moreoptions"),wpo_settings_sites_list_cron=$("#wpo_settings_sites_list_cron"),wpo_settings_sites_list_cron_ul=wpo_settings_sites_list_cron.find("ul").first(),wpo_settings_sites_list_cron_items=$('input[type="checkbox"]',wpo_settings_sites_list_cron_ul),wpo_settings_all_sites_cron_checkbox=wpo_settings_sites_list_cron.find("#wpo_all_sites_cron"),wpo_sitelist_show_moreoptions_cron_link=$("#wpo_sitelist_show_moreoptions_cron"),wpo_sitelist_moreoptions_cron_div=$("#wpo_sitelist_moreoptions_cron");define_moreoptions_settings(wpo_sitelist_show_moreoptions_link,wpo_sitelist_moreoptions_div,wpo_settings_all_sites_checkbox,wpo_settings_sites_list_items);var sites_list_clicked_count=0;$([wpo_settings_all_sites_checkbox,wpo_settings_sites_list_items]).each(function(){$(this).on("change",function(){sites_list_clicked_count++,setTimeout(function(){sites_list_clicked_count--,0==sites_list_clicked_count&&update_optimizations_info()},1e3)})}),define_moreoptions_settings(wpo_sitelist_show_moreoptions_cron_link,wpo_sitelist_moreoptions_cron_div,wpo_settings_all_sites_cron_checkbox,wpo_settings_sites_list_cron_items),$("#wp_optimize_table_list_refresh").click(function(e){e.preventDefault(),$("#wpoptimize_table_list tbody").css("opacity","0.5"),send_command("get_table_list",!1,function(e){if(e.hasOwnProperty("table_list")){var t=!0,i=function(e){$("#wpoptimize_table_list tbody").css("opacity","1")};$("#wpoptimize_table_list").trigger("updateAll",[t,i])}e.hasOwnProperty("total_size")&&$("#optimize_current_db_size").html(e.total_size),update_single_table_optimization_buttons(single_table_optimization_force.is(":checked"))})}),$("#settings_form").on("click","#wp-optimize-settings-save",function(e){if(e.preventDefault(),!validate_logger_settings())return!1;console.log("What?"),$("#save_spinner").show();var t=gather_settings();send_command("save_settings",t,function(e){if($("#save_spinner").hide(),$("#save_done").show().delay(5e3).fadeOut(),e&&e.hasOwnProperty("save_results")&&e.save_results&&e.save_results.hasOwnProperty("errors")){for(var t=0,i=e.save_results.errors.length;t<i;t++){var o='<div class="error">'+e.errors[t]+"</div>";temporarily_display_notice(o,"#wp-optimize-settings-save-results")}console.log(e.save_results.messages)}e&&e.hasOwnProperty("status_box_contents")&&$("#wp_optimize_status_box .inside").html(e.status_box_contents),e&&e.hasOwnProperty("optimizations_table")&&$("#optimizations_list").replaceWith(e.optimizations_table),e.save_results.refresh&&location.reload()})}),$("#wp_optimize_status_box").on("click","#wp_optimize_status_box_refresh",function(e){e.preventDefault(),$("#wp_optimize_status_box").css("opacity","0.5"),send_command("get_status_box_contents",null,function(e){$("#wp_optimize_status_box").css("opacity","1").find(".inside").html(e)})});var optimization_force_checkbox=$("#innodb_force_optimize"),optimization_force=optimization_force_checkbox.is(":checked"),optimization_row=optimization_force_checkbox.closest("tr"),single_table_optimization_force=$("#innodb_force_optimize_single");optimization_force_checkbox.on("change",function(){$('button, input[type="checkbox"]',optimization_row).each(function(){optimization_force=optimization_force_checkbox.is(":checked");var e=$(this);e.data("disabled")&&(optimization_force?e.prop("disabled",!1):e.prop("disabled",!0))})}),$("#wpoptimize_table_list").on("click",".run-single-table-optimization",function(){var e=$("#enable-auto-backup-1");e.is(":checked")?take_a_backup_with_updraftplus(run_single_table_optimization($(this))):run_single_table_optimization($(this))}),single_table_optimization_force.change(function(){update_single_table_optimization_buttons(single_table_optimization_force.is(":checked"))}),update_single_table_optimization_buttons(single_table_optimization_force.is(":checked"));var get_optimizations_info_cache={};setTimeout(function(){send_command("check_overdue_crons",null,function(e){e&&e.hasOwnProperty("m")&&$("#wpo_settings_warnings").append(e.m)})},11e3),$("#wpo_import_settings_btn").on("click",function(e){var t=$("#wpo_import_settings_file"),i=t.val(),o=t[0].files[0],n=new FileReader;return $("#wpo_import_settings_btn").prop("disabled",!0),/\.json$/.test(i)?(n.onload=function(){import_settings(this.result)},n.readAsText(o),!1):(e.preventDefault(),$("#wpo_import_settings_btn").prop("disabled",!1),$("#wpo_import_error_message").text(wpoptimize.please_select_settings_file).slideDown(),!1)}),$("#wpo_import_settings_file").on("change",function(){$("#wpo_import_error_message").slideUp()}),$("#wpo_export_settings_btn").on("click",function(e){return wpo_download_json_file(gather_settings("object")),!1});var optimization_get_info=function(e,t,i){return send_command("get_optimization_info",{optimization_id:t,data:i},function(i){var o=i&&i.result&&i.result.meta?i.result.meta:{},n=i&&i.result&&i.result.output?i.result.output.join("<br>"):"...";$(document).trigger(["optimization_get_info_",t].join(""),n),e.html(n),o.finished?$(document).trigger(["optimization_get_info_",t,"_done"].join(""),i):setTimeout(function(){optimization_get_info(e,t,o)},1)})};return $(document).ready(function(){$(".wp-optimize-optimization-info-ajax").each(function(){var e=$(this),t=e.parent(),i=e.data("id");$(document).trigger(["optimization_get_info_",i,"_start"].join("")),optimization_get_info(t,i,{support_ajax_get_info:!0})})}),$("#wpoptimize_table_list").on("click",".run-single-table-repair",function(){var e=$(this),t=e.next(),i=t.next(),o=e.data("table"),n={optimization_id:"repairtables",optimization_table:o};t.removeClass("visibility-hidden"),send_command("do_optimization",{optimization_id:"repairtables",data:n},function(n){if(n.result.meta.success){var s=e.closest("tr"),a=n.result.meta.tableinfo;e.prop("disabled",!1),t.addClass("visibility-hidden"),i.show().removeClass("visibility-hidden"),$("td:eq(2)",s).text(a.rows),$("td:eq(3)",s).text(a.data_size),$("td:eq(4)",s).text(a.index_size),$("td:eq(5)",s).text(a.type),a.is_optimizable?$("td:eq(6)",s).html(['<span color="',a.overhead>0?"#0000FF":"#004600",'">',a.overhead,"</span>"].join("")):$("td:eq(6)",s).html('<span color="#0000FF">-</span>'),setTimeout(function(){var t=e.closest("td"),i=e.closest(".wpo_button_wrap");i.fadeOut("fast",function(){i.closest(".wpo_button_wrap").remove(),a.is_optimizable&&$(".wpo_button_wrap",t).removeClass("wpo_hidden")}),change_actions_column_visibility()},1e3)}else e.prop("disabled",!1),t.addClass("visibility-hidden"),alert(wpoptimize.table_was_not_repaired.replace("%s",o))})}),$("#wpoptimize_table_list").on("click",".run-single-table-delete",function(){if(!confirm(wpoptimize.are_you_sure_you_want_to_remove_this_table))return!1;var e=$("#enable-auto-backup-1");e.is(":checked")?take_a_backup_with_updraftplus(remove_single_db_table($(this))):e()}),change_actions_column_visibility(),setTimeout(function(){send_command("check_overdue_crons",null,function(e){e&&e.hasOwnProperty("m")&&$("#wpo_settings_warnings").append(e.m)})},11e3),{send_command:send_command,optimization_get_info:optimization_get_info,take_a_backup_with_updraftplus:take_a_backup_with_updraftplus,save_auto_backup_options:save_auto_backup_options}};jQuery(document).ready(function(e){function t(t){var i=["#",t.data("additional")].join("");t.is(":checked")?e(i).show():e(i).hide()}function i(){var t=e("#wp-optimize-logger-settings .save_settings_reminder");t.is(":visible")||t.slideDown("normal")}function o(){e(".wpo_logger_type").each(function(){n(e(this))})}function n(t){var i,o,n=s();for(i in n)o=n[i],wpoptimize.loggers_classes_info[o].allow_multiple?e('option[value="'+o+'"]',t).show():e('option[value="'+o+'"]',t).hide()}function s(){var t=[];return e(".wpo_logging_row, .wpo_logger_type").each(function(){var i=e(this).is("select")?e(this).val():e(this).data("id");i&&t.push(i)}),t}function a(){var e,t=['<option value="">Select destination</option>'];for(e in wpoptimize.loggers_classes_info)wpoptimize.loggers_classes_info.hasOwnProperty(e)&&wpoptimize.loggers_classes_info[e].available&&t.push(['<option value="',e,'">',wpoptimize.loggers_classes_info[e].description,"</option>"].join(""));return['<div class="wpo_add_logger_form">','<select class="wpo_logger_type" name="wpo-logger-type[]">',t.join(""),"<select>",'<a href="#" class="wpo_delete_logger dashicons dashicons-no-alt"></a>','<div class="wpo_additional_logger_options"></div>',"</div>"].join("")}function _(t){if(!wpoptimize.loggers_classes_info[t].options)return"";var i,o=wpoptimize.loggers_classes_info[t].options,n=[],s="",a="";for(i in o)o.hasOwnProperty(i)&&(e.isArray(o[i])?(s=e.trim(o[i][0]),a=e.trim(o[i][1])):(s=e.trim(o[i]),a=""),n.push(['<input class="wpo_logger_addition_option" type="text" name="wpo-logger-options[',i,'][]" value="" ','placeholder="',s,'" ',""!==a?'data-validate="'+a+'"':"","/>"].join("")));return n.push('<input type="hidden" name="wpo-logger-options[active][]" value="1" />'),n.join("")}e(".wp-optimize-logging-settings").each(function(){var i=e(this);t(i),i.on("change",function(){t(i)})});var p=e("#wpo_add_logger_link");p.on("click",function(t){t.preventDefault(),e("#wp-optimize-logger-settings .save_settings_reminder").after(a()),n(e(".wpo_logger_type").first())}),e("#wp-optimize-general-settings").on("change",".wpo_logger_type",function(){var t=e(this),o=t.val(),n=t.parent().find(".wpo_additional_logger_options");n.html(_(o)),t.val()&&i()}),e(".wpo_logging_actions_row .dashicons-edit").on("click",function(){var t=e(this),i=t.closest(".wpo_logging_row");return e(".wpo_additional_logger_options",i).removeClass("wpo_hidden"),e(".wpo_logging_options_row",i).text(""),e(".wpo_logging_status_row",i).text(""),t.hide(),!1}),e("#wp-optimize-logger-settings").on("change",".wpo_logger_addition_option",function(){i()}),e(".wpo_logger_active_checkbox").on("change",function(){var t=e(this),i=t.closest("label").find('input[type="hidden"]');i.val(t.is(":checked")?"1":"0")}),e("#wp-optimize-general-settings").on("click",".wpo_delete_logger",function(){if(!confirm(wpoptimize.are_you_sure_you_want_to_remove_logging_destination))return!1;var t=e(this);return t.closest(".wpo_logging_row, .wpo_add_logger_form").remove(),o(),0==e("#wp-optimize-logging-options .wpo_logging_row").length&&e("#wp-optimize-logging-options").hide(),i(),!1});var r=!1;e(window).on("scroll",function(t){window.requestAnimationFrame(function(){var t=e(".wpo-main-header").length?e(".wpo-main-header")[0].offsetTop:0;window.pageYOffset>t-20!=r&&(r=!r,e("body").toggleClass("is-scrolled",r))})})});
languages/wp-optimize.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2018 wp-optimize
2
  # This file is distributed under the same license as the wp-optimize package.
3
  msgid ""
4
  msgstr ""
@@ -7,7 +7,7 @@ msgstr ""
7
  "MIME-Version: 1.0\n"
8
  "Content-Type: text/plain; charset=UTF-8\n"
9
  "Content-Transfer-Encoding: 8bit\n"
10
- "PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n"
11
  "Last-Translator: John Doe <mail@example.com>\n"
12
  "Language-Team: Team Updraft <mail@example.com>\n"
13
  "X-Poedit-Basepath: ..\n"
@@ -17,11 +17,11 @@ msgstr ""
17
  "X-Poedit-SearchPathExcluded-0: *.js\n"
18
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
 
20
- #: src/includes/class-commands.php:180, src/includes/class-commands.php:224, src/includes/class-commands.php:266
21
  msgid "No optimization was indicated."
22
  msgstr ""
23
 
24
- #: src/includes/class-commands.php:376, src/includes/class-commands.php:385
25
  msgid "Please upload a valid settings file."
26
  msgstr ""
27
 
@@ -58,7 +58,7 @@ msgid "Image restored successfully"
58
  msgstr ""
59
 
60
  #: src/includes/class-updraft-smush-manager-commands.php:142
61
- msgid "A total of %d image(s) were compressed on this site, saving appoximately %s of space at an average of %02d percent per image."
62
  msgstr ""
63
 
64
  #: src/includes/class-updraft-smush-manager-commands.php:143
@@ -94,7 +94,7 @@ msgid "Pending tasks cleared successfully"
94
  msgstr ""
95
 
96
  #: src/includes/class-updraft-smush-manager-commands.php:255
97
- msgid "Log file does not exist or cant be read"
98
  msgstr ""
99
 
100
  #: src/includes/class-updraft-smush-manager.php:212
@@ -110,7 +110,7 @@ msgid "Could not copy file, check your PHP error logs for details"
110
  msgstr ""
111
 
112
  #: src/includes/class-updraft-smush-manager.php:434
113
- msgid "All valid images are compresed now"
114
  msgstr ""
115
 
116
  #: src/includes/class-updraft-smush-manager.php:435
@@ -158,7 +158,7 @@ msgid "Backing up original image"
158
  msgstr ""
159
 
160
  #: src/includes/class-updraft-smush-task.php:237
161
- msgid "Saving optimised image"
162
  msgstr ""
163
 
164
  #: src/includes/class-updraft-smush-task.php:238
@@ -169,6 +169,34 @@ msgstr ""
169
  msgid "Preview found items"
170
  msgstr ""
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  #: src/includes/class-wp-optimize-options.php:142
173
  msgid "Auto backup option updated."
174
  msgstr ""
@@ -181,22 +209,26 @@ msgstr ""
181
  msgid "No such optimization"
182
  msgstr ""
183
 
184
- #: src/includes/class-wp-optimizer.php:453
185
  msgid "Comments have now been disabled on all current and previously published posts."
186
  msgstr ""
187
 
188
- #: src/includes/class-wp-optimizer.php:456
189
  msgid "Comments have now been enabled on all current and previously published posts."
190
  msgstr ""
191
 
192
- #: src/includes/class-wp-optimizer.php:463
193
  msgid "Trackbacks have now been disabled on all current and previously published posts."
194
  msgstr ""
195
 
196
- #: src/includes/class-wp-optimizer.php:466
197
  msgid "Trackbacks have now been enabled on all current and previously published posts."
198
  msgstr ""
199
 
 
 
 
 
200
  #: src/includes/wp-optimize-notices.php:41
201
  msgid "Make sure you backup before you optimize your database"
202
  msgstr ""
@@ -451,6 +483,14 @@ msgstr ""
451
  msgid "Clean orphaned relationship data"
452
  msgstr ""
453
 
 
 
 
 
 
 
 
 
454
  #: src/optimizations/pingbacks.php:50, src/optimizations/spam.php:83, src/optimizations/trackbacks.php:51, src/optimizations/unapproved.php:66
455
  msgid "Author"
456
  msgstr ""
@@ -507,10 +547,6 @@ msgstr ""
507
  msgid "Remove orphaned post meta"
508
  msgstr ""
509
 
510
- #: src/optimizations/repairtables.php:142
511
- msgid "No corrupted tables found"
512
- msgstr ""
513
-
514
  #: src/optimizations/repairtables.php:154
515
  msgid "Repair database tables"
516
  msgstr ""
@@ -717,856 +753,988 @@ msgstr ""
717
  msgid "Remove unapproved comments"
718
  msgstr ""
719
 
720
- #: src/templates/admin-page-header.php:5, src/templates/may-also-like.php:25
721
- msgid "Premium"
 
 
 
 
722
  msgstr ""
723
 
724
- #: src/templates/admin-page-header.php:11
725
  msgid "Home"
726
  msgstr ""
727
 
728
- #: src/templates/admin-page-header.php:15
729
  msgid "News"
730
  msgstr ""
731
 
732
- #: src/templates/admin-page-header.php:17
733
  msgid "Twitter"
734
  msgstr ""
735
 
736
- #: src/templates/admin-page-header.php:19
737
  msgid "Support"
738
  msgstr ""
739
 
740
- #: src/templates/admin-page-header.php:21
741
- msgid "Newsletter sign-up"
742
  msgstr ""
743
 
744
- #: src/templates/admin-page-header.php:23
745
- msgid "Lead developer"
746
  msgstr ""
747
 
748
- #: src/templates/admin-page-header.php:25, src/templates/may-also-like.php:7
749
  msgid "FAQs"
750
  msgstr ""
751
 
752
- #: src/templates/admin-page-header.php:27
753
  msgid "More plugins"
754
  msgstr ""
755
 
756
- #: src/templates/admin-settings-auto-cleanup.php:3
757
- msgid "Scheduled clean-up settings"
758
  msgstr ""
759
 
760
- #: src/templates/admin-settings-auto-cleanup.php:6
761
- msgid "Take control of clean-ups: Upgrade to Premium for a more powerful and flexible scheduler"
762
  msgstr ""
763
 
764
- #: src/templates/admin-settings-auto-cleanup.php:12
765
- msgid "Enable scheduled clean-up and optimization (Beta feature)"
766
  msgstr ""
767
 
768
- #: src/templates/admin-settings-auto-cleanup.php:20
769
- msgid "Select schedule type (default is Weekly)"
770
  msgstr ""
771
 
772
- #: src/templates/admin-settings-auto-cleanup.php:25
773
- msgid "Daily"
774
  msgstr ""
775
 
776
- #: src/templates/admin-settings-auto-cleanup.php:26
777
- msgid "Weekly"
778
  msgstr ""
779
 
780
- #: src/templates/admin-settings-auto-cleanup.php:27
781
- msgid "Fortnightly"
782
  msgstr ""
783
 
784
- #: src/templates/admin-settings-auto-cleanup.php:28
785
- msgid "Monthly (approx. - every 30 days)"
786
  msgstr ""
787
 
788
- #: src/templates/admin-settings-general.php:17
789
- msgid "General settings"
790
  msgstr ""
791
 
792
- #: src/templates/admin-settings-general.php:19
793
- msgid "Whether manually or on a schedule, these settings apply whenever a relevant optimization is run."
794
  msgstr ""
795
 
796
- #: src/templates/admin-settings-general.php:28
797
- msgid "Keep last %s weeks data"
798
  msgstr ""
799
 
800
- #: src/templates/admin-settings-general.php:34
801
- msgid "This option will, where relevant, retain data from the chosen period, and remove any garbage data before that period."
802
  msgstr ""
803
 
804
- #: src/templates/admin-settings-general.php:34
805
- msgid "If the option is not active, then all garbage data will be removed."
806
  msgstr ""
807
 
808
- #: src/templates/admin-settings-general.php:34
809
- msgid "This will also affect Auto Clean-up process"
810
  msgstr ""
811
 
812
- #: src/templates/admin-settings-general.php:39
813
- msgid "Enable admin bar link"
814
  msgstr ""
815
 
816
- #: src/templates/admin-settings-general.php:42
817
- msgid "This option will put an WP-Optimize link on the top admin bar (default is off). Requires a second page refresh after saving the settings."
818
  msgstr ""
819
 
820
- #: src/templates/admin-settings-logging.php:3
821
- msgid "Logging settings"
822
  msgstr ""
823
 
824
- #: src/templates/admin-settings-logging.php:7
825
- msgid "Add logging destination"
826
  msgstr ""
827
 
828
- #: src/templates/admin-settings-logging.php:11
829
- msgid "Remember to save your settings so that your changes take effect."
830
  msgstr ""
831
 
832
- #: src/templates/admin-settings-logging.php:22
833
- msgid "Destination"
834
  msgstr ""
835
 
836
- #: src/templates/admin-settings-logging.php:23
837
- msgid "Options"
838
  msgstr ""
839
 
840
- #: src/templates/admin-settings-logging.php:24, src/templates/status-box-contents.php:11
841
- msgid "Status"
842
  msgstr ""
843
 
844
- #: src/templates/admin-settings-logging.php:25, src/templates/tables-body.php:81, src/templates/tables.php:28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
845
  msgid "Actions"
846
  msgstr ""
847
 
848
- #: src/templates/admin-settings-logging.php:39, src/templates/admin-settings-logging.php:79
849
- msgid "Active"
850
  msgstr ""
851
 
852
- #: src/templates/admin-settings-logging.php:39
853
- msgid "Inactive"
 
 
 
 
 
 
854
  msgstr ""
855
 
856
- #: src/templates/admin-settings-logging.php:96
857
- msgid "Save settings"
858
  msgstr ""
859
 
860
- #: src/templates/admin-settings-sidebar.php:4
861
- msgid "Trackback/comments actions"
862
  msgstr ""
863
 
864
- #: src/templates/admin-settings-sidebar.php:9
865
- msgid "Trackbacks"
866
  msgstr ""
867
 
868
- #: src/templates/admin-settings-sidebar.php:12
869
- msgid "Use these buttons to enable or disable any future trackbacks on all your previously published posts."
870
  msgstr ""
871
 
872
- #: src/templates/admin-settings-sidebar.php:15, src/templates/admin-settings-sidebar.php:27
873
- msgid "Enable"
874
  msgstr ""
875
 
876
- #: src/templates/admin-settings-sidebar.php:17, src/templates/admin-settings-sidebar.php:29
877
- msgid "Disable"
878
  msgstr ""
879
 
880
- #: src/templates/admin-settings-sidebar.php:23
881
- msgid "Comments"
882
  msgstr ""
883
 
884
- #: src/templates/admin-settings-sidebar.php:25
885
- msgid "Use these buttons to enable or disable any future comments on all your previously published posts."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
  msgstr ""
887
 
888
- #: src/templates/may-also-like.php:3
 
 
 
 
 
 
 
 
889
  msgid "WP-Optimize free / premium comparison"
890
  msgstr ""
891
 
892
- #: src/templates/may-also-like.php:9
893
  msgid "Ask a pre-sales question"
894
  msgstr ""
895
 
896
- #: src/templates/may-also-like.php:20, src/templates/may-also-like.php:25
897
  msgid "WP-Optimize"
898
  msgstr ""
899
 
900
- #: src/templates/may-also-like.php:20
901
  msgid "Free"
902
  msgstr ""
903
 
904
- #: src/templates/may-also-like.php:23
905
  msgid "WP-Optimize Premium"
906
  msgstr ""
907
 
908
- #: src/templates/may-also-like.php:31, src/templates/may-also-like.php:224
909
  msgid "Installed"
910
  msgstr ""
911
 
912
- #: src/templates/may-also-like.php:35, src/templates/may-also-like.php:228
913
  msgid "Upgrade now"
914
  msgstr ""
915
 
916
- #: src/templates/may-also-like.php:41, src/templates/may-also-like.php:42
917
  msgid "Auto-optimize database"
918
  msgstr ""
919
 
920
- #: src/templates/may-also-like.php:43
921
  msgid "Optimizes without the need for manual queries"
922
  msgstr ""
923
 
924
- #: src/templates/may-also-like.php:46, src/templates/may-also-like.php:49, src/templates/may-also-like.php:59, src/templates/may-also-like.php:62, src/templates/may-also-like.php:72, src/templates/may-also-like.php:75, src/templates/may-also-like.php:85, src/templates/may-also-like.php:88, src/templates/may-also-like.php:98, src/templates/may-also-like.php:101, src/templates/may-also-like.php:111, src/templates/may-also-like.php:114, src/templates/may-also-like.php:127, src/templates/may-also-like.php:140, src/templates/may-also-like.php:153, src/templates/may-also-like.php:166, src/templates/may-also-like.php:179, src/templates/may-also-like.php:192, src/templates/may-also-like.php:205, src/templates/may-also-like.php:218
925
  msgid "Yes"
926
  msgstr ""
927
 
928
- #: src/templates/may-also-like.php:54, src/templates/may-also-like.php:55
929
  msgid "Scheduled clean-ups"
930
  msgstr ""
931
 
932
- #: src/templates/may-also-like.php:56
933
  msgid "Carries out scheduled clean-ups daily, weekly, fortnightly and monthly"
934
  msgstr ""
935
 
936
- #: src/templates/may-also-like.php:67, src/templates/may-also-like.php:68
937
  msgid "Displays database table statistics"
938
  msgstr ""
939
 
940
- #: src/templates/may-also-like.php:69
941
  msgid "Displays database table statistics to show how much space can be cleared"
942
  msgstr ""
943
 
944
- #: src/templates/may-also-like.php:80, src/templates/may-also-like.php:81
945
  msgid "Enables / disables trackbacks and comments"
946
  msgstr ""
947
 
948
- #: src/templates/may-also-like.php:82
949
  msgid "Enable or disable trackbacks and comments for all of your published posts"
950
  msgstr ""
951
 
952
- #: src/templates/may-also-like.php:93, src/templates/may-also-like.php:94
953
  msgid "Retains a set number of weeks' data during clean-ups"
954
  msgstr ""
955
 
956
- #: src/templates/may-also-like.php:95
957
  msgid "Choose how much historical data to retain, for extra safety."
958
  msgstr ""
959
 
960
- #: src/templates/may-also-like.php:106, src/templates/may-also-like.php:107
961
  msgid "Clean auto-draft posts"
962
  msgstr ""
963
 
964
- #: src/templates/may-also-like.php:108
965
  msgid "Automatically cleans up auto draft posts older than your chosen age"
966
  msgstr ""
967
 
968
- #: src/templates/may-also-like.php:119, src/templates/may-also-like.php:120, src/templates/may-also-like.php:158
969
  msgid "Multisite support"
970
  msgstr ""
971
 
972
- #: src/templates/may-also-like.php:121
973
  msgid "Optimize any site (or combination of sites) on your WordPress Multisite or network"
974
  msgstr ""
975
 
976
- #: src/templates/may-also-like.php:124, src/templates/may-also-like.php:137, src/templates/may-also-like.php:150, src/templates/may-also-like.php:163, src/templates/may-also-like.php:176, src/templates/may-also-like.php:189, src/templates/may-also-like.php:202, src/templates/may-also-like.php:215
977
  msgid "No"
978
  msgstr ""
979
 
980
- #: src/templates/may-also-like.php:132, src/templates/may-also-like.php:133
981
  msgid "Optimize individual tables"
982
  msgstr ""
983
 
984
- #: src/templates/may-also-like.php:134
985
  msgid "Perform optimizations on single tables"
986
  msgstr ""
987
 
988
- #: src/templates/may-also-like.php:145, src/templates/may-also-like.php:146
989
  msgid "Remove unwanted images"
990
  msgstr ""
991
 
992
- #: src/templates/may-also-like.php:147
993
  msgid "Remove images that have been orphaned or are no longer in use"
994
  msgstr ""
995
 
996
- #: src/templates/may-also-like.php:159
997
  msgid "Sophisticated scheduling"
998
  msgstr ""
999
 
1000
- #: src/templates/may-also-like.php:160
1001
  msgid "A more advanced scheduling system to make regular routine optimizations whenever you prefer"
1002
  msgstr ""
1003
 
1004
- #: src/templates/may-also-like.php:171, src/templates/may-also-like.php:172
1005
  msgid "Control with WP-CLI"
1006
  msgstr ""
1007
 
1008
- #: src/templates/may-also-like.php:173
1009
  msgid "Save time managing multiple sites from the WP command line"
1010
  msgstr ""
1011
 
1012
- #: src/templates/may-also-like.php:184, src/templates/may-also-like.php:185
1013
  msgid "Enhanced logging and reporting"
1014
  msgstr ""
1015
 
1016
- #: src/templates/may-also-like.php:186
1017
  msgid "Send log messages to three additional locations: Slack, Syslog and Simple History"
1018
  msgstr ""
1019
 
1020
- #: src/templates/may-also-like.php:197, src/templates/may-also-like.php:198
1021
  msgid "More choice and flexibility"
1022
  msgstr ""
1023
 
1024
- #: src/templates/may-also-like.php:199
1025
  msgid "Choose from a number of advanced options, like the ability to optimize individual DB tables"
1026
  msgstr ""
1027
 
1028
- #: src/templates/may-also-like.php:210, src/templates/may-also-like.php:211
1029
  msgid "Premium support"
1030
  msgstr ""
1031
 
1032
- #: src/templates/may-also-like.php:212
1033
  msgid "Get your specific queries addressed directly by our experts"
1034
  msgstr ""
1035
 
1036
- #: src/templates/may-also-like.php:236
1037
  msgid "Our other plugins"
1038
  msgstr ""
1039
 
1040
- #: src/templates/may-also-like.php:253
1041
  msgid "UpdraftPlus"
1042
  msgstr ""
1043
 
1044
- #: src/templates/may-also-like.php:254
1045
  msgid "UpdraftPlus – the ultimate protection for your site, hard work and business"
1046
  msgstr ""
1047
 
1048
- #: src/templates/may-also-like.php:257
1049
  msgid "If you’ve got a WordPress website, you need a backup."
1050
  msgstr ""
1051
 
1052
- #: src/templates/may-also-like.php:260
1053
  msgid "Hacking, server crashes, dodgy updates or simple user error can ruin everything."
1054
  msgstr ""
1055
 
1056
- #: src/templates/may-also-like.php:263
1057
  msgid "With UpdraftPlus, you can rest assured that if the worst does happen, it's no big deal. rather than losing everything, you can simply restore the backup and be up and running again in no time at all."
1058
  msgstr ""
1059
 
1060
- #: src/templates/may-also-like.php:266
1061
  msgid "You can also migrate your website with few clicks without hassle."
1062
  msgstr ""
1063
 
1064
- #: src/templates/may-also-like.php:269
1065
  msgid "With a long-standing reputation for excellence and outstanding reviews, it’s no wonder that UpdraftPlus is the world’s most popular WordPress backup plugin."
1066
  msgstr ""
1067
 
1068
- #: src/templates/may-also-like.php:271, src/templates/may-also-like.php:290, src/templates/may-also-like.php:311, src/templates/may-also-like.php:328
1069
  msgid "Try for free"
1070
  msgstr ""
1071
 
1072
- #: src/templates/may-also-like.php:277
1073
  msgid ""
1074
  "UpdraftCentral Dashboard\n"
1075
  ""
1076
  msgstr ""
1077
 
1078
- #: src/templates/may-also-like.php:279
1079
  msgid "UpdraftCentral – save hours managing multiple WP sites from one place"
1080
  msgstr ""
1081
 
1082
- #: src/templates/may-also-like.php:282
1083
  msgid "If you manage a few WordPress sites, you need UpdraftCentral."
1084
  msgstr ""
1085
 
1086
- #: src/templates/may-also-like.php:285
1087
  msgid "UpdraftCentral is a powerful tool that allows you to efficiently manage, update, backup and even restore multiple websites from just one location. You can also manage users and comments on all the sites at once, and through its central login feature, you can access each WP-dashboard with a single click."
1088
  msgstr ""
1089
 
1090
- #: src/templates/may-also-like.php:288
1091
  msgid "With a wide range of useful features, including automated backup schedules and sophisticated one click updates, UpdraftCentral is sure to boost to your productivity and save you time."
1092
  msgstr ""
1093
 
1094
- #: src/templates/may-also-like.php:296
1095
  msgid "Meta Slider"
1096
  msgstr ""
1097
 
1098
- #: src/templates/may-also-like.php:297
1099
  msgid "MetaSlider - hold visitors’ attention to increase conversion and profits."
1100
  msgstr ""
1101
 
1102
- #: src/templates/may-also-like.php:300
1103
  msgid "With Metaslider, WordPress’ most popular slider plugin, you can add unique, SEO-optimizing slideshow to your blog or website in a matter of seconds!"
1104
  msgstr ""
1105
 
1106
- #: src/templates/may-also-like.php:303
1107
  msgid "Sliders instantly make a web-page more eye-catching and engaging."
1108
  msgstr ""
1109
 
1110
- #: src/templates/may-also-like.php:306
1111
  msgid "With Metaslider, creating them couldn’t be easier: simply select images from your WordPress Media Library, drag and drop them into place. You can then set the slide captions, links and SEO fields all from one page."
1112
  msgstr ""
1113
 
1114
- #: src/templates/may-also-like.php:309
1115
  msgid "Easily improve the look of your site, your conversion rate and bottom line."
1116
  msgstr ""
1117
 
1118
- #: src/templates/may-also-like.php:316
1119
  msgid "Keyy Two Factor Authentication"
1120
  msgstr ""
1121
 
1122
- #: src/templates/may-also-like.php:317
1123
  msgid "Keyy – instant &amp; secure logins with a wave of your phone"
1124
  msgstr ""
1125
 
1126
- #: src/templates/may-also-like.php:320
1127
  msgid "Keyy is a unique 2-factor authentication plugin that allows you to log in to your website with just a wave of your smartphone. It represents the ultimate UX, doing away with the need for usernames, passwords and other 2FA tokens."
1128
  msgstr ""
1129
 
1130
- #: src/templates/may-also-like.php:323
1131
  msgid "Using innovative RSA public-key cryptography, Keyy is highly secure and prevents password-based hacking risks such as brute-forcing, key-logging, shoulder-surfing and connection sniffing."
1132
  msgstr ""
1133
 
1134
- #: src/templates/may-also-like.php:326
1135
  msgid "Logging in with Keyy is simple. Once users have installed the app onto their smartphone and secured it using a fingerprint or 4-number pin, they just open the app, point it at the moving on-screen barcode and voila!"
1136
  msgstr ""
1137
 
1138
- #: src/templates/notices/horizontal-notice.php:6
1139
- msgid "notice image"
1140
  msgstr ""
1141
 
1142
- #: src/templates/notices/horizontal-notice.php:16, src/templates/notices/horizontal-notice.php:18
1143
- msgid "Dismiss"
1144
  msgstr ""
1145
 
1146
- #: src/templates/notices/horizontal-notice.php:31
1147
- msgid "Get UpdraftCentral"
1148
  msgstr ""
1149
 
1150
- #: src/templates/notices/horizontal-notice.php:33
1151
- msgid "Review WP-Optimize"
1152
  msgstr ""
1153
 
1154
- #: src/templates/notices/horizontal-notice.php:35
1155
- msgid "Get UpdraftPlus"
1156
  msgstr ""
1157
 
1158
- #: src/templates/notices/horizontal-notice.php:37
1159
- msgid "Sign up"
1160
  msgstr ""
1161
 
1162
- #: src/templates/notices/horizontal-notice.php:39
1163
- msgid "Go there"
1164
  msgstr ""
1165
 
1166
- #: src/templates/notices/horizontal-notice.php:41, src/templates/notices/horizontal-notice.php:43
1167
- msgid "Find out more."
1168
  msgstr ""
1169
 
1170
- #: src/templates/notices/thanks-for-using-main-dash.php:5
1171
- msgid "Dismiss (for %s months)"
1172
  msgstr ""
1173
 
1174
- #: src/templates/notices/thanks-for-using-main-dash.php:7
1175
- msgid "Thank you for installing WP-Optimize!"
1176
  msgstr ""
1177
 
1178
- #: src/templates/notices/thanks-for-using-main-dash.php:14
1179
- msgid "Super-charge and secure your WordPress site with our other top plugins:"
1180
  msgstr ""
1181
 
1182
- #: src/templates/notices/thanks-for-using-main-dash.php:18
1183
- msgid "%s offers powerful extra features and flexibility, and WordPress multisite support."
1184
  msgstr ""
1185
 
1186
- #: src/templates/notices/thanks-for-using-main-dash.php:18
1187
- msgid "WP-Optimize Premium:"
1188
  msgstr ""
1189
 
1190
- #: src/templates/notices/thanks-for-using-main-dash.php:22
1191
- msgid "%s simplifies backups and restoration. It is the world’s highest ranking and most popular scheduled backup plugin, with over a million currently-active installs."
1192
  msgstr ""
1193
 
1194
- #: src/templates/notices/thanks-for-using-main-dash.php:26
1195
- msgid "%s is a highly efficient way to manage, optimize, update and backup multiple websites from one place."
1196
  msgstr ""
1197
 
1198
- #: src/templates/notices/thanks-for-using-main-dash.php:30
1199
- msgid "Keyy:"
1200
  msgstr ""
1201
 
1202
- #: src/templates/notices/thanks-for-using-main-dash.php:30
1203
- msgid "Simple & secure login with a wave of your phone"
1204
  msgstr ""
1205
 
1206
- #: src/templates/notices/thanks-for-using-main-dash.php:34
1207
- msgid "Add style and flare easily with beautifully-designed sliders with the #1 WP slider plugin"
1208
  msgstr ""
1209
 
1210
- #: src/templates/notices/thanks-for-using-main-dash.php:38
1211
- msgid "Premium WooCommerce extensions"
1212
  msgstr ""
1213
 
1214
- #: src/templates/optimizations-table.php:7
1215
- msgid "Optimization"
1216
  msgstr ""
1217
 
1218
- #: src/templates/optimizations-table.php:8
1219
- msgid "Notes"
1220
  msgstr ""
1221
 
1222
- #: src/templates/optimizations-table.php:71
1223
- msgid "Run optimization"
1224
  msgstr ""
1225
 
1226
- #: src/templates/optimizations-table.php:73
1227
- msgid "Go"
1228
  msgstr ""
1229
 
1230
- #: src/templates/optimize-table.php:6
1231
- msgid "Warning: This operation is permanent. Continue?"
1232
  msgstr ""
1233
 
1234
- #: src/templates/optimize-table.php:14
1235
- msgid "Optimizations"
1236
  msgstr ""
1237
 
1238
- #: src/templates/optimize-table.php:17
1239
- msgid "Run all selected optimizations"
1240
  msgstr ""
1241
 
1242
- #: src/templates/optimize-table.php:26
1243
- msgid "Warning:"
1244
  msgstr ""
1245
 
1246
- #: src/templates/optimize-table.php:26
1247
- msgid "Items marked in red perform more intensive database operations. In very rare cases, if your database server happened to crash or be forcibly powered down at the same time as an optimization operation was running, data might be corrupted. "
1248
  msgstr ""
1249
 
1250
- #: src/templates/optimize-table.php:26
1251
- msgid "You may wish to run a backup before optimizing."
 
 
 
 
1252
  msgstr ""
1253
 
1254
- #: src/templates/status-box-contents.php:16
1255
  msgid "running on:"
1256
  msgstr ""
1257
 
1258
- #: src/templates/status-box-contents.php:16
1259
  msgid "MySQL"
1260
  msgstr ""
1261
 
1262
- #: src/templates/status-box-contents.php:25
1263
  msgid "Last scheduled optimization was at"
1264
  msgstr ""
1265
 
1266
- #: src/templates/status-box-contents.php:30
1267
  msgid "There was no scheduled optimization"
1268
  msgstr ""
1269
 
1270
- #: src/templates/status-box-contents.php:56
1271
- msgid "Scheduled cleaning enabled"
1272
  msgstr ""
1273
 
1274
- #: src/templates/status-box-contents.php:68
1275
  msgid "Next schedule:"
1276
  msgstr ""
1277
 
1278
- #: src/templates/status-box-contents.php:73
1279
  msgid "Refresh"
1280
  msgstr ""
1281
 
1282
- #: src/templates/status-box-contents.php:77
1283
  msgid "Scheduled cleaning disabled"
1284
  msgstr ""
1285
 
1286
- #: src/templates/status-box-contents.php:84
1287
  msgid "Keeping last %s weeks data"
1288
  msgstr ""
1289
 
1290
- #: src/templates/status-box-contents.php:87
1291
  msgid "Not keeping recent data"
1292
  msgstr ""
1293
 
1294
- #: src/templates/status-box-contents.php:93
1295
  msgid "Current database size:"
1296
  msgstr ""
1297
 
1298
- #: src/templates/status-box-contents.php:100
1299
  msgid "You have saved:"
1300
  msgstr ""
1301
 
1302
- #: src/templates/status-box-contents.php:104
1303
  msgid "You can save around:"
1304
  msgstr ""
1305
 
1306
- #: src/templates/status-box-contents.php:117
1307
  msgid "Total clean up overall:"
1308
  msgstr ""
1309
 
1310
- #: src/templates/status-box-contents.php:131
1311
  msgid "Your database has %s corrupted table."
1312
  msgid_plural "Your database has %s corrupted tables."
1313
  msgstr[0] ""
1314
  msgstr[1] ""
1315
 
1316
- #: src/templates/status-box-contents.php:132
1317
  msgid "Repair corrupted tables here."
1318
  msgstr ""
1319
 
1320
- #: src/templates/status-box-contents.php:136
1321
  msgid "Support and feedback"
1322
  msgstr ""
1323
 
1324
- #: src/templates/status-box-contents.php:138
1325
- msgid "If you like WP-Optimize,"
1326
- msgstr ""
1327
-
1328
- #: src/templates/status-box-contents.php:138
1329
- msgid "please give us a positive review, here."
1330
- msgstr ""
1331
-
1332
- #: src/templates/status-box-contents.php:138
1333
- msgid "Or, if you did not like it,"
1334
  msgstr ""
1335
 
1336
- #: src/templates/status-box-contents.php:138
1337
- msgid "please tell us why at this link."
1338
- msgstr ""
1339
-
1340
- #: src/templates/status-box-contents.php:139
1341
  msgid "Support is available here."
1342
  msgstr ""
1343
 
1344
- #: src/templates/tables-body.php:67
1345
- msgid "Total:"
1346
- msgstr ""
1347
-
1348
- #: src/templates/tables-body.php:68
1349
- msgid "%s Table"
1350
- msgid_plural "%s Tables"
1351
- msgstr[0] ""
1352
- msgstr[1] ""
1353
-
1354
- #: src/templates/tables.php:3
1355
- msgid "Database name:"
1356
- msgstr ""
1357
-
1358
- #: src/templates/tables.php:9
1359
- msgid "Optimized all the tables found in the database."
1360
- msgstr ""
1361
-
1362
- #: src/templates/tables.php:17
1363
- msgid "Search for table"
1364
- msgstr ""
1365
-
1366
- #: src/templates/tables.php:21
1367
- msgid "No."
1368
- msgstr ""
1369
-
1370
- #: src/templates/tables.php:22
1371
- msgid "Table"
1372
- msgstr ""
1373
-
1374
- #: src/templates/tables.php:23
1375
- msgid "Records"
1376
- msgstr ""
1377
-
1378
- #: src/templates/tables.php:24
1379
- msgid "Data Size"
1380
- msgstr ""
1381
-
1382
- #: src/templates/tables.php:25
1383
- msgid "Index Size"
1384
- msgstr ""
1385
-
1386
- #: src/templates/tables.php:26
1387
- msgid "Type"
1388
- msgstr ""
1389
-
1390
- #: src/templates/tables.php:27
1391
- msgid "Overhead"
1392
- msgstr ""
1393
-
1394
- #: src/templates/tables.php:36
1395
- msgid "Tables not found."
1396
  msgstr ""
1397
 
1398
- #: src/templates/tables.php:37
1399
- msgid "Total size of database:"
1400
  msgstr ""
1401
 
1402
- #: src/templates/tables.php:48
1403
- msgid "Optimization results:"
1404
  msgstr ""
1405
 
1406
- #: src/templates/tables.php:52
1407
- msgid "Total space saved:"
1408
  msgstr ""
1409
 
1410
  #: src/templates/take-a-backup.php:17
1411
  msgid "Backup before running optimizations"
1412
  msgstr ""
1413
 
1414
- #: src/templates/take-a-backup.php:64
1415
  msgid "Take a backup with UpdraftPlus before doing this"
1416
  msgstr ""
1417
 
1418
- #: src/templates/take-a-backup.php:71
1419
  msgid "Follow this link to install UpdraftPlus, to take a backup before optimization"
1420
  msgstr ""
1421
 
1422
- #: src/templates/take-a-backup.php:87
1423
  msgid "UpdraftPlus needs to be updated to 1.12.33 or higher in order to backup the database before optimization."
1424
  msgstr ""
1425
 
1426
- #: src/templates/take-a-backup.php:87
1427
  msgid "Please update UpdraftPlus to the latest version."
1428
  msgstr ""
1429
 
1430
- #: src/templates/take-a-backup.php:90
1431
  msgid "UpdraftPlus is installed but currently not active. Follow this link to activate UpdraftPlus, to take a backup before optimization."
1432
  msgstr ""
1433
 
1434
- #: src/wp-optimize.php:269
1435
  msgid "WP-Optimize (Free) has been de-activated, because WP-Optimize Premium is active."
1436
  msgstr ""
1437
 
1438
- #: src/wp-optimize.php:279
1439
  msgid "New feature: WP-Optimize Premium can now optimize all sites within a multisite install, not just the main one."
1440
  msgstr ""
1441
 
1442
- #: src/wp-optimize.php:394
1443
- msgid "Table information"
1444
  msgstr ""
1445
 
1446
- #: src/wp-optimize.php:394, src/wp-optimize.php:595
1447
- msgid "Settings"
 
 
 
 
 
 
 
 
1448
  msgstr ""
1449
 
1450
- #: src/wp-optimize.php:394
 
 
 
 
1451
  msgid "Premium / Plugin family"
1452
  msgstr ""
1453
 
1454
- #: src/wp-optimize.php:536
1455
  msgid "Automatic backup before optimizations"
1456
  msgstr ""
1457
 
1458
- #: src/wp-optimize.php:537
1459
  msgid "An unexpected response was received."
1460
  msgstr ""
1461
 
1462
- #: src/wp-optimize.php:538
1463
  msgid "Optimization complete"
1464
  msgstr ""
1465
 
1466
- #: src/wp-optimize.php:539
1467
  msgid "Run optimizations"
1468
  msgstr ""
1469
 
1470
- #: src/wp-optimize.php:540
1471
  msgid "Cancel"
1472
  msgstr ""
1473
 
1474
- #: src/wp-optimize.php:541
1475
  msgid "Please, select settings file."
1476
  msgstr ""
1477
 
1478
- #: src/wp-optimize.php:542
1479
  msgid "Are you sure you want to remove this logging destination?"
1480
  msgstr ""
1481
 
1482
- #: src/wp-optimize.php:543
1483
  msgid "Before saving, you need to complete the currently incomplete settings (or remove them)."
1484
  msgstr ""
1485
 
1486
- #: src/wp-optimize.php:544
1487
- msgid "%s was not repaired. For more details, please check your logs configured in logging destinations settings."
 
 
 
 
 
 
 
 
1488
  msgstr ""
1489
 
1490
- #: src/wp-optimize.php:576
1491
- msgid "Optimize"
1492
  msgstr ""
1493
 
1494
- #: src/wp-optimize.php:598
 
 
 
 
1495
  msgid "Optimizer"
1496
  msgstr ""
1497
 
1498
- #: src/wp-optimize.php:614
1499
  msgid "Repair"
1500
  msgstr ""
1501
 
1502
- #: src/wp-optimize.php:720
 
 
 
 
1503
  msgid "Warning"
1504
  msgstr ""
1505
 
1506
- #: src/wp-optimize.php:720
1507
  msgid "WordPress has a number (%d) of scheduled tasks which are overdue. Unless this is a development site, this probably means that the scheduler in your WordPress install is not working."
1508
  msgstr ""
1509
 
1510
- #: src/wp-optimize.php:720
1511
  msgid "Read this page for a guide to possible causes and how to fix it."
1512
  msgstr ""
1513
 
1514
- #: src/wp-optimize.php:787
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1515
  msgid "Error:"
1516
  msgstr ""
1517
 
1518
- #: src/wp-optimize.php:787
1519
  msgid "template not found"
1520
  msgstr ""
1521
 
1522
- #: src/wp-optimize.php:839
1523
  msgid "Automatic Operation Completed"
1524
  msgstr ""
1525
 
1526
- #: src/wp-optimize.php:841
1527
  msgid "Scheduled optimization was executed at"
1528
  msgstr ""
1529
 
1530
- #: src/wp-optimize.php:842
1531
  msgid "You can safely delete this email."
1532
  msgstr ""
1533
 
1534
- #: src/wp-optimize.php:844
1535
  msgid "Regards,"
1536
  msgstr ""
1537
 
1538
- #: src/wp-optimize.php:845
1539
  msgid "WP-Optimize Plugin"
1540
  msgstr ""
1541
 
1542
- #: src/wp-optimize.php:867
1543
  msgid "GB"
1544
  msgstr ""
1545
 
1546
- #: src/wp-optimize.php:869
1547
  msgid "MB"
1548
  msgstr ""
1549
 
1550
- #: src/wp-optimize.php:871
1551
  msgid "KB"
1552
  msgstr ""
1553
 
1554
- #: src/wp-optimize.php:873
1555
  msgid "bytes"
1556
  msgstr ""
1557
 
1558
- #: src/wp-optimize.php:1192
1559
  msgid "You have no permissions to run optimizations."
1560
  msgstr ""
1561
 
1562
- #: src/wp-optimize.php:1199
1563
  msgid "You have no permissions to manage WP-Optimize settings."
1564
  msgstr ""
1565
 
1566
- #: src/wp-optimize.php:1349
1567
  msgid "Only Network Administrator can activate WP-Optimize plugin."
1568
  msgstr ""
1569
 
1570
- #: src/wp-optimize.php:1350
1571
  msgid "go back"
1572
  msgstr ""
1
+ # Copyright (C) 2019 wp-optimize
2
  # This file is distributed under the same license as the wp-optimize package.
3
  msgid ""
4
  msgstr ""
7
  "MIME-Version: 1.0\n"
8
  "Content-Type: text/plain; charset=UTF-8\n"
9
  "Content-Transfer-Encoding: 8bit\n"
10
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
11
  "Last-Translator: John Doe <mail@example.com>\n"
12
  "Language-Team: Team Updraft <mail@example.com>\n"
13
  "X-Poedit-Basepath: ..\n"
17
  "X-Poedit-SearchPathExcluded-0: *.js\n"
18
  "Plural-Forms: nplurals=2; plural=(n != 1);\n"
19
 
20
+ #: src/includes/class-commands.php:184, src/includes/class-commands.php:228, src/includes/class-commands.php:270
21
  msgid "No optimization was indicated."
22
  msgstr ""
23
 
24
+ #: src/includes/class-commands.php:401, src/includes/class-commands.php:410
25
  msgid "Please upload a valid settings file."
26
  msgstr ""
27
 
58
  msgstr ""
59
 
60
  #: src/includes/class-updraft-smush-manager-commands.php:142
61
+ msgid "A total of %d image(s) were compressed on this site, saving approximately %s of space at an average of %02d percent per image."
62
  msgstr ""
63
 
64
  #: src/includes/class-updraft-smush-manager-commands.php:143
94
  msgstr ""
95
 
96
  #: src/includes/class-updraft-smush-manager-commands.php:255
97
+ msgid "Log file does not exist or could not be read"
98
  msgstr ""
99
 
100
  #: src/includes/class-updraft-smush-manager.php:212
110
  msgstr ""
111
 
112
  #: src/includes/class-updraft-smush-manager.php:434
113
+ msgid "All valid images are compressed now"
114
  msgstr ""
115
 
116
  #: src/includes/class-updraft-smush-manager.php:435
158
  msgstr ""
159
 
160
  #: src/includes/class-updraft-smush-task.php:237
161
+ msgid "Saving optimized image"
162
  msgstr ""
163
 
164
  #: src/includes/class-updraft-smush-task.php:238
169
  msgid "Preview found items"
170
  msgstr ""
171
 
172
+ #: src/includes/class-wp-optimize-browser-cache.php:59
173
+ msgid "We successfully updated your .htaccess file. But it seems one of Apache modules - mod_expires or mod_headers is not active."
174
+ msgstr ""
175
+
176
+ #: src/includes/class-wp-optimize-browser-cache.php:113
177
+ msgid "Browser static caching settings already exists in the .htaccess file"
178
+ msgstr ""
179
+
180
+ #: src/includes/class-wp-optimize-browser-cache.php:156
181
+ msgid "We successfully updated your .htaccess file."
182
+ msgstr ""
183
+
184
+ #: src/includes/class-wp-optimize-browser-cache.php:163, src/includes/class-wp-optimize-gzip-compression.php:188
185
+ msgid "We can't update your %s file. Please try to add following lines manually:"
186
+ msgstr ""
187
+
188
+ #: src/includes/class-wp-optimize-browser-cache.php:168, src/includes/class-wp-optimize-gzip-compression.php:186
189
+ msgid "We can't update your %s file. Please try to remove following lines manually:"
190
+ msgstr ""
191
+
192
+ #: src/includes/class-wp-optimize-gzip-compression.php:84, src/includes/class-wp-optimize-gzip-compression.php:88
193
+ msgid "We can't definitely determine Gzip status as API doesn't return correct answer."
194
+ msgstr ""
195
+
196
+ #: src/includes/class-wp-optimize-gzip-compression.php:114
197
+ msgid "We successfully added Gzip compression settings into .htaccess file. But it seems one of Apache modules - mod_filter or mod_deflate is not active."
198
+ msgstr ""
199
+
200
  #: src/includes/class-wp-optimize-options.php:142
201
  msgid "Auto backup option updated."
202
  msgstr ""
209
  msgid "No such optimization"
210
  msgstr ""
211
 
212
+ #: src/includes/class-wp-optimizer.php:470
213
  msgid "Comments have now been disabled on all current and previously published posts."
214
  msgstr ""
215
 
216
+ #: src/includes/class-wp-optimizer.php:473
217
  msgid "Comments have now been enabled on all current and previously published posts."
218
  msgstr ""
219
 
220
+ #: src/includes/class-wp-optimizer.php:480
221
  msgid "Trackbacks have now been disabled on all current and previously published posts."
222
  msgstr ""
223
 
224
+ #: src/includes/class-wp-optimizer.php:483
225
  msgid "Trackbacks have now been enabled on all current and previously published posts."
226
  msgstr ""
227
 
228
+ #: src/includes/wp-optimize-database-information.php:411, src/includes/wp-optimize-database-information.php:456, src/templates/database/tables-body.php:29, src/wp-optimize.php:880
229
+ msgid "WordPress core"
230
+ msgstr ""
231
+
232
  #: src/includes/wp-optimize-notices.php:41
233
  msgid "Make sure you backup before you optimize your database"
234
  msgstr ""
483
  msgid "Clean orphaned relationship data"
484
  msgstr ""
485
 
486
+ #: src/optimizations/orphanedtables.php:112, src/optimizations/repairtables.php:142
487
+ msgid "No corrupted tables found"
488
+ msgstr ""
489
+
490
+ #: src/optimizations/orphanedtables.php:124
491
+ msgid "Delete orphaned database tables"
492
+ msgstr ""
493
+
494
  #: src/optimizations/pingbacks.php:50, src/optimizations/spam.php:83, src/optimizations/trackbacks.php:51, src/optimizations/unapproved.php:66
495
  msgid "Author"
496
  msgstr ""
547
  msgid "Remove orphaned post meta"
548
  msgstr ""
549
 
 
 
 
 
550
  #: src/optimizations/repairtables.php:154
551
  msgid "Repair database tables"
552
  msgstr ""
753
  msgid "Remove unapproved comments"
754
  msgstr ""
755
 
756
+ #: src/templates/admin-page-header-tabs.php:30, src/templates/pages-menu.php:5
757
+ msgid "Menu"
758
+ msgstr ""
759
+
760
+ #: src/templates/admin-page-header.php:5, src/templates/pages-menu.php:24
761
+ msgid "Useful links"
762
  msgstr ""
763
 
764
+ #: src/templates/admin-page-header.php:6, src/templates/pages-menu.php:25
765
  msgid "Home"
766
  msgstr ""
767
 
768
+ #: src/templates/admin-page-header.php:10, src/templates/pages-menu.php:29
769
  msgid "News"
770
  msgstr ""
771
 
772
+ #: src/templates/admin-page-header.php:12, src/templates/pages-menu.php:31
773
  msgid "Twitter"
774
  msgstr ""
775
 
776
+ #: src/templates/admin-page-header.php:14, src/templates/pages-menu.php:33
777
  msgid "Support"
778
  msgstr ""
779
 
780
+ #: src/templates/admin-page-header.php:16, src/templates/pages-menu.php:35
781
+ msgid "Newsletter"
782
  msgstr ""
783
 
784
+ #: src/templates/admin-page-header.php:18, src/templates/pages-menu.php:37
785
+ msgid "Team lead"
786
  msgstr ""
787
 
788
+ #: src/templates/admin-page-header.php:20, src/templates/pages-menu.php:39, src/templates/settings/may-also-like.php:8
789
  msgid "FAQs"
790
  msgstr ""
791
 
792
+ #: src/templates/admin-page-header.php:22, src/templates/pages-menu.php:41, src/wp-optimize.php:1068, src/wp-optimize.php:1069
793
  msgid "More plugins"
794
  msgstr ""
795
 
796
+ #: src/templates/admin-page-header.php:29, src/templates/settings/may-also-like.php:26
797
+ msgid "Premium"
798
  msgstr ""
799
 
800
+ #: src/templates/admin-page-header.php:31
801
+ msgid "The #1 optimization plugin!"
802
  msgstr ""
803
 
804
+ #: src/templates/cache/browser-cache.php:4
805
+ msgid "Browser static file caching settings"
806
  msgstr ""
807
 
808
+ #: src/templates/cache/browser-cache.php:19
809
+ msgid "Browser static file caching uses HTTP response headers to advise a visitor's browser to cache non-changing files for a while, so that it doesn’t need to retrieve them upon every visit."
810
  msgstr ""
811
 
812
+ #: src/templates/cache/browser-cache.php:22, src/templates/cache/browser-cache.php:23
813
+ msgid "Browser static file caching headers are currently %s."
814
  msgstr ""
815
 
816
+ #: src/templates/cache/browser-cache.php:22, src/templates/settings/status-box-contents.php:58
817
+ msgid "enabled"
818
  msgstr ""
819
 
820
+ #: src/templates/cache/browser-cache.php:23
821
+ msgid "disabled"
822
  msgstr ""
823
 
824
+ #: src/templates/cache/browser-cache.php:32, src/wp-optimize.php:786
825
+ msgid "Update"
826
  msgstr ""
827
 
828
+ #: src/templates/cache/browser-cache.php:32, src/templates/cache/gzip-compression.php:43, src/templates/settings/settings-trackback-and-comments.php:13, src/templates/settings/settings-trackback-and-comments.php:29, src/wp-optimize.php:775, src/wp-optimize.php:785
829
+ msgid "Enable"
830
  msgstr ""
831
 
832
+ #: src/templates/cache/browser-cache.php:35
833
+ msgid "Expiration time:"
834
  msgstr ""
835
 
836
+ #: src/templates/cache/browser-cache.php:37
837
+ msgid "day(s)"
838
  msgstr ""
839
 
840
+ #: src/templates/cache/browser-cache.php:39
841
+ msgid "hour(s)"
842
  msgstr ""
843
 
844
+ #: src/templates/cache/browser-cache.php:44
845
+ msgid "Make the time empty or zero to disable the headers."
846
  msgstr ""
847
 
848
+ #: src/templates/cache/gzip-compression.php:20
849
+ msgid "GZip compression has been enabled by something other than WP-Optimize."
850
  msgstr ""
851
 
852
+ #: src/templates/cache/gzip-compression.php:27
853
+ msgid "Gzip compression improves the performance of your website and decreases its loading time. When a visitor makes a request for your website, the server compresses the requested page and transfers it to the customer's computer."
854
  msgstr ""
855
 
856
+ #: src/templates/cache/gzip-compression.php:33
857
+ msgid "Gzip compression is currently ENABLED."
858
  msgstr ""
859
 
860
+ #: src/templates/cache/gzip-compression.php:34
861
+ msgid "Gzip compression is currently DISABLED."
862
  msgstr ""
863
 
864
+ #: src/templates/cache/gzip-compression.php:43, src/templates/settings/settings-trackback-and-comments.php:15, src/templates/settings/settings-trackback-and-comments.php:31, src/wp-optimize.php:776
865
+ msgid "Disable"
866
  msgstr ""
867
 
868
+ #: src/templates/database/optimizations-table.php:7
869
+ msgid "Optimization"
870
  msgstr ""
871
 
872
+ #: src/templates/database/optimizations-table.php:79
873
+ msgid "Run optimization"
874
  msgstr ""
875
 
876
+ #: src/templates/database/optimizations-table.php:81
877
+ msgid "Go"
878
  msgstr ""
879
 
880
+ #: src/templates/database/optimize-table.php:21
881
+ msgid "Warning: This operation is permanent. Continue?"
882
  msgstr ""
883
 
884
+ #: src/templates/database/optimize-table.php:25, src/wp-optimize.php:484
885
+ msgid "Optimizations"
886
+ msgstr ""
887
+
888
+ #: src/templates/database/optimize-table.php:29
889
+ msgid "Run all selected optimizations"
890
+ msgstr ""
891
+
892
+ #: src/templates/database/optimize-table.php:38
893
+ msgid "Warning:"
894
+ msgstr ""
895
+
896
+ #: src/templates/database/optimize-table.php:38
897
+ msgid "Items marked with this icon perform more intensive database operations. In very rare cases, if your database server happened to crash or be forcibly powered down at the same time as an optimization operation was running, data might be corrupted. "
898
+ msgstr ""
899
+
900
+ #: src/templates/database/optimize-table.php:38
901
+ msgid "You may wish to run a backup before optimizing."
902
+ msgstr ""
903
+
904
+ #: src/templates/database/tables-body.php:24, src/templates/database/tables.php:22
905
+ msgid "No."
906
+ msgstr ""
907
+
908
+ #: src/templates/database/tables-body.php:25, src/templates/database/tables.php:23
909
+ msgid "Table"
910
+ msgstr ""
911
+
912
+ #: src/templates/database/tables-body.php:28
913
+ msgid "Belongs to:"
914
+ msgstr ""
915
+
916
+ #: src/templates/database/tables-body.php:35
917
+ msgid "not installed"
918
+ msgstr ""
919
+
920
+ #: src/templates/database/tables-body.php:37
921
+ msgid "inactive"
922
+ msgstr ""
923
+
924
+ #: src/templates/database/tables-body.php:44, src/templates/database/tables.php:24
925
+ msgid "Records"
926
+ msgstr ""
927
+
928
+ #: src/templates/database/tables-body.php:45, src/templates/database/tables.php:25
929
+ msgid "Data Size"
930
+ msgstr ""
931
+
932
+ #: src/templates/database/tables-body.php:46, src/templates/database/tables.php:26
933
+ msgid "Index Size"
934
+ msgstr ""
935
+
936
+ #: src/templates/database/tables-body.php:49, src/templates/database/tables-body.php:62, src/templates/database/tables.php:27
937
+ msgid "Type"
938
+ msgstr ""
939
+
940
+ #: src/templates/database/tables-body.php:51, src/templates/database/tables-body.php:63, src/templates/database/tables.php:28
941
+ msgid "Overhead"
942
+ msgstr ""
943
+
944
+ #: src/templates/database/tables-body.php:70, src/templates/database/tables-body.php:99, src/templates/database/tables.php:29, src/templates/settings/settings-logging.php:25
945
  msgid "Actions"
946
  msgstr ""
947
 
948
+ #: src/templates/database/tables-body.php:85
949
+ msgid "Total:"
950
  msgstr ""
951
 
952
+ #: src/templates/database/tables-body.php:86
953
+ msgid "%s Table"
954
+ msgid_plural "%s Tables"
955
+ msgstr[0] ""
956
+ msgstr[1] ""
957
+
958
+ #: src/templates/database/tables.php:7
959
+ msgid "Optimized all the tables found in the database."
960
  msgstr ""
961
 
962
+ #: src/templates/database/tables.php:16
963
+ msgid "Take a backup with UpdraftPlus before any actions upon tables (recommended)."
964
  msgstr ""
965
 
966
+ #: src/templates/database/tables.php:18
967
+ msgid "Database name:"
968
  msgstr ""
969
 
970
+ #: src/templates/database/tables.php:18
971
+ msgid "Refresh tables"
972
  msgstr ""
973
 
974
+ #: src/templates/database/tables.php:18
975
+ msgid "Search for table"
976
  msgstr ""
977
 
978
+ #: src/templates/database/tables.php:36
979
+ msgid "Tables not found."
980
  msgstr ""
981
 
982
+ #: src/templates/database/tables.php:37
983
+ msgid "Total size of database:"
984
  msgstr ""
985
 
986
+ #: src/templates/database/tables.php:48
987
+ msgid "Optimization results:"
988
  msgstr ""
989
 
990
+ #: src/templates/database/tables.php:52
991
+ msgid "Total space saved:"
992
+ msgstr ""
993
+
994
+ #: src/templates/notices/horizontal-notice.php:6
995
+ msgid "notice image"
996
+ msgstr ""
997
+
998
+ #: src/templates/notices/horizontal-notice.php:16, src/templates/notices/horizontal-notice.php:18
999
+ msgid "Dismiss"
1000
+ msgstr ""
1001
+
1002
+ #: src/templates/notices/horizontal-notice.php:31
1003
+ msgid "Get UpdraftCentral"
1004
+ msgstr ""
1005
+
1006
+ #: src/templates/notices/horizontal-notice.php:33
1007
+ msgid "Review WP-Optimize"
1008
+ msgstr ""
1009
+
1010
+ #: src/templates/notices/horizontal-notice.php:35
1011
+ msgid "Get UpdraftPlus"
1012
+ msgstr ""
1013
+
1014
+ #: src/templates/notices/horizontal-notice.php:37
1015
+ msgid "Sign up"
1016
+ msgstr ""
1017
+
1018
+ #: src/templates/notices/horizontal-notice.php:39
1019
+ msgid "Go there"
1020
+ msgstr ""
1021
+
1022
+ #: src/templates/notices/horizontal-notice.php:41, src/templates/notices/horizontal-notice.php:43
1023
+ msgid "Find out more."
1024
+ msgstr ""
1025
+
1026
+ #: src/templates/notices/thanks-for-using-main-dash.php:5
1027
+ msgid "Dismiss (for %s months)"
1028
+ msgstr ""
1029
+
1030
+ #: src/templates/notices/thanks-for-using-main-dash.php:7
1031
+ msgid "Thank you for installing WP-Optimize!"
1032
+ msgstr ""
1033
+
1034
+ #: src/templates/notices/thanks-for-using-main-dash.php:14
1035
+ msgid "Super-charge and secure your WordPress site with our other top plugins:"
1036
+ msgstr ""
1037
+
1038
+ #: src/templates/notices/thanks-for-using-main-dash.php:18
1039
+ msgid "%s offers powerful extra features and flexibility, and WordPress multisite support."
1040
+ msgstr ""
1041
+
1042
+ #: src/templates/notices/thanks-for-using-main-dash.php:18
1043
+ msgid "WP-Optimize Premium:"
1044
+ msgstr ""
1045
+
1046
+ #: src/templates/notices/thanks-for-using-main-dash.php:22
1047
+ msgid "%s simplifies backups and restoration. It is the world’s highest ranking and most popular scheduled backup plugin, with over a million currently-active installs."
1048
+ msgstr ""
1049
+
1050
+ #: src/templates/notices/thanks-for-using-main-dash.php:26
1051
+ msgid "%s is a highly efficient way to manage, optimize, update and backup multiple websites from one place."
1052
+ msgstr ""
1053
+
1054
+ #: src/templates/notices/thanks-for-using-main-dash.php:30
1055
+ msgid "Keyy:"
1056
+ msgstr ""
1057
+
1058
+ #: src/templates/notices/thanks-for-using-main-dash.php:30
1059
+ msgid "Simple & secure login with a wave of your phone"
1060
  msgstr ""
1061
 
1062
+ #: src/templates/notices/thanks-for-using-main-dash.php:34
1063
+ msgid "Add style and flare easily with beautifully-designed sliders with the #1 WP slider plugin"
1064
+ msgstr ""
1065
+
1066
+ #: src/templates/notices/thanks-for-using-main-dash.php:38
1067
+ msgid "Premium WooCommerce extensions"
1068
+ msgstr ""
1069
+
1070
+ #: src/templates/settings/may-also-like.php:4
1071
  msgid "WP-Optimize free / premium comparison"
1072
  msgstr ""
1073
 
1074
+ #: src/templates/settings/may-also-like.php:10
1075
  msgid "Ask a pre-sales question"
1076
  msgstr ""
1077
 
1078
+ #: src/templates/settings/may-also-like.php:21, src/templates/settings/may-also-like.php:26
1079
  msgid "WP-Optimize"
1080
  msgstr ""
1081
 
1082
+ #: src/templates/settings/may-also-like.php:21
1083
  msgid "Free"
1084
  msgstr ""
1085
 
1086
+ #: src/templates/settings/may-also-like.php:24
1087
  msgid "WP-Optimize Premium"
1088
  msgstr ""
1089
 
1090
+ #: src/templates/settings/may-also-like.php:32, src/templates/settings/may-also-like.php:223
1091
  msgid "Installed"
1092
  msgstr ""
1093
 
1094
+ #: src/templates/settings/may-also-like.php:35, src/templates/settings/may-also-like.php:226
1095
  msgid "Upgrade now"
1096
  msgstr ""
1097
 
1098
+ #: src/templates/settings/may-also-like.php:40, src/templates/settings/may-also-like.php:41
1099
  msgid "Auto-optimize database"
1100
  msgstr ""
1101
 
1102
+ #: src/templates/settings/may-also-like.php:42
1103
  msgid "Optimizes without the need for manual queries"
1104
  msgstr ""
1105
 
1106
+ #: src/templates/settings/may-also-like.php:45, src/templates/settings/may-also-like.php:48, src/templates/settings/may-also-like.php:58, src/templates/settings/may-also-like.php:61, src/templates/settings/may-also-like.php:71, src/templates/settings/may-also-like.php:74, src/templates/settings/may-also-like.php:84, src/templates/settings/may-also-like.php:87, src/templates/settings/may-also-like.php:97, src/templates/settings/may-also-like.php:100, src/templates/settings/may-also-like.php:110, src/templates/settings/may-also-like.php:113, src/templates/settings/may-also-like.php:126, src/templates/settings/may-also-like.php:139, src/templates/settings/may-also-like.php:152, src/templates/settings/may-also-like.php:165, src/templates/settings/may-also-like.php:178, src/templates/settings/may-also-like.php:191, src/templates/settings/may-also-like.php:204, src/templates/settings/may-also-like.php:217
1107
  msgid "Yes"
1108
  msgstr ""
1109
 
1110
+ #: src/templates/settings/may-also-like.php:53, src/templates/settings/may-also-like.php:54
1111
  msgid "Scheduled clean-ups"
1112
  msgstr ""
1113
 
1114
+ #: src/templates/settings/may-also-like.php:55
1115
  msgid "Carries out scheduled clean-ups daily, weekly, fortnightly and monthly"
1116
  msgstr ""
1117
 
1118
+ #: src/templates/settings/may-also-like.php:66, src/templates/settings/may-also-like.php:67
1119
  msgid "Displays database table statistics"
1120
  msgstr ""
1121
 
1122
+ #: src/templates/settings/may-also-like.php:68
1123
  msgid "Displays database table statistics to show how much space can be cleared"
1124
  msgstr ""
1125
 
1126
+ #: src/templates/settings/may-also-like.php:79, src/templates/settings/may-also-like.php:80
1127
  msgid "Enables / disables trackbacks and comments"
1128
  msgstr ""
1129
 
1130
+ #: src/templates/settings/may-also-like.php:81
1131
  msgid "Enable or disable trackbacks and comments for all of your published posts"
1132
  msgstr ""
1133
 
1134
+ #: src/templates/settings/may-also-like.php:92, src/templates/settings/may-also-like.php:93
1135
  msgid "Retains a set number of weeks' data during clean-ups"
1136
  msgstr ""
1137
 
1138
+ #: src/templates/settings/may-also-like.php:94
1139
  msgid "Choose how much historical data to retain, for extra safety."
1140
  msgstr ""
1141
 
1142
+ #: src/templates/settings/may-also-like.php:105, src/templates/settings/may-also-like.php:106
1143
  msgid "Clean auto-draft posts"
1144
  msgstr ""
1145
 
1146
+ #: src/templates/settings/may-also-like.php:107
1147
  msgid "Automatically cleans up auto draft posts older than your chosen age"
1148
  msgstr ""
1149
 
1150
+ #: src/templates/settings/may-also-like.php:118, src/templates/settings/may-also-like.php:119, src/templates/settings/may-also-like.php:157
1151
  msgid "Multisite support"
1152
  msgstr ""
1153
 
1154
+ #: src/templates/settings/may-also-like.php:120
1155
  msgid "Optimize any site (or combination of sites) on your WordPress Multisite or network"
1156
  msgstr ""
1157
 
1158
+ #: src/templates/settings/may-also-like.php:123, src/templates/settings/may-also-like.php:136, src/templates/settings/may-also-like.php:149, src/templates/settings/may-also-like.php:162, src/templates/settings/may-also-like.php:175, src/templates/settings/may-also-like.php:188, src/templates/settings/may-also-like.php:201, src/templates/settings/may-also-like.php:214
1159
  msgid "No"
1160
  msgstr ""
1161
 
1162
+ #: src/templates/settings/may-also-like.php:131, src/templates/settings/may-also-like.php:132
1163
  msgid "Optimize individual tables"
1164
  msgstr ""
1165
 
1166
+ #: src/templates/settings/may-also-like.php:133
1167
  msgid "Perform optimizations on single tables"
1168
  msgstr ""
1169
 
1170
+ #: src/templates/settings/may-also-like.php:144, src/templates/settings/may-also-like.php:145
1171
  msgid "Remove unwanted images"
1172
  msgstr ""
1173
 
1174
+ #: src/templates/settings/may-also-like.php:146
1175
  msgid "Remove images that have been orphaned or are no longer in use"
1176
  msgstr ""
1177
 
1178
+ #: src/templates/settings/may-also-like.php:158
1179
  msgid "Sophisticated scheduling"
1180
  msgstr ""
1181
 
1182
+ #: src/templates/settings/may-also-like.php:159
1183
  msgid "A more advanced scheduling system to make regular routine optimizations whenever you prefer"
1184
  msgstr ""
1185
 
1186
+ #: src/templates/settings/may-also-like.php:170, src/templates/settings/may-also-like.php:171
1187
  msgid "Control with WP-CLI"
1188
  msgstr ""
1189
 
1190
+ #: src/templates/settings/may-also-like.php:172
1191
  msgid "Save time managing multiple sites from the WP command line"
1192
  msgstr ""
1193
 
1194
+ #: src/templates/settings/may-also-like.php:183, src/templates/settings/may-also-like.php:184
1195
  msgid "Enhanced logging and reporting"
1196
  msgstr ""
1197
 
1198
+ #: src/templates/settings/may-also-like.php:185
1199
  msgid "Send log messages to three additional locations: Slack, Syslog and Simple History"
1200
  msgstr ""
1201
 
1202
+ #: src/templates/settings/may-also-like.php:196, src/templates/settings/may-also-like.php:197
1203
  msgid "More choice and flexibility"
1204
  msgstr ""
1205
 
1206
+ #: src/templates/settings/may-also-like.php:198
1207
  msgid "Choose from a number of advanced options, like the ability to optimize individual DB tables"
1208
  msgstr ""
1209
 
1210
+ #: src/templates/settings/may-also-like.php:209, src/templates/settings/may-also-like.php:210
1211
  msgid "Premium support"
1212
  msgstr ""
1213
 
1214
+ #: src/templates/settings/may-also-like.php:211
1215
  msgid "Get your specific queries addressed directly by our experts"
1216
  msgstr ""
1217
 
1218
+ #: src/templates/settings/may-also-like.php:234
1219
  msgid "Our other plugins"
1220
  msgstr ""
1221
 
1222
+ #: src/templates/settings/may-also-like.php:250
1223
  msgid "UpdraftPlus"
1224
  msgstr ""
1225
 
1226
+ #: src/templates/settings/may-also-like.php:251
1227
  msgid "UpdraftPlus – the ultimate protection for your site, hard work and business"
1228
  msgstr ""
1229
 
1230
+ #: src/templates/settings/may-also-like.php:254
1231
  msgid "If you’ve got a WordPress website, you need a backup."
1232
  msgstr ""
1233
 
1234
+ #: src/templates/settings/may-also-like.php:257
1235
  msgid "Hacking, server crashes, dodgy updates or simple user error can ruin everything."
1236
  msgstr ""
1237
 
1238
+ #: src/templates/settings/may-also-like.php:260
1239
  msgid "With UpdraftPlus, you can rest assured that if the worst does happen, it's no big deal. rather than losing everything, you can simply restore the backup and be up and running again in no time at all."
1240
  msgstr ""
1241
 
1242
+ #: src/templates/settings/may-also-like.php:263
1243
  msgid "You can also migrate your website with few clicks without hassle."
1244
  msgstr ""
1245
 
1246
+ #: src/templates/settings/may-also-like.php:266
1247
  msgid "With a long-standing reputation for excellence and outstanding reviews, it’s no wonder that UpdraftPlus is the world’s most popular WordPress backup plugin."
1248
  msgstr ""
1249
 
1250
+ #: src/templates/settings/may-also-like.php:268, src/templates/settings/may-also-like.php:285, src/templates/settings/may-also-like.php:304, src/templates/settings/may-also-like.php:319
1251
  msgid "Try for free"
1252
  msgstr ""
1253
 
1254
+ #: src/templates/settings/may-also-like.php:272
1255
  msgid ""
1256
  "UpdraftCentral Dashboard\n"
1257
  ""
1258
  msgstr ""
1259
 
1260
+ #: src/templates/settings/may-also-like.php:274
1261
  msgid "UpdraftCentral – save hours managing multiple WP sites from one place"
1262
  msgstr ""
1263
 
1264
+ #: src/templates/settings/may-also-like.php:277
1265
  msgid "If you manage a few WordPress sites, you need UpdraftCentral."
1266
  msgstr ""
1267
 
1268
+ #: src/templates/settings/may-also-like.php:280
1269
  msgid "UpdraftCentral is a powerful tool that allows you to efficiently manage, update, backup and even restore multiple websites from just one location. You can also manage users and comments on all the sites at once, and through its central login feature, you can access each WP-dashboard with a single click."
1270
  msgstr ""
1271
 
1272
+ #: src/templates/settings/may-also-like.php:283
1273
  msgid "With a wide range of useful features, including automated backup schedules and sophisticated one click updates, UpdraftCentral is sure to boost to your productivity and save you time."
1274
  msgstr ""
1275
 
1276
+ #: src/templates/settings/may-also-like.php:289
1277
  msgid "Meta Slider"
1278
  msgstr ""
1279
 
1280
+ #: src/templates/settings/may-also-like.php:290
1281
  msgid "MetaSlider - hold visitors’ attention to increase conversion and profits."
1282
  msgstr ""
1283
 
1284
+ #: src/templates/settings/may-also-like.php:293
1285
  msgid "With Metaslider, WordPress’ most popular slider plugin, you can add unique, SEO-optimizing slideshow to your blog or website in a matter of seconds!"
1286
  msgstr ""
1287
 
1288
+ #: src/templates/settings/may-also-like.php:296
1289
  msgid "Sliders instantly make a web-page more eye-catching and engaging."
1290
  msgstr ""
1291
 
1292
+ #: src/templates/settings/may-also-like.php:299
1293
  msgid "With Metaslider, creating them couldn’t be easier: simply select images from your WordPress Media Library, drag and drop them into place. You can then set the slide captions, links and SEO fields all from one page."
1294
  msgstr ""
1295
 
1296
+ #: src/templates/settings/may-also-like.php:302
1297
  msgid "Easily improve the look of your site, your conversion rate and bottom line."
1298
  msgstr ""
1299
 
1300
+ #: src/templates/settings/may-also-like.php:307
1301
  msgid "Keyy Two Factor Authentication"
1302
  msgstr ""
1303
 
1304
+ #: src/templates/settings/may-also-like.php:308
1305
  msgid "Keyy – instant &amp; secure logins with a wave of your phone"
1306
  msgstr ""
1307
 
1308
+ #: src/templates/settings/may-also-like.php:311
1309
  msgid "Keyy is a unique 2-factor authentication plugin that allows you to log in to your website with just a wave of your smartphone. It represents the ultimate UX, doing away with the need for usernames, passwords and other 2FA tokens."
1310
  msgstr ""
1311
 
1312
+ #: src/templates/settings/may-also-like.php:314
1313
  msgid "Using innovative RSA public-key cryptography, Keyy is highly secure and prevents password-based hacking risks such as brute-forcing, key-logging, shoulder-surfing and connection sniffing."
1314
  msgstr ""
1315
 
1316
+ #: src/templates/settings/may-also-like.php:317
1317
  msgid "Logging in with Keyy is simple. Once users have installed the app onto their smartphone and secured it using a fingerprint or 4-number pin, they just open the app, point it at the moving on-screen barcode and voila!"
1318
  msgstr ""
1319
 
1320
+ #: src/templates/settings/settings-auto-cleanup.php:3
1321
+ msgid "Scheduled clean-up settings"
1322
  msgstr ""
1323
 
1324
+ #: src/templates/settings/settings-auto-cleanup.php:6
1325
+ msgid "Take control of clean-ups: Upgrade to Premium for a more powerful and flexible scheduler"
1326
  msgstr ""
1327
 
1328
+ #: src/templates/settings/settings-auto-cleanup.php:14
1329
+ msgid "Enable scheduled clean-up and optimization (Beta feature)"
1330
  msgstr ""
1331
 
1332
+ #: src/templates/settings/settings-auto-cleanup.php:22
1333
+ msgid "Select schedule type (default is Weekly)"
1334
  msgstr ""
1335
 
1336
+ #: src/templates/settings/settings-auto-cleanup.php:27
1337
+ msgid "Daily"
1338
  msgstr ""
1339
 
1340
+ #: src/templates/settings/settings-auto-cleanup.php:28
1341
+ msgid "Weekly"
1342
  msgstr ""
1343
 
1344
+ #: src/templates/settings/settings-auto-cleanup.php:29
1345
+ msgid "Fortnightly"
1346
  msgstr ""
1347
 
1348
+ #: src/templates/settings/settings-auto-cleanup.php:30
1349
+ msgid "Monthly (approx. - every 30 days)"
1350
  msgstr ""
1351
 
1352
+ #: src/templates/settings/settings-general.php:3
1353
+ msgid "General settings"
1354
  msgstr ""
1355
 
1356
+ #: src/templates/settings/settings-general.php:6
1357
+ msgid "Whether manually or on a schedule, these settings apply whenever a relevant optimization is run."
1358
  msgstr ""
1359
 
1360
+ #: src/templates/settings/settings-general.php:15
1361
+ msgid "Keep last %s weeks data"
1362
  msgstr ""
1363
 
1364
+ #: src/templates/settings/settings-general.php:21
1365
+ msgid "This option will, where relevant, retain data from the chosen period, and remove any garbage data before that period."
1366
  msgstr ""
1367
 
1368
+ #: src/templates/settings/settings-general.php:21
1369
+ msgid "If the option is not active, then all garbage data will be removed."
1370
  msgstr ""
1371
 
1372
+ #: src/templates/settings/settings-general.php:21
1373
+ msgid "This will also affect Auto Clean-up process"
1374
  msgstr ""
1375
 
1376
+ #: src/templates/settings/settings-general.php:26
1377
+ msgid "Enable admin bar link"
1378
  msgstr ""
1379
 
1380
+ #: src/templates/settings/settings-general.php:29
1381
+ msgid "This option will put an WP-Optimize link on the top admin bar (default is off). Requires a second page refresh after saving the settings."
1382
  msgstr ""
1383
 
1384
+ #: src/templates/settings/settings-logging.php:3
1385
+ msgid "Logging settings"
1386
  msgstr ""
1387
 
1388
+ #: src/templates/settings/settings-logging.php:7
1389
+ msgid "Add logging destination"
1390
  msgstr ""
1391
 
1392
+ #: src/templates/settings/settings-logging.php:11
1393
+ msgid "Remember to save your settings so that your changes take effect."
1394
  msgstr ""
1395
 
1396
+ #: src/templates/settings/settings-logging.php:22
1397
+ msgid "Destination"
1398
  msgstr ""
1399
 
1400
+ #: src/templates/settings/settings-logging.php:23
1401
+ msgid "Options"
1402
  msgstr ""
1403
 
1404
+ #: src/templates/settings/settings-logging.php:24, src/templates/settings/status-box-contents.php:11
1405
+ msgid "Status"
1406
  msgstr ""
1407
 
1408
+ #: src/templates/settings/settings-logging.php:39, src/templates/settings/settings-logging.php:79
1409
+ msgid "Active"
1410
  msgstr ""
1411
 
1412
+ #: src/templates/settings/settings-logging.php:39
1413
+ msgid "Inactive"
1414
  msgstr ""
1415
 
1416
+ #: src/templates/settings/settings-trackback-and-comments.php:2
1417
+ msgid "Trackback/comments actions"
1418
  msgstr ""
1419
 
1420
+ #: src/templates/settings/settings-trackback-and-comments.php:5
1421
+ msgid "Trackbacks"
1422
  msgstr ""
1423
 
1424
+ #: src/templates/settings/settings-trackback-and-comments.php:10
1425
+ msgid "Use these buttons to enable or disable any future trackbacks on all your previously published posts."
1426
  msgstr ""
1427
 
1428
+ #: src/templates/settings/settings-trackback-and-comments.php:23
1429
+ msgid "Comments"
1430
  msgstr ""
1431
 
1432
+ #: src/templates/settings/settings-trackback-and-comments.php:27
1433
+ msgid "Use these buttons to enable or disable any future comments on all your previously published posts."
1434
+ msgstr ""
1435
+
1436
+ #: src/templates/settings/settings.php:20
1437
+ msgid "Save settings"
1438
  msgstr ""
1439
 
1440
+ #: src/templates/settings/status-box-contents.php:17
1441
  msgid "running on:"
1442
  msgstr ""
1443
 
1444
+ #: src/templates/settings/status-box-contents.php:17
1445
  msgid "MySQL"
1446
  msgstr ""
1447
 
1448
+ #: src/templates/settings/status-box-contents.php:26
1449
  msgid "Last scheduled optimization was at"
1450
  msgstr ""
1451
 
1452
+ #: src/templates/settings/status-box-contents.php:31
1453
  msgid "There was no scheduled optimization"
1454
  msgstr ""
1455
 
1456
+ #: src/templates/settings/status-box-contents.php:57
1457
+ msgid "Scheduled cleaning"
1458
  msgstr ""
1459
 
1460
+ #: src/templates/settings/status-box-contents.php:70
1461
  msgid "Next schedule:"
1462
  msgstr ""
1463
 
1464
+ #: src/templates/settings/status-box-contents.php:75
1465
  msgid "Refresh"
1466
  msgstr ""
1467
 
1468
+ #: src/templates/settings/status-box-contents.php:79
1469
  msgid "Scheduled cleaning disabled"
1470
  msgstr ""
1471
 
1472
+ #: src/templates/settings/status-box-contents.php:86
1473
  msgid "Keeping last %s weeks data"
1474
  msgstr ""
1475
 
1476
+ #: src/templates/settings/status-box-contents.php:89
1477
  msgid "Not keeping recent data"
1478
  msgstr ""
1479
 
1480
+ #: src/templates/settings/status-box-contents.php:95
1481
  msgid "Current database size:"
1482
  msgstr ""
1483
 
1484
+ #: src/templates/settings/status-box-contents.php:102
1485
  msgid "You have saved:"
1486
  msgstr ""
1487
 
1488
+ #: src/templates/settings/status-box-contents.php:106
1489
  msgid "You can save around:"
1490
  msgstr ""
1491
 
1492
+ #: src/templates/settings/status-box-contents.php:119
1493
  msgid "Total clean up overall:"
1494
  msgstr ""
1495
 
1496
+ #: src/templates/settings/status-box-contents.php:133
1497
  msgid "Your database has %s corrupted table."
1498
  msgid_plural "Your database has %s corrupted tables."
1499
  msgstr[0] ""
1500
  msgstr[1] ""
1501
 
1502
+ #: src/templates/settings/status-box-contents.php:134
1503
  msgid "Repair corrupted tables here."
1504
  msgstr ""
1505
 
1506
+ #: src/templates/settings/support-and-faqs.php:3
1507
  msgid "Support and feedback"
1508
  msgstr ""
1509
 
1510
+ #: src/templates/settings/support-and-faqs.php:6
1511
+ msgid "Read our FAQ here"
 
 
 
 
 
 
 
 
1512
  msgstr ""
1513
 
1514
+ #: src/templates/settings/support-and-faqs.php:7
 
 
 
 
1515
  msgid "Support is available here."
1516
  msgstr ""
1517
 
1518
+ #: src/templates/settings/support-and-faqs.php:8
1519
+ msgid "If you like WP-Optimize,"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1520
  msgstr ""
1521
 
1522
+ #: src/templates/settings/support-and-faqs.php:8
1523
+ msgid "please give us a positive review, here."
1524
  msgstr ""
1525
 
1526
+ #: src/templates/settings/support-and-faqs.php:8
1527
+ msgid "Or, if you did not like it,"
1528
  msgstr ""
1529
 
1530
+ #: src/templates/settings/support-and-faqs.php:8
1531
+ msgid "please tell us why at this link."
1532
  msgstr ""
1533
 
1534
  #: src/templates/take-a-backup.php:17
1535
  msgid "Backup before running optimizations"
1536
  msgstr ""
1537
 
1538
+ #: src/templates/take-a-backup.php:62
1539
  msgid "Take a backup with UpdraftPlus before doing this"
1540
  msgstr ""
1541
 
1542
+ #: src/templates/take-a-backup.php:75
1543
  msgid "Follow this link to install UpdraftPlus, to take a backup before optimization"
1544
  msgstr ""
1545
 
1546
+ #: src/templates/take-a-backup.php:91
1547
  msgid "UpdraftPlus needs to be updated to 1.12.33 or higher in order to backup the database before optimization."
1548
  msgstr ""
1549
 
1550
+ #: src/templates/take-a-backup.php:91
1551
  msgid "Please update UpdraftPlus to the latest version."
1552
  msgstr ""
1553
 
1554
+ #: src/templates/take-a-backup.php:94
1555
  msgid "UpdraftPlus is installed but currently not active. Follow this link to activate UpdraftPlus, to take a backup before optimization."
1556
  msgstr ""
1557
 
1558
+ #: src/wp-optimize.php:352
1559
  msgid "WP-Optimize (Free) has been de-activated, because WP-Optimize Premium is active."
1560
  msgstr ""
1561
 
1562
+ #: src/wp-optimize.php:362
1563
  msgid "New feature: WP-Optimize Premium can now optimize all sites within a multisite install, not just the main one."
1564
  msgstr ""
1565
 
1566
+ #: src/wp-optimize.php:481, src/wp-optimize.php:854, src/wp-optimize.php:1031, src/wp-optimize.php:1032
1567
+ msgid "Settings"
1568
  msgstr ""
1569
 
1570
+ #: src/wp-optimize.php:484
1571
+ msgid "Tables"
1572
+ msgstr ""
1573
+
1574
+ #: src/wp-optimize.php:486
1575
+ msgid "Gzip compression"
1576
+ msgstr ""
1577
+
1578
+ #: src/wp-optimize.php:487
1579
+ msgid "Static file caching"
1580
  msgstr ""
1581
 
1582
+ #: src/wp-optimize.php:489
1583
+ msgid "Support / FAQs"
1584
+ msgstr ""
1585
+
1586
+ #: src/wp-optimize.php:490
1587
  msgid "Premium / Plugin family"
1588
  msgstr ""
1589
 
1590
+ #: src/wp-optimize.php:770
1591
  msgid "Automatic backup before optimizations"
1592
  msgstr ""
1593
 
1594
+ #: src/wp-optimize.php:771
1595
  msgid "An unexpected response was received."
1596
  msgstr ""
1597
 
1598
+ #: src/wp-optimize.php:772
1599
  msgid "Optimization complete"
1600
  msgstr ""
1601
 
1602
+ #: src/wp-optimize.php:773
1603
  msgid "Run optimizations"
1604
  msgstr ""
1605
 
1606
+ #: src/wp-optimize.php:774
1607
  msgid "Cancel"
1608
  msgstr ""
1609
 
1610
+ #: src/wp-optimize.php:777
1611
  msgid "Please, select settings file."
1612
  msgstr ""
1613
 
1614
+ #: src/wp-optimize.php:778
1615
  msgid "Are you sure you want to remove this logging destination?"
1616
  msgstr ""
1617
 
1618
+ #: src/wp-optimize.php:779
1619
  msgid "Before saving, you need to complete the currently incomplete settings (or remove them)."
1620
  msgstr ""
1621
 
1622
+ #: src/wp-optimize.php:780
1623
+ msgid "%s was not repaired. For more details, please check the logs (configured in your logging destinations settings)."
1624
+ msgstr ""
1625
+
1626
+ #: src/wp-optimize.php:781
1627
+ msgid "Are you sure you want to remove this table?"
1628
+ msgstr ""
1629
+
1630
+ #: src/wp-optimize.php:782
1631
+ msgid "%s was not deleted. For more details, please check your logs configured in logging destinations settings."
1632
  msgstr ""
1633
 
1634
+ #: src/wp-optimize.php:783
1635
+ msgid "Please use positive integers."
1636
  msgstr ""
1637
 
1638
+ #: src/wp-optimize.php:784
1639
+ msgid "Please use valid values."
1640
+ msgstr ""
1641
+
1642
+ #: src/wp-optimize.php:857
1643
  msgid "Optimizer"
1644
  msgstr ""
1645
 
1646
+ #: src/wp-optimize.php:873
1647
  msgid "Repair"
1648
  msgstr ""
1649
 
1650
+ #: src/wp-optimize.php:884
1651
+ msgid "Remove"
1652
+ msgstr ""
1653
+
1654
+ #: src/wp-optimize.php:991
1655
  msgid "Warning"
1656
  msgstr ""
1657
 
1658
+ #: src/wp-optimize.php:991
1659
  msgid "WordPress has a number (%d) of scheduled tasks which are overdue. Unless this is a development site, this probably means that the scheduler in your WordPress install is not working."
1660
  msgstr ""
1661
 
1662
+ #: src/wp-optimize.php:991
1663
  msgid "Read this page for a guide to possible causes and how to fix it."
1664
  msgstr ""
1665
 
1666
+ #: src/wp-optimize.php:1045, src/wp-optimize.php:1046
1667
+ msgid "Database"
1668
+ msgstr ""
1669
+
1670
+ #: src/wp-optimize.php:1059
1671
+ msgid "Support & FAQs"
1672
+ msgstr ""
1673
+
1674
+ #: src/wp-optimize.php:1060
1675
+ msgid "Help"
1676
+ msgstr ""
1677
+
1678
+ #: src/wp-optimize.php:1081, src/wp-optimize.php:1082
1679
+ msgid "Cache"
1680
+ msgstr ""
1681
+
1682
+ #: src/wp-optimize.php:1144
1683
  msgid "Error:"
1684
  msgstr ""
1685
 
1686
+ #: src/wp-optimize.php:1144
1687
  msgid "template not found"
1688
  msgstr ""
1689
 
1690
+ #: src/wp-optimize.php:1196
1691
  msgid "Automatic Operation Completed"
1692
  msgstr ""
1693
 
1694
+ #: src/wp-optimize.php:1198
1695
  msgid "Scheduled optimization was executed at"
1696
  msgstr ""
1697
 
1698
+ #: src/wp-optimize.php:1199
1699
  msgid "You can safely delete this email."
1700
  msgstr ""
1701
 
1702
+ #: src/wp-optimize.php:1201
1703
  msgid "Regards,"
1704
  msgstr ""
1705
 
1706
+ #: src/wp-optimize.php:1202
1707
  msgid "WP-Optimize Plugin"
1708
  msgstr ""
1709
 
1710
+ #: src/wp-optimize.php:1224
1711
  msgid "GB"
1712
  msgstr ""
1713
 
1714
+ #: src/wp-optimize.php:1226
1715
  msgid "MB"
1716
  msgstr ""
1717
 
1718
+ #: src/wp-optimize.php:1228
1719
  msgid "KB"
1720
  msgstr ""
1721
 
1722
+ #: src/wp-optimize.php:1230
1723
  msgid "bytes"
1724
  msgstr ""
1725
 
1726
+ #: src/wp-optimize.php:1549
1727
  msgid "You have no permissions to run optimizations."
1728
  msgstr ""
1729
 
1730
+ #: src/wp-optimize.php:1556
1731
  msgid "You have no permissions to manage WP-Optimize settings."
1732
  msgstr ""
1733
 
1734
+ #: src/wp-optimize.php:1706
1735
  msgid "Only Network Administrator can activate WP-Optimize plugin."
1736
  msgstr ""
1737
 
1738
+ #: src/wp-optimize.php:1707
1739
  msgid "go back"
1740
  msgstr ""
optimizations/orphanedtables.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if (!defined('WPO_VERSION')) die('No direct access allowed');
4
+
5
+ class WP_Optimization_orphanedtables extends WP_Optimization {
6
+
7
+ public $available_for_auto = false;
8
+
9
+ public $setting_default = true;
10
+
11
+ public $changes_table_data = true;
12
+
13
+ public $run_multisite = false;
14
+
15
+ /**
16
+ * Display or hide optimization in optimizations list.
17
+ *
18
+ * @return bool
19
+ */
20
+ public function display_in_optimizations_list() {
21
+ return false;
22
+ }
23
+
24
+ /**
25
+ * Run optimization.
26
+ */
27
+ public function optimize() {
28
+ // check if single table name posted or optimize all tables.
29
+ if (isset($this->data['optimization_table']) && '' != $this->data['optimization_table']) {
30
+ $table = $this->optimizer->get_table($this->data['optimization_table']);
31
+
32
+ $result = $this->delete_table($table);
33
+
34
+ $this->register_meta('success', $result);
35
+ } else {
36
+ // delete all orphaned tables if table name was not selected.
37
+ $tables = $this->optimizer->get_tables();
38
+ $deleted = 0;
39
+
40
+ foreach ($tables as $table) {
41
+ if ($table->is_using) continue;
42
+
43
+ if ($this->delete_table($table)) {
44
+ $deleted++;
45
+ }
46
+ }
47
+
48
+ $this->register_output(sprintf(_n('%s orphaned table deleted', '%s orphaned tables deleted', $deleted), $deleted));
49
+
50
+ if ($deleted > 0) {
51
+ $this->register_output(sprintf(_n('Deleting %s orphaned table was unsuccessful', 'Repairing %s orphaned tables were unsuccessful', $deleted), $deleted));
52
+ }
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Drop table from database.
58
+ *
59
+ * @param object $table_obj object contains information about database table.
60
+ *
61
+ * @return bool
62
+ */
63
+ private function delete_table($table_obj) {
64
+ global $wpdb;
65
+
66
+ // don't delete table if it in use.
67
+ if ($table_obj->is_using) return true;
68
+
69
+ $sql_query = $wpdb->prepare('DROP TABLE %s', $table_obj->Name);
70
+
71
+ $this->logger->info($sql_query);
72
+
73
+ $result = $wpdb->query($sql_query);
74
+
75
+ // check if drop query finished successfully.
76
+ if ('' != $wpdb->last_error) {
77
+ $this->logger->info($wpdb->last_error);
78
+ }
79
+
80
+ return $result;
81
+ }
82
+
83
+ /**
84
+ * Get count of unused database tables, i.e. not using by any of installed plugin.
85
+ *
86
+ * @return int
87
+ */
88
+ public function get_unused_tables_count() {
89
+ $tablesinfo = $this->optimizer->get_tables();
90
+
91
+ $unused_tables = 0;
92
+
93
+ if (!empty($tablesinfo)) {
94
+ foreach ($tablesinfo as $tableinfo) {
95
+ if (false == $tableinfo->is_using) {
96
+ $unused_tables++;
97
+ }
98
+ }
99
+ }
100
+
101
+ return $unused_tables;
102
+ }
103
+
104
+ /**
105
+ * Register info about optimization.
106
+ */
107
+ public function get_info() {
108
+
109
+ $corrupted_tables = $this->get_unused_tables_count();
110
+
111
+ if (0 == $corrupted_tables) {
112
+ $this->register_output(__('No corrupted tables found', 'wp-optimize'));
113
+ } else {
114
+ $this->register_output(sprintf(_n('%s corrupted table found', '%s corrupted tables found', $corrupted_tables), $corrupted_tables));
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Returns settings label.
120
+ *
121
+ * @return string
122
+ */
123
+ public function settings_label() {
124
+ return __('Delete orphaned database tables', 'wp-optimize');
125
+ }
126
+ }
optimizations/trash.php CHANGED
@@ -40,7 +40,7 @@ class WP_Optimization_trash extends WP_Optimization {
40
  $sql = $this->wpdb->prepare(
41
  "SELECT `ID`, `post_title`, `post_date`".
42
  " FROM `" . $this->wpdb->posts . "`".
43
- " WHERE post_type = 'trash'".
44
  $retention_subquery.
45
  " ORDER BY `ID` LIMIT %d, %d;",
46
  array(
@@ -62,7 +62,7 @@ class WP_Optimization_trash extends WP_Optimization {
62
  }
63
 
64
  // get total count auto-draft for optimization.
65
- $sql = "SELECT COUNT(*) FROM `" . $this->wpdb->posts . "` WHERE post_type = 'trash'";
66
 
67
  if ('true' == $this->retention_enabled) {
68
  $sql .= ' and post_modified < NOW() - INTERVAL ' . $this->retention_period . ' WEEK';
40
  $sql = $this->wpdb->prepare(
41
  "SELECT `ID`, `post_title`, `post_date`".
42
  " FROM `" . $this->wpdb->posts . "`".
43
+ " WHERE post_status = 'trash'".
44
  $retention_subquery.
45
  " ORDER BY `ID` LIMIT %d, %d;",
46
  array(
62
  }
63
 
64
  // get total count auto-draft for optimization.
65
+ $sql = "SELECT COUNT(*) FROM `" . $this->wpdb->posts . "` WHERE post_status = 'trash'";
66
 
67
  if ('true' == $this->retention_enabled) {
68
  $sql .= ' and post_modified < NOW() - INTERVAL ' . $this->retention_period . ' WEEK';
plugin.json ADDED
@@ -0,0 +1 @@
 
1
+ {"yoast_seo_links":"wordpress-seo","yoast_seo_meta":"wordpress-seo","woocommerce_order_itemmeta":"woocommerce","woocommerce_tax_rates":"woocommerce","woocommerce_shipping_zones":"woocommerce","woocommerce_shipping_zone_methods":"woocommerce","woocommerce_shipping_zone_locations":"woocommerce","woocommerce_sessions":"woocommerce","woocommerce_payment_tokens":"woocommerce","woocommerce_payment_tokenmeta":"woocommerce","woocommerce_order_items":"woocommerce","woocommerce_log":"woocommerce","woocommerce_downloadable_product_permissions":"woocommerce","woocommerce_attribute_taxonomies":"woocommerce","woocommerce_api_keys":"woocommerce","woocommerce_tax_rate_locations":"woocommerce","wc_download_log":"woocommerce","wc_webhooks":"woocommerce","wfhits":"wordfence","wffilechanges":"wordfence","wfreversecache":"wordfence","wfscanners":"wordfence","wfsnipcache":"wordfence","wfstatus":"wordfence","wfthrottlelog":"wordfence","wfvulnscanners":"wordfence","wfconfig":"wordfence","wfcrawlers":"wordfence","wfhoover":"wordfence","wfblocksadv":"wordfence","wfblocks7":"wordfence","wfblocks":"wordfence","wfblockediplog":"wordfence","wfblockedcommentlog":"wordfence","wfbadleechers":"wordfence","wfpendingissues":"wordfence","wfnet404s":"wordfence","wfissues":"wordfence","wfknownfilelist":"wordfence","wfnotifications":"wordfence","wfleechers":"wordfence","wflivetraffichuman":"wordfence","wffilemods":"wordfence","wflockedout":"wordfence","wflogins":"wordfence","wflocs":"wordfence","nf3_field_meta":"ninja-forms","nf3_upgrades":"ninja-forms","ngg_pictures":"nextcellent-gallery-nextgen-legacy","ngg_gallery":"nextcellent-gallery-nextgen-legacy","ngg_album":"nextcellent-gallery-nextgen-legacy","redirection_logs":"redirection","nf3_relationships":"ninja-forms","nf3_chunks":"ninja-forms","redirection_items":"redirection","redirection_groups":"redirection","nf3_objects":"ninja-forms","nf3_object_meta":"ninja-forms","nf3_forms":"ninja-forms","nf3_form_meta":"ninja-forms","nf3_action_meta":"ninja-forms","nf3_fields":"ninja-forms","nf3_actions":"ninja-forms","redirection_404":"redirection","smush_dir_images":"wp-smushit","duplicator_packages":"duplicator","itsec_temp":"better-wp-security","itsec_lockouts":"better-wp-security","itsec_distributed_storage":"better-wp-security","itsec_log":"better-wp-security","itsec_logs":"better-wp-security","loginizer_logs":"loginizer","aiowps_global_meta":"all-in-one-wp-security-and-firewall","aiowps_failed_logins":"all-in-one-wp-security-and-firewall","aiowps_login_activity":"all-in-one-wp-security-and-firewall","aiowps_login_lockdown":"all-in-one-wp-security-and-firewall","ewwwio_images":"ewww-image-optimizer-cloud","aiowps_permanent_block":"all-in-one-wp-security-and-firewall","aiowps_events":"all-in-one-wp-security-and-firewall","blc_synch":"broken-link-checker","blc_links":"broken-link-checker","blc_instances":"broken-link-checker","blc_filters":"broken-link-checker","wpmm_subscribers":"wp-maintenance-mode","wpgmza_categories":"wp-google-maps","statistics_useronline":"wp-statistics","wpgmza":"wp-google-maps","wpgmza_polygon":"wp-google-maps","statistics_visitor":"wp-statistics","statistics_search":"wp-statistics","wpgmza_rectangles":"wp-google-maps","statistics_visit":"wp-statistics","statistics_exclusions":"wp-statistics","wpgmza_polylines":"wp-google-maps","wpgmza_maps":"wp-google-maps","wpgmza_circles":"wp-google-maps","wpgmza_category_maps":"wp-google-maps","statistics_pages":"wp-statistics","statistics_historical":"wp-statistics","wysija_email":"wysija-newsletters","newsletter_sent":"digital-media-combined","newsletter_emails":"digital-media-combined","newsletter_user_logs":"newsletter","popularpostsdata":"mh-board","nextend2_smartslider3_slides":"smart-slider-3","popularpostssummary":"wordpress-popular-posts","bwg_theme":"photo-gallery","nextend2_image_storage":"smart-slider-3","nextend2_section_storage":"smart-slider-3","nextend2_smartslider3_generators":"smart-slider-3","nextend2_smartslider3_sliders":"smart-slider-3","nextend2_smartslider3_sliders_xref":"smart-slider-3","wysija_email_user_stat":"wysija-newsletters","wysija_custom_field":"wysija-newsletters","wysija_campaign_list":"wysija-newsletters","wysija_campaign":"wysija-newsletters","litespeed_img_optm":"litespeed-cache","litespeed_optimizer":"litespeed-cache","newsletter":"digital-media-combined","newsletter_stats":"digital-media-combined","hctpc_whitelist":"captcha","wysija_user_history":"wysija-newsletters","wysija_user":"wysija-newsletters","wysija_user_field":"wysija-newsletters","cptch_blacklist_ip":"captcha","cptch_images":"captcha","cptch_packages":"captcha","cptch_track_countries":"captcha","bwg_image":"photo-gallery","wysija_user_list":"wysija-newsletters","cptch_track_visitor":"captcha","cptch_whitelist":"captcha","bwg_gallery":"photo-gallery","hctpc_packages":"captcha","bwg_album_gallery":"photo-gallery","bwg_album":"photo-gallery","wysija_url_mail":"wysija-newsletters","wysija_url":"wysija-newsletters","wysija_subscriber_ips":"wysija-newsletters","wysija_queue":"wysija-newsletters","bwg_shortcode":"photo-gallery","hctpc_images":"captcha","wysija_email_user_url":"wysija-newsletters","wysija_form":"wysija-newsletters","bwg_image_comment":"photo-gallery","wysija_list":"wysija-newsletters","bwg_image_rate":"photo-gallery","bwg_image_tag":"photo-gallery","prli_link_metas":"pretty-link","prli_groups":"pretty-link","prli_clicks":"pretty-link","prli_links":"pretty-link","pum_subscribers":"popup-maker","signups":"wp-user-signups","toolset_post_guid_id":"types","bp_activity":"buddypress","bp_xprofile_groups":"buddypress","bp_activity_meta":"buddypress","frm_forms":"formidable","lockdowns":"login-lockdown","yarpp_related_cache":"yet-another-related-posts-plugin","bp_notifications":"buddypress","frm_item_metas":"formidable","login_fails":"login-lockdown","frm_fields":"formidable","bp_notifications_meta":"buddypress","bp_xprofile_meta":"buddypress","bp_xprofile_fields":"buddypress","bp_xprofile_data":"buddypress","frm_items":"formidable","pmxi_templates":"wp-all-import","pmxi_images":"wp-all-import","odb_logs":"rvg-optimize-database","pmxi_imports":"wp-all-import","pmxi_posts":"wp-all-import","imagify_files":"imagify","brizy_logs":"brizy","visual_form_builder_forms":"visual-form-builder","imagify_folders":"imagify","wpgdprc_consents":"wp-gdpr-compliance","wpeditor_settings":"wp-editor","pollsip":"wp-polls","pollsq":"wp-polls","pollsa":"wp-polls","slim_events":"wp-slimstat","es_templatetable":"email-subscribers","relevanssi":"relevanssi","cf_pro_messages":"caldera-forms","cf_forms":"caldera-forms","cf_form_entry_values":"caldera-forms","cf_form_entry_meta":"caldera-forms","cf_form_entries":"caldera-forms","responsive_menu":"responsive-menu","relevanssi_stopwords":"relevanssi","masterslider_sliders":"master-slider","cf_tracking_meta":"caldera-forms","maxbuttons_collections":"maxbuttons","maxbuttons_collections_trans":"maxbuttons","maxbuttonsv3":"maxbuttons","pmxi_files":"wp-all-import","ratings":"wp-postratings","cbnetpo_ping_optimizer":"wordpress-ping-optimizer","hugeit_slider_slide":"slider-image","cf_tracking":"caldera-forms","group_map":"wp-google-map-plugin","nxs_query":"social-networks-auto-poster-facebook-twitter-g","create_map":"wp-google-map-plugin","db7_forms":"contact-form-cfdb7","map_locations":"wp-google-map-plugin","mappress_maps":"mappress-google-maps-for-wordpress","mappress_posts":"mappress-google-maps-for-wordpress","gglcptch_whitelist":"google-captcha","ahm_download_stats":"download-manager","ahm_emails":"download-manager","ai1ec_event_category_meta":"all-in-one-event-calendar","cntctfrm_field":"contact-form-plugin","ai1ec_event_feeds":"all-in-one-event-calendar","ai1ec_event_instances":"all-in-one-event-calendar","ai1ec_events":"all-in-one-event-calendar","download_log":"download-monitor","relevanssi_log":"relevanssi","masterslider_options":"master-slider","cpd_counter":"count-per-day","hugeit_slider_slider":"slider-image","pmxi_history":"wp-all-import","slim_events_archive":"wp-slimstat","es_notification":"email-subscribers","visual_form_builder_fields":"visual-form-builder","es_deliverreport":"email-subscribers","siteguard_history":"siteguard","siteguard_login":"siteguard","em_tickets_bookings":"events-manager","em_tickets":"event-monster","em_meta":"events-manager","em_locations":"events-manager","nxs_log":"social-networks-auto-poster-facebook-twitter-g","em_events":"events-manager","em_bookings":"event-monster","slim_stats":"wp-slimstat","slim_stats_archive":"wp-slimstat","formmaker":"contact-form-maker","formmaker_backup":"contact-form-maker","formmaker_blocked":"contact-form-maker","formmaker_submits":"contact-form-maker","visual_form_builder_entries":"visual-form-builder","404_to_301":"404-to-301","social_users":"nextend-twitter-connect","formmaker_views":"contact-form-maker","wp_rp_tags":"wordpress-23-related-posts-plugin","formmaker_themes":"contact-form-maker","formmaker_sessions":"contact-form-maker","es_sentdetails":"email-subscribers","formmaker_query":"contact-form-maker","formmaker_groups":"contact-form-maker","snippets":"code-snippets","formmaker_display_options":"contact-form-maker","es_emaillist":"email-subscribers","sg_fblike_popup":"popup-builder","sg_html_popup":"popup-builder","sg_popup_settings":"popup-builder","sg_image_popup":"popup-builder","sg_popup":"popup-builder","sg_popup_addons":"popup-builder","sgpb_subscription_error_log":"popup-builder","sg_popup_addons_connection":"popup-builder","cerber_sets":"wp-cerber","cerber_files":"wp-cerber","sg_shortcode_popup":"popup-builder","sgpb_subscribers":"popup-builder","ber_blocks":"wp-cerber","yikes_easy_mc_forms":"yikes-inc-easy-mailchimp-extender","ber_countries":"wp-cerber","ber_files":"wp-cerber","ber_lab":"wp-cerber","ber_lab_ip":"wp-cerber","login_redirects":"peters-login-redirect","ber_lab_net":"wp-cerber","aryo_activity_log":"aryo-activity-log","ber_log":"wp-cerber","wdi_themes":"wd-instagram-feed","wdi_feeds":"wd-instagram-feed","ber_traffic":"wp-cerber","ber_acl":"wp-cerber","icwp_wpsf_traffic":"wp-simple-firewall","post_views":"access-expiration","icwp_wpsf_sessions":"wp-simple-firewall","bpspro_seclog_ignore":"bulletproof-security","bpspro_mscan":"bulletproof-security","bpspro_db_backup":"bulletproof-security","wsluserscontacts":"wordpress-social-login","wslusersprofiles":"wordpress-social-login","icwp_wpsf_audit_trail":"wp-simple-firewall","icwp_wpsf_ip_lists":"wp-simple-firewall","icwp_wpsf_notes":"wp-simple-firewall","icwp_wpsf_reporting":"wp-simple-firewall","bpspro_login_security":"bulletproof-security","icwp_wpsf_statistics":"wp-simple-firewall","gde_secure":"google-document-embedder","gde_profiles":"google-document-embedder","sg_schedule":"backup","sg_config":"backup","sg_action":"backup","simple_history":"simple-history","simple_history_contexts":"simple-history","mailpoet_newsletter_links":"mailpoet","mailpoet_newsletter_option":"mailpoet","mailpoet_newsletter_option_fields":"mailpoet","mailpoet_newsletters":"mailpoet","mailpoet_newsletter_posts":"mailpoet","mailpoet_newsletter_segment":"mailpoet","mailpoet_newsletter_templates":"mailpoet","mailpoet_log":"mailpoet","mailpoet_scheduled_task_subscribers":"mailpoet","mailpoet_mapping_to_external_entities":"mailpoet","gg_tags":"gallery-by-supsystic","mailpoet_forms":"mailpoet","mailpoet_custom_fields":"mailpoet","wsal_metadata":"wp-security-audit-log","mailpoet_scheduled_tasks":"mailpoet","wsal_options":"wp-security-audit-log","statify":"statify","dynamic_widgets":"dynamic-widgets","filemeta":"advanced-code-editor","hustle_modules":"wordpress-popup","hustle_modules_meta":"wordpress-popup","wsal_occurrences":"wp-security-audit-log","cleantalk_sfw":"cleantalk-spam-protect","gg_stats":"gallery-by-supsystic","mailpoet_statistics_unsubscribes":"mailpoet","gg_settings_sets":"gallery-by-supsystic","gg_settings_presets":"gallery-by-supsystic","gg_photos_settings":"gallery-by-supsystic","gg_photos_pos":"gallery-by-supsystic","gg_photos":"gallery-by-supsystic","gg_membership_presets":"gallery-by-supsystic","gg_image_optimize":"gallery-by-supsystic","mailpoet_subscribers":"mailpoet","mailpoet_subscriber_segment":"mailpoet","mailpoet_subscriber_ips":"mailpoet","mailpoet_subscriber_custom_field":"mailpoet","pmpro_memberships_categories":"paid-memberships-pro","gg_attributes":"gallery-by-supsystic","gg_galleries_resources":"gallery-by-supsystic","mailpoet_statistics_newsletters":"mailpoet","gg_galleries_excluded":"gallery-by-supsystic","mailpoet_statistics_forms":"mailpoet","mailpoet_statistics_clicks":"mailpoet","mailpoet_settings":"mailpoet","gg_galleries":"gallery-by-supsystic","mailpoet_sending_queues":"mailpoet","mailpoet_segments":"mailpoet","gg_folders":"gallery-by-supsystic","cleantalk_sfw_logs":"cleantalk-spam-protect","gg_cdn":"gallery-by-supsystic","mailpoet_statistics_opens":"mailpoet","pmpro_membership_orders":"paid-memberships-pro","pmpro_discount_codes_levels":"paid-memberships-pro","pmpro_membership_levelmeta":"paid-memberships-pro","wdsslider":"slider-wd","optin_meta":"wordpress-popup","optins":"wordpress-popup","wdsslide":"slider-wd","pmpro_discount_codes_uses":"paid-memberships-pro","pmpro_memberships_pages":"paid-memberships-pro","pmpro_discount_codes":"paid-memberships-pro","pmpro_membership_levels":"paid-memberships-pro","wdslayer":"slider-wd","pmpro_memberships_users":"paid-memberships-pro","wpb2d_excluded_files":"wordpress-backup-to-dropbox","yuzoviews":"yuzo-related-post","wplc_chat_sessions":"wp-live-chat-support","wplc_offline_messages":"wp-live-chat-support","wplc_chat_msgs":"wp-live-chat-support","edd_customers":"easy-digital-downloads","edd_customermeta":"easy-digital-downloads","_wsd_plugin_scans":"wp-security-scan","wpb2d_processed_dbtables":"wordpress-backup-to-dropbox","wpb2d_options":"wordpress-backup-to-dropbox","_wsd_plugin_alerts":"secure-wordpress","_wsd_plugin_live_traffic":"secure-wordpress","_wsd_plugin_scan":"wp-security-scan","wplc_webhooks":"wp-live-chat-support","strong_views":"strong-testimonials","hugeit_maps_polylines":"google-maps","hugeit_maps_polygons":"google-maps","hugeit_maps_stores":"google-maps","subscribe2":"subscribe2","xcloner_scheduler":"xcloner-backup-and-restore","hugeit_maps_markers":"google-maps","aps_social_icons":"accesspress-social-icons","hugeit_maps_maps":"google-maps","hugeit_maps_directions":"google-maps","hugeit_maps_circles":"google-maps","huge_itportfolio_portfolios":"portfolio-gallery","huge_itportfolio_images":"portfolio-gallery","wpfront_ure_login_redirect":"wpfront-user-role-editor","podsrel":"pods","wpfront_ure_options":"wpfront-user-role-editor","ktaisession":"ktai-style","wpb2d_processed_files":"wordpress-backup-to-dropbox","adrotate_schedule":"adrotate","adrotate":"adrotate","contactformmaker":"contact-form-builder","wp_seo_cache":"404-redirection-manager","wp_seo_redirection_log":"404-redirection-manager","wp_seo_redirection":"404-redirection-manager","adrotate_stats":"adrotate","adrotate_stats_archive":"adrotate","wp_seo_404_links":"404-redirection-manager","woocommerce_ir":"persian-woocommerce","adrotate_tracker":"adrotate","contactformmaker_views":"contact-form-builder","cn_social_icon":"easy-social-icons","adrotate_transactions":"adrotate","contactformmaker_themes":"contact-form-builder","contactformmaker_submits":"contact-form-builder","contactformmaker_blocked":"contact-form-builder","adrotate_groups":"adrotate","redirects":"links-auditor","give_formmeta":"give","pmxe_exports":"wp-all-export","give_sessions":"give","give_customermeta":"give","pmxe_templates":"wp-all-export","pmxe_google_cats":"wp-all-export","give_logs":"give","give_donors":"give","give_logmeta":"give","give_customers":"give","pmxe_posts":"wp-all-export","huge_it_videogallery_galleries":"gallery-video","give_paymentmeta":"give","huge_it_videogallery_videos":"gallery-video","give_donationmeta":"give","give_donormeta":"give","bookingdates":"booking","booking":"asi-taxi-booking","adrotate_linkmeta":"adrotate","mail_bank":"wp-mail-bank","mail_bank_email_logs":"wp-mail-bank","mail_bank_meta":"wp-mail-bank","give_sequential_ordering":"give","statpress":"statpresscn","learnpress_order_items":"learnpress","learnpress_user_items":"learnpress","wc_follow_users":"wpdiscuz","bad_behavior":"bad-behavior","wc_comments_subscription":"wpdiscuz","wc_avatars_cache":"wpdiscuz","wpml_mails":"wp-mail-logging","learnpress_user_itemmeta":"learnpress","gmp_icons":"google-maps-easy","learnpress_sessions":"learnpress","gmp_modules_type":"google-maps-easy","learnpress_question_answermeta":"learnpress","gmp_maps":"google-maps-easy","gmp_marker_groups":"google-maps-easy","gmp_marker_groups_relation":"google-maps-easy","gmp_markers":"google-maps-easy","gmp_membership_presets":"google-maps-easy","wc_users_voted":"wpdiscuz","gmp_modules":"google-maps-easy","gmp_options":"google-maps-easy","learnpress_sections":"learnpress","gmp_options_categories":"google-maps-easy","wc_phrases":"wpdiscuz","gmp_usage_stat":"google-maps-easy","rp4wp_cache":"related-posts-for-wp","learnpress_quiz_questions":"learnpress","learnpress_question_answers":"learnpress","learnpress_review_logs":"learnpress","learnpress_section_items":"learnpress","learnpress_order_itemmeta":"learnpress","wd_fb_info":"wd-facebook-feed","wd_fb_theme":"wd-facebook-feed","_visits_time":"visitors-traffic-real-time-statistics","gwolle_gb_entries":"gwolle-gb","gwolle_gb_log":"gwolle-gb","similar_posts":"similar-posts","wpadm_ga_cache":"analytics-counter","_refering_sites":"visitors-traffic-real-time-statistics","wd_fb_option":"wd-facebook-feed","wd_fb_shortcode":"wd-facebook-feed","_recent_visitors":"visitors-traffic-real-time-statistics","eo_events":"event-organiser","eo_venuemeta":"event-organiser","_visitors":"visitors-traffic-real-time-statistics","_title_traffic":"visitors-traffic-real-time-statistics","_settings":"photo-video-store","_searching_visits":"visitors-traffic-real-time-statistics","_search_engines":"visitors-traffic-real-time-statistics","cfs_sessions":"custom-field-suite","_search_engine_crawlers":"visitors-traffic-real-time-statistics","cfs_values":"custom-field-suite","ufbl_entries":"ultimate-form-builder-lite","uam_accessgroups":"user-access-manager","_hits":"visitors-traffic-real-time-statistics","alm":"ajax-load-more","_daily_visitors_stats":"visitors-traffic-real-time-statistics","wd_fb_data":"wd-facebook-feed","limit_login":"wp-limit-login-attempts","_countries":"mymovingloads-leads-form","ufbl_forms":"ultimate-form-builder-lite","_keywords":"project-supremacy","_browsers":"visitors-traffic-real-time-statistics","_online_users":"visitors-traffic-real-time-statistics","uam_accessgroup_to_object":"user-access-manager","supsystic_tbl_rows":"data-tables-generator-by-supsystic","evf_entries":"everest-forms","evf_entrymeta":"everest-forms","supsystic_tbl_tables":"data-tables-generator-by-supsystic","aepc_logs":"pixel-caffeine","aepc_custom_audiences":"pixel-caffeine","searchmeter":"search-meter","stream":"stream","stream_meta":"stream","searchmeter_recent":"search-meter","evf_sessions":"everest-forms","external_links_logs":"mihdan-no-external-links","supsystic_tbl_diagrams":"data-tables-generator-by-supsystic","supsystic_tbl_columns":"data-tables-generator-by-supsystic","external_links_masks":"mihdan-no-external-links","my_calendar_categories":"my-calendar","xsg_sitemap_meta":"www-xml-sitemap-generator-org","swpm_membership_meta_tbl":"simple-membership","my_calendar":"my-calendar","wppa_albums":"wp-photo-album-plus","wppa_comments":"wp-photo-album-plus","wppa_exif":"wp-photo-album-plus","wppa_index":"wp-photo-album-plus","metaseo_images":"wp-meta-seo","my_calendar_category_relationships":"my-calendar","modula_images":"modula-best-grid-gallery","my_calendar_events":"my-calendar","my_calendar_locations":"my-calendar","wppa_iptc":"wp-photo-album-plus","finaltiles_gallery":"final-tiles-grid-gallery-lite","wppa_photos":"wp-photo-album-plus","wppa_rating":"wp-photo-album-plus","wppa_session":"wp-photo-album-plus","auto_updates":"companion-auto-update","modula":"modula-best-grid-gallery","em_modal_metas":"easy-modal","em_modals":"easy-modal","em_theme_metas":"easy-modal","em_themes":"easy-modal","wpms_links":"wp-meta-seo","finaltiles_gallery_images":"final-tiles-grid-gallery-lite","swpm_members_tbl":"simple-membership","cp_calculated_fields_form_discount_codes":"calculated-fields-form","swpm_membership_tbl":"simple-membership","ip_geo_block_cache":"ip-geo-block","iqblock_logging":"iq-block-country","ip_geo_block_stat":"ip-geo-block","gpi_api_error_logs":"google-pagespeed-insights","gpi_custom_urls":"google-pagespeed-insights","gpi_page_blacklist":"google-pagespeed-insights","gpi_page_reports":"google-pagespeed-insights","gpi_page_stats":"google-pagespeed-insights","gpi_summary_snapshots":"google-pagespeed-insights","ip_geo_block_logs":"ip-geo-block","huge_it_contact_style_fields":"forms-contact","huge_it_contact_general_options":"forms-contact","huge_it_contact_contacts_fields":"forms-contact","pps_popup_show_pages":"popup-by-supsystic","user_login_log":"crazy-bone","cp_calculated_fields_form_posts":"calculated-fields-form","qss":"quickseo-by-squirrly","pps_usage_stat":"popup-by-supsystic","hidemysitesecure":"wp-privacy","cftemail_messages":"contact-form-to-email","cftemail_forms":"contact-form-to-email","swpm_payments_tbl":"simple-membership","pps_subscribers":"popup-by-supsystic","pps_statistics":"popup-by-supsystic","iowd_images":"image-optimizer-wd","pps_countries":"popup-by-supsystic","pps_modules":"popup-by-supsystic","pps_modules_type":"popup-by-supsystic","pps_popup":"popup-by-supsystic","irecommendthis_votes":"i-recommend-this","huge_it_contact_contacts":"forms-contact","huge_it_contact_styles":"forms-contact","leafletmapsmarker_markers":"leaflet-maps-marker","pts_modules":"pricing-table-by-supsystic","pts_modules_type":"pricing-table-by-supsystic","wassup":"wassup","wassup_meta":"wassup","taxonomymeta":"travel-routes","wassup_tmp":"wassup","xyz_ihs_short_code":"insert-html-snippet","pts_tables":"pricing-table-by-supsystic","xyz_ips_short_code":"insert-php-code-snippet","pts_usage_stat":"pricing-table-by-supsystic","huge_it_contact_submission":"forms-contact","leafletmapsmarker_layers":"leaflet-maps-marker","pps_popup_show_categories":"popup-by-supsystic","visitor_maps_st":"visitor-maps","cp_calculated_fields_form_revision":"calculated-fields-form","cp_calculated_fields_form_settings":"calculated-fields-form","huge_it_contact_subscribers":"forms-contact","top_ten_daily":"top-10","visitor_maps_wo":"visitor-maps","visitor_maps_ge":"visitor-maps","top_ten":"top-10","cb_dynamic_settings":"contact-bank","wpbdp_plans":"business-directory-plugin","wpbdp_payments":"business-directory-plugin","wpbdp_payments_items":"business-directory-plugin","cegg_price_alert":"content-egg","wpbdp_submit_state":"business-directory-plugin","wpdatacharts":"wpdatatables","wpbdp_listings":"business-directory-plugin","cegg_price_history":"content-egg","cb_contact_form":"contact-bank","cb_create_control_form":"contact-bank","vod_video":"vod-infomaniak","wpbackitup_job_control":"wp-backitup","wpbdp_logs":"business-directory-plugin","wpdatatables":"wpdatatables","wpbdp_listing_fees":"business-directory-plugin","cb_roles_capability":"contact-bank","cb_email_template_admin":"contact-bank","simple_login_log":"simple-login-log","cb_form_settings_table":"contact-bank","cb_frontend_data_table":"contact-bank","cb_frontend_forms_table":"contact-bank","cb_layout_settings_table":"contact-bank","cb_licensing":"contact-bank","useronline":"usermap","wpdatatables_columns":"wpdatatables","vod_player":"vod-infomaniak","apsl_users_social_profile_details":"accesspress-social-login-lite","wfu_dbxqueue":"wp-file-upload","vod_playlist":"vod-infomaniak","vod_upload":"vod-infomaniak","email_log":"email-log","wfu_log":"wp-file-upload","wpbdp_form_fields":"business-directory-plugin","wfu_userdata":"wp-file-upload","cegg_autoblog":"content-egg","wpbdp_fees":"business-directory-plugin","cfs_statistics":"contact-form-by-supsystic","calendar_config":"calendar-plus","wp_pro_quiz_category":"wp-pro-quiz","wp_pro_quiz_statistic":"wp-pro-quiz","wp_pro_quiz_question":"wp-pro-quiz","wp_pro_quiz_prerequisite":"wp-pro-quiz","easy_pie_emails":"easy-pie-coming-soon","easy_pie_cs_subscribers":"easy-pie-coming-soon","easy_pie_cs_entities":"easy-pie-coming-soon","easy_pie_contacts":"easy-pie-coming-soon","spidercalendar_widget_theme":"spider-event-calendar","wp_pro_quiz_master":"wp-pro-quiz","wp_pro_quiz_lock":"wp-pro-quiz","ariadminer_connections":"ari-adminer","wp_pro_quiz_form":"wp-pro-quiz","spidercalendar_event_category":"spider-event-calendar","wp125_ads":"wp125","crellyslider_elements":"crelly-slider","wowslider":"wowslider","ac_sent_history_lite":"woocommerce-abandoned-cart","crellyslider_sliders":"crelly-slider","crellyslider_slides":"crelly-slider","cscs_db_subscriptions":"igniteup","structuring_markup":"wp-structuring-markup","subscribe_reloaded_subscribers":"subscribe-to-comments-reloaded","ta_link_clicks_meta":"thirstyaffiliates","cwa":"wp-custom-widget-area","ta_link_clicks":"thirstyaffiliates","spidercalendar_theme":"spider-event-calendar","spidercalendar_event":"spider-event-calendar","cfs_contacts":"contact-form-by-supsystic","allowphp_functions":"allow-php-in-posts-and-pages","eig_sso":"eig-sso","cfs_countries":"contact-form-by-supsystic","cfs_forms":"contact-form-by-supsystic","cfs_membership_presets":"contact-form-by-supsystic","cfs_modules":"contact-form-by-supsystic","smuzform_entry":"contact-form-add","smuzform_entry_data":"contact-form-add","cfs_modules_type":"contact-form-by-supsystic","cfs_usage_stat":"contact-form-by-supsystic","unitegallery_items":"unite-gallery-lite","unitegallery_galleries":"unite-gallery-lite","unitegallery_categories":"unite-gallery-lite","uji_subscriptions":"uji-countdown","wp_pro_quiz_statistic_ref":"wp-pro-quiz","uji_counter":"uji-countdown","trp_gettext_en_us":"translatepress-multilingual","trp_gettext_":"translatepress-multilingual","translations_log":"transposh-translation-filter-for-wordpress","wp_pro_quiz_toplist":"wp-pro-quiz","wp_pro_quiz_template":"wp-pro-quiz","translations":"transposh-translation-filter-for-wordpress","calendar_categories":"calendar-plus","contact_bank":"contact-bank","contact_bank_meta":"contact-bank","calendar":"calendar-plus","spidercalendar_calendar":"spider-event-calendar","vod_folder":"vod-infomaniak","wpbackitup_job_items":"wp-backitup","ac_guest_abandoned_cart_history_lite":"woocommerce-abandoned-cart","login_security_solution_fail":"login-security-solution","instapage_pages":"instapage","lrgawidget_global_settings":"lara-google-analytics","itro_plugin_field":"itro-popup","itro_plugin_option":"itro-popup","logger_ginger":"ginger","instapage_debug":"instapage","gallery_galleries":"slideshow-gallery","gallery_galleriesslides":"slideshow-gallery","gallery_pics":"gallery-bank","gallery_settings":"gallery-bank","gallery_slides":"slideshow-gallery","gdbc_attempts":"goodbye-captcha","links_extrainfo":"link-library","instapage_options":"instapage","wpuf_subscribers":"wp-user-frontend","p2pmeta":"rtbiz","mainwp_stream_context":"mainwp-child-reports","rt_rtm_api":"buddypress-media","rt_rtm_activity":"buddypress-media","quotescollection":"quotes-collection","hsa_plugin":"horizontal-scrolling-announcement","pz_linkcard":"pz-linkcard","econtactform7_lookup":"save-contact-form-7","mainwp_stream_meta":"mainwp-child-reports","mainwp_stream":"mainwp-child-reports","gallery_bank_meta":"gallery-bank","wpuf_transaction":"wp-user-frontend","p2p":"rtbiz","wpsm_tables":"table-maker","mailerlite_forms":"official-mailerlite-sign-up-forms","huge_it_reslider_sliders":"slider","huge_it_reslider_slides":"slider","gallery_albums":"gallery-bank","gallery_bank":"gallery-bank","linkcategorymeta":"link-library","gmwd_themes":"wd-google-maps","rt_rtm_media_interaction":"buddypress-media","yasr_multi_values":"yet-another-stars-rating","yop2_poll_questionmeta":"yop-poll","yop2_poll_logs":"yop-poll","yop2_poll_custom_fields":"yop-poll","yop2_poll_bans":"yop-poll","yop2_poll_answers":"yop-poll","gmwd_circles":"wd-google-maps","yop2_poll_answermeta":"yop-poll","yasr_multi_set_fields":"yet-another-stars-rating","yop2_poll_results":"yop-poll","yasr_multi_set":"yet-another-stars-rating","yasr_log":"yet-another-stars-rating","gmedia_term_relationships":"grand-media","gmedia_term_meta":"grand-media","gmedia_term":"grand-media","gmedia_meta":"grand-media","gmedia_log":"grand-media","yop2_poll_questions":"yop-poll","yop2_poll_templates":"yop-poll","gmwd_shortcodes":"wd-google-maps","gmwd_polylines":"wd-google-maps","gmwd_rectangles":"wd-google-maps","yoppoll_votes":"yop-poll","yoppoll_templates":"yop-poll","yoppoll_subelements":"yop-poll","yoppoll_polls":"yop-poll","yoppoll_logs":"yop-poll","yoppoll_elements":"yop-poll","yoppoll_bans":"yop-poll","yop2_poll_votes_custom_fields":"yop-poll","gmwd_polygons":"wd-google-maps","yop2_polls":"yop-poll","yop2_pollmeta":"yop-poll","gmwd_options":"wd-google-maps","gmwd_markers":"wd-google-maps","gmwd_markercategories":"wd-google-maps","gmwd_mapstyles":"wd-google-maps","gmwd_maps":"wd-google-maps","rt_rtm_media":"buddypress-media","gmedia":"grand-media","_posts_network_details":"blog2social","_posts":"blog2social","wpsc_purchase_meta":"wp-e-commerce","grp_google_review":"wp-social-seo","wpsc_coupon_codes":"wp-e-commerce","wpsc_also_bought":"wp-e-commerce-cross-sales","flag_album":"flash-album-gallery","grp_google_place":"wp-social-seo","groups_user_group":"groups","flag_comments":"flash-album-gallery","flag_gallery":"flash-album-gallery","groups_user_capability":"groups","groups_group_capability":"groups","flag_pictures":"flash-album-gallery","fo_elements":"font-organizer","wpsc_submited_form_data":"wp-e-commerce","wpsc_product_rating":"wp-e-commerce","wpsc_meta":"wp-e-commerce","wpbackitup_job_tasks":"wp-backitup","fo_usable_fonts":"font-organizer","say_what_strings":"say-what","groups_group":"groups","wpsc_download_status":"wp-e-commerce","groups_capability":"groups","wpsc_cart_contents":"wp-e-commerce","wpsc_cart_item_meta":"wp-e-commerce","wpsc_checkout_forms":"wp-e-commerce","wpsc_currency_list":"wp-e-commerce","wpsc_claimed_stock":"wp-e-commerce","wpsc_region_tax":"wp-e-commerce","wpsc_purchase_logs":"wp-e-commerce","_post_sched_settings":"blog2social","_user_network_settings":"blog2social","zerospam_blocked_ips":"zero-spam","zerospam_log":"zero-spam","ac_email_templates_lite":"woocommerce-abandoned-cart","ac_abandoned_cart_history_lite":"woocommerce-abandoned-cart","mlw_qm_audit_trail":"quiz-master-next","mlw_questions":"quiz-master-next","mech_statistik":"mechanic-visitor-counter","mo_openid_linked_user":"miniorange-login-openid","mlw_quizzes":"quiz-master-next","mediafromftp_log":"media-from-ftp","mp_timetable_data":"mp-timetable","mlw_results":"quiz-master-next","rt_rtm_media_meta":"buddypress-media","wpsc_visitors":"wp-e-commerce","m_tables":"table-maker","_user_contact":"blog2social","wpsc_visitor_meta":"wp-e-commerce","_user":"blog2social","_posts_sched_details":"blog2social","h5p_results":"h5p","h5p_libraries_languages":"h5p","participants_database":"participants-database","pantheon_sessions":"stripe","page_visit_history":"page-visit-counter","vslider":"vslider","h5p_libraries_libraries":"h5p","page_visit":"page-visit-counter","upcp_item_images":"ultimate-product-catalogue","cf7_vdata_entry":"advanced-cf7-db","upcp_videos":"ultimate-product-catalogue","h5p_libraries":"h5p","upcp_tags":"ultimate-product-catalogue","upcp_items":"ultimate-product-catalogue","upcp_tagged_items":"ultimate-product-catalogue","h5p_tags":"h5p","upcp_tag_groups":"ultimate-product-catalogue","h5p_libraries_hub_cache":"h5p","upcp_subcategories":"ultimate-product-catalogue","h5p_libraries_cachedassets":"h5p","usces_order_meta":"usc-e-shop","power_stats_browsers":"wp-power-stats","cf7_vdata":"advanced-cf7-db","huge_it_catalog_general_params":"product-catalog","huge_it_videos":"video-player","huge_it_video_players":"video-player","huge_it_video_params":"video-player","vimeography_gallery_meta":"vimeography","vimeography_gallery":"vimeography","vcp_log":"vieraslaskuri","huge_it_catalogs":"product-catalog","huge_it_catalog_reviews":"product-catalog","huge_it_catalog_rating":"product-catalog","huge_it_catalog_asc_seller":"product-catalog","pvc_daily":"page-views-count","huge_it_catalog_albums":"product-catalog","huge_it_catalog_album_catalog_contact":"product-catalog","usces_access":"usc-e-shop","usces_log":"usc-e-shop","usces_member":"usc-e-shop","user2role2object_rs":"role-scoper","user2group_rs":"role-scoper","usces_ordercart_meta":"usc-e-shop","usces_ordercart":"usc-e-shop","usces_member_meta":"usc-e-shop","pvc_total":"page-views-count","psp":"premium-seo-pack","cf7_data_entry":"cf7-database","power_stats_os":"wp-power-stats","cf7_data":"cf7-database","participants_database_fields":"participants-database","h5p_tmpfiles":"h5p","participants_database_groups":"participants-database","po_plugins":"plugin-organizer","rednao_smart_forms_table_name":"smart-forms","rednao_smart_forms_entry_detail":"smart-forms","usces_order":"usc-e-shop","rednao_smart_forms_entry":"smart-forms","hfcm_scripts":"header-footer-code-manager","power_stats_pageviews":"wp-power-stats","ihrss_plugin":"image-horizontal-reel-scroll-slideshow","power_stats_posts":"wp-power-stats","power_stats_searches":"wp-power-stats","power_stats_visits":"wp-power-stats","inbound_tracked_links":"leads","inbound_page_views":"leads","inbound_events":"leads","private_blog_access_logs":"password-protect-wordpress","huge_it_catalog_products":"product-catalog","lmtttmpts_blacklist":"limit-attempts","mainwp_wp_backup":"mainwp","awpcp_tasks":"another-wordpress-classifieds-plugin","media_file_manager_log":"media-file-manager","mdf_stat_tmp":"wp-meta-data-filter-and-taxonomy-filter","mdf_stat_buffer":"wp-meta-data-filter-and-taxonomy-filter","mdf_query_cache":"wp-meta-data-filter-and-taxonomy-filter","mainwp_wp_sync":"mainwp","mainwp_wp_settings_backup":"mainwp","mainwp_wp_options":"mainwp","mainwp_wp_group":"mainwp","mainwp_wp_backup_progress":"mainwp","bannerize":"wp-bannerize","mainwp_wp":"mainwp","awpcp_media":"another-wordpress-classifieds-plugin","mainwp_users":"mainwp","mainwp_tips":"mainwp","mainwp_request_log":"mainwp","mainwp_group":"mainwp","mainwp_client_report_token":"mainwp","mainwp_client_report_site_token":"mainwp","mainwp_client_report_format":"mainwp","mainwp_client_report_client":"mainwp","mainwp_client_report":"mainwp","maintenance_page":"maintenance-page","wonderplugin_slider":"wonderplugin-slider-lite","awpcp_payments":"another-wordpress-classifieds-plugin","awpcp_credit_plans":"another-wordpress-classifieds-plugin","wise_chat_messages":"wise-chat","wpam_tracking_tokens":"affiliates-manager","mlab_popup":"homepage-pop-up","mltlngg_translate":"multilanguage","mo2f_user_details":"miniorange-2-factor-authentication","microblogposter_user_accounts":"microblog-poster","microblogposter_old_items":"microblog-poster","microblogposter_logs":"microblog-poster","microblogposter_items_meta":"microblog-poster","microblogposter_accounts":"microblog-poster","audit_trail":"audit-trail","wpam_transactions":"affiliates-manager","wpam_tracking_tokens_purchase_logs":"affiliates-manager","wpam_paypal_logs":"affiliates-manager","awpcp_categories":"another-wordpress-classifieds-plugin","wpam_messages":"affiliates-manager","wpam_impressions":"affiliates-manager","wpam_events":"affiliates-manager","wpam_creatives":"affiliates-manager","wpam_affiliates_fields":"affiliates-manager","wpam_affiliates":"affiliates-manager","wpam_actions":"affiliates-manager","avhec_category_groups":"extended-categories-widget","awpcp_ad_regions":"another-wordpress-classifieds-plugin","awpcp_adfees":"another-wordpress-classifieds-plugin","awpcp_admeta":"another-wordpress-classifieds-plugin","awpcp_ads":"another-wordpress-classifieds-plugin","wise_chat_users":"wise-chat","wise_chat_kicks":"wise-chat","lgp_crons":"content-links","login_log":"login-log","lmtttmpts_whitelist":"limit-attempts","lmtttmpts_failed_attempts":"limit-attempts","upcp_custom_fields":"ultimate-product-catalogue","lmtttmpts_all_failed_attempts":"limit-attempts","opanda_leads":"opt-in-panda","opanda_leads_fields":"opt-in-panda","opanda_stats_v2":"opt-in-panda","lgp_posts":"content-links","lgp_log":"content-links","lgp_linking":"content-links","wcmp_visitors_stats":"dc-woocommerce-multi-vendor","lps_lockdowns":"login-page-styler","wcmp_vendor_orders":"dc-woocommerce-multi-vendor","wcmp_products_map":"dc-woocommerce-multi-vendor","wcmp_cust_questions":"dc-woocommerce-multi-vendor","wcmp_cust_answers":"dc-woocommerce-multi-vendor","legal_pages":"wplegalpages","lead_form_options":"lead-form-builder","lead_form_extension":"lead-form-builder","lead_form_data":"lead-form-builder","lead_form":"lead-form-builder","wbz404_redirects":"404-redirected","wbz404_logs":"404-redirected","lp_popups":"wplegalpages","lps_login_fails":"login-page-styler","wise_chat_channels":"wise-chat","m_membership_relationships":"membership","wise_chat_channel_users":"wise-chat","wise_chat_bans":"wise-chat","m_urlgroups":"membership","m_subscriptions_levels":"membership","m_subscriptions":"membership","m_subscriptionmeta":"membership","wise_chat_actions":"wise-chat","m_subscription_transaction":"membership","m_pings":"membership","m_ping_history":"membership","m_membership_rules":"membership","m_membership_news":"membership","nm_personalized":"woocommerce-product-addon","m_membership_levels":"membership","m_member_payments":"membership","m_levelmeta":"membership","m_coupons":"membership","m_communications":"membership","nextend_smartslider_layouts":"smart-slider-2","nextend_smartslider_sliders":"smart-slider-2","nextend_smartslider_slides":"smart-slider-2","nextend_smartslider_storage":"smart-slider-2","lsp_sliders":"logo-slider","lsp_images":"best-local-seo-tools","ninja_table_items":"ninja-tables","upcp_fields_meta":"ultimate-product-catalogue","rich_web_slider_effect10_loader":"slider-images","upcp_categories":"ultimate-product-catalogue","ea_connections":"easy-appointments","dopbsp_locations":"booking-system","dopbsp_models":"booking-system","dopbsp_reservations":"booking-system","dopbsp_rules":"booking-system","dopbsp_searches":"booking-system","dopbsp_settings":"booking-system","dopbsp_settings_calendar":"booking-system","dopbsp_settings_notifications":"booking-system","dopbsp_settings_payment":"booking-system","dopbsp_settings_search":"booking-system","dopbsp_translation_en":"booking-system","ea_appointments":"easy-appointments","rs_exclude":"slider-by-supsystic","dopbsp_forms_select_options":"booking-system","rs_folders":"slider-by-supsystic","rs_maps":"slider-by-supsystic","rs_membership_presets":"slider-by-supsystic","rs_photos":"slider-by-supsystic","rs_photos_pos":"slider-by-supsystic","rs_resources":"slider-by-supsystic","ea_error_logs":"easy-appointments","ea_fields":"easy-appointments","ea_locations":"easy-appointments","ea_meta_fields":"easy-appointments","ea_options":"easy-appointments","ea_services":"easy-appointments","ea_staff":"easy-appointments","dopbsp_languages":"booking-system","dopbsp_forms_fields":"booking-system","easy_gallery":"wp-easy-gallery","dopbsp_availability_price":"booking-system","store_locator":"store-locator-le","sticky":"wp-sticky","stb_styles":"wp-special-textboxes","geodir_custom_fields":"geodirectory","geodir_countrie